diff --git a/Documentation/devicetree/bindings/net/smsc-lan87xx.txt b/Documentation/devicetree/bindings/net/smsc-lan87xx.txt index 8b7c719b0bb9..a8d0dc9a8c0e 100644 --- a/Documentation/devicetree/bindings/net/smsc-lan87xx.txt +++ b/Documentation/devicetree/bindings/net/smsc-lan87xx.txt @@ -5,6 +5,10 @@ through an Ethernet OF device node. Optional properties: +- clocks: + The clock used as phy reference clock and is connected to phy + pin XTAL1/CLKIN. + - smsc,disable-energy-detect: If set, do not enable energy detect mode for the SMSC phy. default: enable energy detect mode diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 638e8c3d1f4a..ec97669be5c2 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -12,6 +12,7 @@ * */ +#include #include #include #include @@ -44,14 +45,22 @@ static struct smsc_hw_stat smsc_hw_stats[] = { struct smsc_phy_priv { bool energy_enable; + struct clk *refclk; }; static int smsc_phy_config_intr(struct phy_device *phydev) { - int rc = phy_write (phydev, MII_LAN83C185_IM, - ((PHY_INTERRUPT_ENABLED == phydev->interrupts) - ? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS - : 0)); + struct smsc_phy_priv *priv = phydev->priv; + u16 intmask = 0; + int rc; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + intmask = MII_LAN83C185_ISF_INT4 | MII_LAN83C185_ISF_INT6; + if (priv->energy_enable) + intmask |= MII_LAN83C185_ISF_INT7; + } + + rc = phy_write(phydev, MII_LAN83C185_IM, intmask); return rc < 0 ? rc : 0; } @@ -66,19 +75,21 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev) static int smsc_phy_config_init(struct phy_device *phydev) { struct smsc_phy_priv *priv = phydev->priv; + int rc; - int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); + if (!priv->energy_enable) + return 0; + + rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); if (rc < 0) return rc; - if (priv->energy_enable) { - /* Enable energy detect mode for this SMSC Transceivers */ - rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, - rc | MII_LAN83C185_EDPWRDOWN); - if (rc < 0) - return rc; - } + /* Enable energy detect mode for this SMSC Transceivers */ + rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, + rc | MII_LAN83C185_EDPWRDOWN); + if (rc < 0) + return rc; return smsc_phy_ack_interrupt(phydev); } @@ -244,11 +255,20 @@ static void smsc_get_stats(struct phy_device *phydev, data[i] = smsc_get_stat(phydev, i); } +static void smsc_phy_remove(struct phy_device *phydev) +{ + struct smsc_phy_priv *priv = phydev->priv; + + clk_disable_unprepare(priv->refclk); + clk_put(priv->refclk); +} + static int smsc_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; struct device_node *of_node = dev->of_node; struct smsc_phy_priv *priv; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -261,6 +281,19 @@ static int smsc_phy_probe(struct phy_device *phydev) phydev->priv = priv; + /* Make clk optional to keep DTB backward compatibility. */ + priv->refclk = clk_get_optional(dev, NULL); + if (IS_ERR(priv->refclk)) + dev_err_probe(dev, PTR_ERR(priv->refclk), "Failed to request clock\n"); + + ret = clk_prepare_enable(priv->refclk); + if (ret) + return ret; + + ret = clk_set_rate(priv->refclk, 50 * 1000 * 1000); + if (ret) + return ret; + return 0; } @@ -364,9 +397,9 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8710/LAN8720", /* PHY_BASIC_FEATURES */ - .flags = PHY_RST_AFTER_CLK_EN, .probe = smsc_phy_probe, + .remove = smsc_phy_remove, /* basic functions */ .read_status = lan87xx_read_status,