summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2009-05-05 21:22:53 +0200
committerDavid S. Miller <davem@davemloft.net>2009-05-05 21:22:53 +0200
commitb6907b0c705b6db221f937b4d343e2a6b280c8c5 (patch)
tree1cc95afd264bc7ca29fb7ea4f1e32a35aff64fe8
parentnet: remove driver_data direct access of struct device from more drivers (diff)
downloadlinux-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.c46
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 */