diff options
| author | Giuseppe Cavallaro <peppe.cavallaro@st.com> | 2008-11-28 19:24:56 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-11-28 19:24:56 -0500 |
| commit | 0f0ca340e57bd7446855fefd07a64249acf81223 (patch) | |
| tree | 9a3af0f86f8bcce9eb86a38bf4dd5f4a2c5da2d1 | |
| parent | 914804b95caa61c633431262044034ab05c78ba4 (diff) | |
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 <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/phy/mdio_bus.c | 14 | ||||
| -rw-r--r-- | drivers/net/phy/phy_device.c | 31 | ||||
| -rw-r--r-- | include/linux/phy.h | 2 |
3 files changed, 42 insertions, 5 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 868812ff6de8..8755d8cd4166 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) | |||
| 284 | { | 284 | { |
| 285 | int ret = 0; | 285 | int ret = 0; |
| 286 | struct device_driver *drv = dev->driver; | 286 | struct device_driver *drv = dev->driver; |
| 287 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
| 288 | struct phy_device *phydev = to_phy_device(dev); | ||
| 287 | 289 | ||
| 288 | if (drv && drv->suspend) | 290 | if ((!device_may_wakeup(phydev->dev.parent)) && |
| 289 | ret = drv->suspend(dev, state); | 291 | (phydrv && phydrv->suspend)) |
| 292 | ret = phydrv->suspend(phydev); | ||
| 290 | 293 | ||
| 291 | return ret; | 294 | return ret; |
| 292 | } | 295 | } |
| @@ -295,9 +298,12 @@ static int mdio_bus_resume(struct device * dev) | |||
| 295 | { | 298 | { |
| 296 | int ret = 0; | 299 | int ret = 0; |
| 297 | struct device_driver *drv = dev->driver; | 300 | struct device_driver *drv = dev->driver; |
| 301 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
| 302 | struct phy_device *phydev = to_phy_device(dev); | ||
| 298 | 303 | ||
| 299 | if (drv && drv->resume) | 304 | if ((!device_may_wakeup(phydev->dev.parent)) && |
| 300 | ret = drv->resume(dev); | 305 | (phydrv && phydrv->resume)) |
| 306 | ret = phydrv->resume(phydev); | ||
| 301 | 307 | ||
| 302 | return ret; | 308 | return ret; |
| 303 | } | 309 | } |
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 29546a206045..4cc75a290c06 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) | |||
| 779 | 779 | ||
| 780 | return 0; | 780 | return 0; |
| 781 | } | 781 | } |
| 782 | int genphy_suspend(struct phy_device *phydev) | ||
| 783 | { | ||
| 784 | int value; | ||
| 785 | |||
| 786 | mutex_lock(&phydev->lock); | ||
| 787 | |||
| 788 | value = phy_read(phydev, MII_BMCR); | ||
| 789 | phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN)); | ||
| 790 | |||
| 791 | mutex_unlock(&phydev->lock); | ||
| 792 | |||
| 793 | return 0; | ||
| 794 | } | ||
| 795 | EXPORT_SYMBOL(genphy_suspend); | ||
| 782 | 796 | ||
| 797 | int genphy_resume(struct phy_device *phydev) | ||
| 798 | { | ||
| 799 | int value; | ||
| 800 | |||
| 801 | mutex_lock(&phydev->lock); | ||
| 802 | |||
| 803 | value = phy_read(phydev, MII_BMCR); | ||
| 804 | phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN)); | ||
| 805 | |||
| 806 | mutex_unlock(&phydev->lock); | ||
| 807 | |||
| 808 | return 0; | ||
| 809 | } | ||
| 810 | EXPORT_SYMBOL(genphy_resume); | ||
| 783 | 811 | ||
| 784 | /** | 812 | /** |
| 785 | * phy_probe - probe and init a PHY device | 813 | * phy_probe - probe and init a PHY device |
| @@ -855,7 +883,6 @@ int phy_driver_register(struct phy_driver *new_driver) | |||
| 855 | { | 883 | { |
| 856 | int retval; | 884 | int retval; |
| 857 | 885 | ||
| 858 | memset(&new_driver->driver, 0, sizeof(new_driver->driver)); | ||
| 859 | new_driver->driver.name = new_driver->name; | 886 | new_driver->driver.name = new_driver->name; |
| 860 | new_driver->driver.bus = &mdio_bus_type; | 887 | new_driver->driver.bus = &mdio_bus_type; |
| 861 | new_driver->driver.probe = phy_probe; | 888 | new_driver->driver.probe = phy_probe; |
| @@ -890,6 +917,8 @@ static struct phy_driver genphy_driver = { | |||
| 890 | .features = 0, | 917 | .features = 0, |
| 891 | .config_aneg = genphy_config_aneg, | 918 | .config_aneg = genphy_config_aneg, |
| 892 | .read_status = genphy_read_status, | 919 | .read_status = genphy_read_status, |
| 920 | .suspend = genphy_suspend, | ||
| 921 | .resume = genphy_resume, | ||
| 893 | .driver = {.owner= THIS_MODULE, }, | 922 | .driver = {.owner= THIS_MODULE, }, |
| 894 | }; | 923 | }; |
| 895 | 924 | ||
diff --git a/include/linux/phy.h b/include/linux/phy.h index 77c4ed60b982..d7e54d98869f 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h | |||
| @@ -467,6 +467,8 @@ int genphy_restart_aneg(struct phy_device *phydev); | |||
| 467 | int genphy_config_aneg(struct phy_device *phydev); | 467 | int genphy_config_aneg(struct phy_device *phydev); |
| 468 | int genphy_update_link(struct phy_device *phydev); | 468 | int genphy_update_link(struct phy_device *phydev); |
| 469 | int genphy_read_status(struct phy_device *phydev); | 469 | int genphy_read_status(struct phy_device *phydev); |
| 470 | int genphy_suspend(struct phy_device *phydev); | ||
| 471 | int genphy_resume(struct phy_device *phydev); | ||
| 470 | void phy_driver_unregister(struct phy_driver *drv); | 472 | void phy_driver_unregister(struct phy_driver *drv); |
| 471 | int phy_driver_register(struct phy_driver *new_driver); | 473 | int phy_driver_register(struct phy_driver *new_driver); |
| 472 | void phy_prepare_link(struct phy_device *phydev, | 474 | void phy_prepare_link(struct phy_device *phydev, |
