diff options
author | Daniel Mack <daniel@caiaq.de> | 2009-05-05 21:22:53 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-05 21:22:53 +0200 |
commit | b6907b0c705b6db221f937b4d343e2a6b280c8c5 (patch) | |
tree | 1cc95afd264bc7ca29fb7ea4f1e32a35aff64fe8 | |
parent | net: remove driver_data direct access of struct device from more drivers (diff) | |
download | linux-b6907b0c705b6db221f937b4d343e2a6b280c8c5.tar.xz linux-b6907b0c705b6db221f937b4d343e2a6b280c8c5.zip |
net: smsc911x: add power management functions
This adds a power management implementation for smsc911x.c which assumes
the chips remains powered during suspend. The device is put in its D1
power saving mode.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Acked-by: Steve Glendinning <steve.glendinning@smsc.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/smsc911x.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 5113b26fc2d9..9a8528c5bb5e 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -2109,12 +2109,58 @@ out_0: return retval; } +#ifdef CONFIG_PM +/* This implementation assumes the devices remains powered on its VDDVARIO + * pins during suspend. */ + +static int smsc911x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct smsc911x_data *pdata = netdev_priv(dev); + + /* enable wake on LAN, energy detection and the external PME + * signal. */ + smsc911x_reg_write(pdata, PMT_CTRL, + PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ | + PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_); + + return 0; +} + +static int smsc911x_resume(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int to = 100; + + /* Note 3.11 from the datasheet: + * "When the LAN9220 is in a power saving state, a write of any + * data to the BYTE_TEST register will wake-up the device." + */ + smsc911x_reg_write(pdata, BYTE_TEST, 0); + + /* poll the READY bit in PMT_CTRL. Any other access to the device is + * forbidden while this bit isn't set. Try for 100ms and return -EIO + * if it failed. */ + while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) + udelay(1000); + + return (to == 0) ? -EIO : 0; +} + +#else +#define smsc911x_suspend NULL +#define smsc911x_resume NULL +#endif + static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, .remove = smsc911x_drv_remove, .driver = { .name = SMSC_CHIPNAME, }, + .suspend = smsc911x_suspend, + .resume = smsc911x_resume, }; /* Entry point for loading the module */ |