From 3867e7a16b495ef81734f7982af44a4848bb804d Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Tue, 3 Jul 2012 16:52:23 -0700 Subject: micrel: powerdown if phy halted and link int disabled --- drivers/net/phy/micrel.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 80747d2d1118..6eafb5cf4902 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -16,6 +16,7 @@ * ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy */ +#include #include #include #include @@ -48,16 +49,34 @@ static int kszphy_ack_interrupt(struct phy_device *phydev) int rc; rc = phy_read(phydev, MII_KSZPHY_INTCS); - return (rc < 0) ? rc : 0; } static int kszphy_set_interrupt(struct phy_device *phydev) { - int temp; - temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ? - KSZPHY_INTCS_ALL : 0; - return phy_write(phydev, MII_KSZPHY_INTCS, temp); + int bmcr, new_bmcr; + bmcr = phy_read(phydev, MII_BMCR); + if (PHY_INTERRUPT_ENABLED == phydev->interrupts) { + new_bmcr = bmcr & ~BMCR_PDOWN; + if (bmcr != new_bmcr) { + unsigned intcs, temp; + phy_write(phydev, MII_BMCR, new_bmcr); + udelay(100); /* power up needs delay after */ + /* force master mode */ + phy_write(phydev, 0x9, 0x1f00); + } + return phy_write(phydev, MII_KSZPHY_INTCS, KSZPHY_INTCS_ALL); + } else { + phy_write(phydev, MII_KSZPHY_INTCS, 0); + new_bmcr = bmcr | BMCR_PDOWN; + if ((PHY_HALTED == phydev->state) && (bmcr != new_bmcr)) { + phy_write(phydev, MII_BMCR, bmcr | BMCR_ANRESTART); + /* let phy note link is down before poweroff */ + udelay(10); + phy_write(phydev, MII_BMCR, new_bmcr); + } + return 0; + } } static int kszphy_config_intr(struct phy_device *phydev) @@ -66,8 +85,10 @@ static int kszphy_config_intr(struct phy_device *phydev) /* set the interrupt pin active low */ temp = phy_read(phydev, MII_KSZPHY_CTRL); - temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; - phy_write(phydev, MII_KSZPHY_CTRL, temp); + if (temp & KSZPHY_CTRL_INT_ACTIVE_HIGH) { + temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; + phy_write(phydev, MII_KSZPHY_CTRL, temp); + } rc = kszphy_set_interrupt(phydev); return rc < 0 ? rc : 0; } @@ -76,10 +97,12 @@ static int ksz9021_config_intr(struct phy_device *phydev) { int temp, rc; - /* set the interrupt pin active low */ temp = phy_read(phydev, MII_KSZPHY_CTRL); - temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH; - phy_write(phydev, MII_KSZPHY_CTRL, temp); + if (temp & KSZ9021_CTRL_INT_ACTIVE_HIGH) { + /* set the interrupt pin active low */ + temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH; + phy_write(phydev, MII_KSZPHY_CTRL, temp); + } rc = kszphy_set_interrupt(phydev); return rc < 0 ? rc : 0; } -- cgit v1.2.3