spi / PM: Support dev_pm_ops
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Sat, 25 Dec 2010 14:32:27 +0000 (15:32 +0100)
committerRafael J. Wysocki <rjw@sisk.pl>
Sat, 25 Dec 2010 14:32:27 +0000 (15:32 +0100)
Allow SPI drivers to use runtime PM and other dev_pm_ops features by
implementing dev_pm_ops for the bus. The existing bus specific suspend
and resume functions will be called if a driver does not provide dev_pm_ops
allowing for transition to the new model.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
drivers/spi/spi.c

index b02d0cb..34bb17f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/spi/spi.h>
 #include <linux/of_spi.h>
+#include <linux/pm_runtime.h>
 
 static void spidev_release(struct device *dev)
 {
@@ -100,9 +101,8 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-#ifdef CONFIG_PM
-
-static int spi_suspend(struct device *dev, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int spi_legacy_suspend(struct device *dev, pm_message_t message)
 {
        int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
@@ -117,7 +117,7 @@ static int spi_suspend(struct device *dev, pm_message_t message)
        return value;
 }
 
-static int spi_resume(struct device *dev)
+static int spi_legacy_resume(struct device *dev)
 {
        int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
@@ -132,18 +132,94 @@ static int spi_resume(struct device *dev)
        return value;
 }
 
+static int spi_pm_suspend(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_suspend(dev);
+       else
+               return spi_legacy_suspend(dev, PMSG_SUSPEND);
+}
+
+static int spi_pm_resume(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_resume(dev);
+       else
+               return spi_legacy_resume(dev);
+}
+
+static int spi_pm_freeze(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_freeze(dev);
+       else
+               return spi_legacy_suspend(dev, PMSG_FREEZE);
+}
+
+static int spi_pm_thaw(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_thaw(dev);
+       else
+               return spi_legacy_resume(dev);
+}
+
+static int spi_pm_poweroff(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_poweroff(dev);
+       else
+               return spi_legacy_suspend(dev, PMSG_HIBERNATE);
+}
+
+static int spi_pm_restore(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_restore(dev);
+       else
+               return spi_legacy_resume(dev);
+}
 #else
-#define spi_suspend    NULL
-#define spi_resume     NULL
+#define spi_pm_suspend NULL
+#define spi_pm_resume  NULL
+#define spi_pm_freeze  NULL
+#define spi_pm_thaw    NULL
+#define spi_pm_poweroff        NULL
+#define spi_pm_restore NULL
 #endif
 
+static const struct dev_pm_ops spi_pm = {
+       .suspend = spi_pm_suspend,
+       .resume = spi_pm_resume,
+       .freeze = spi_pm_freeze,
+       .thaw = spi_pm_thaw,
+       .poweroff = spi_pm_poweroff,
+       .restore = spi_pm_restore,
+       SET_RUNTIME_PM_OPS(
+               pm_generic_runtime_suspend,
+               pm_generic_runtime_resume,
+               pm_generic_runtime_idle
+       )
+};
+
 struct bus_type spi_bus_type = {
        .name           = "spi",
        .dev_attrs      = spi_dev_attrs,
        .match          = spi_match_device,
        .uevent         = spi_uevent,
-       .suspend        = spi_suspend,
-       .resume         = spi_resume,
+       .pm             = &spi_pm,
 };
 EXPORT_SYMBOL_GPL(spi_bus_type);