From: Giuseppe Cavallaro Date: Sat, 29 Nov 2008 00:24:56 +0000 (-0800) Subject: phy: power management support X-Git-Tag: v2.6.29-rc1~581^2~360 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0f0ca340e57bd7446855fefd07a64249acf81223;p=profile%2Fivi%2Fkernel-x86-ivi.git phy: power management support This patch adds the power management support into the physical abstraction layer. Suspend and resume functions respectively turns on/off the bit 11 into the PHY Basic mode control register. Generic PHY device starts supporting PM. In order to support the wake-on LAN and avoid to put in power down the PHY device, the MDIO is aware of what the Ethernet device wants to do. Voluntary, no CONFIG_PM defines were added into the sources. Also generic suspend/resume functions are exported to allow other drivers use them (such as genphy_config_aneg etc.). Within the phy_driver_register function, we need to remove the memset. It overrides the device driver owner and it is not good. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 868812f..8755d8c 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -284,9 +284,12 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state) { int ret = 0; struct device_driver *drv = dev->driver; + struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_device *phydev = to_phy_device(dev); - if (drv && drv->suspend) - ret = drv->suspend(dev, state); + if ((!device_may_wakeup(phydev->dev.parent)) && + (phydrv && phydrv->suspend)) + ret = phydrv->suspend(phydev); return ret; } @@ -295,9 +298,12 @@ static int mdio_bus_resume(struct device * dev) { int ret = 0; struct device_driver *drv = dev->driver; + struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_device *phydev = to_phy_device(dev); - if (drv && drv->resume) - ret = drv->resume(dev); + if ((!device_may_wakeup(phydev->dev.parent)) && + (phydrv && phydrv->resume)) + ret = phydrv->resume(phydev); return ret; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 29546a2..4cc75a2 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -779,7 +779,35 @@ static int genphy_config_init(struct phy_device *phydev) return 0; } +int genphy_suspend(struct phy_device *phydev) +{ + int value; + + mutex_lock(&phydev->lock); + + value = phy_read(phydev, MII_BMCR); + phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN)); + + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(genphy_suspend); +int genphy_resume(struct phy_device *phydev) +{ + int value; + + mutex_lock(&phydev->lock); + + value = phy_read(phydev, MII_BMCR); + phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN)); + + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(genphy_resume); /** * phy_probe - probe and init a PHY device @@ -855,7 +883,6 @@ int phy_driver_register(struct phy_driver *new_driver) { int retval; - memset(&new_driver->driver, 0, sizeof(new_driver->driver)); new_driver->driver.name = new_driver->name; new_driver->driver.bus = &mdio_bus_type; new_driver->driver.probe = phy_probe; @@ -890,6 +917,8 @@ static struct phy_driver genphy_driver = { .features = 0, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = {.owner= THIS_MODULE, }, }; diff --git a/include/linux/phy.h b/include/linux/phy.h index 77c4ed6..d7e54d9 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -467,6 +467,8 @@ int genphy_restart_aneg(struct phy_device *phydev); int genphy_config_aneg(struct phy_device *phydev); int genphy_update_link(struct phy_device *phydev); int genphy_read_status(struct phy_device *phydev); +int genphy_suspend(struct phy_device *phydev); +int genphy_resume(struct phy_device *phydev); void phy_driver_unregister(struct phy_driver *drv); int phy_driver_register(struct phy_driver *new_driver); void phy_prepare_link(struct phy_device *phydev,