PM: Introduce generic prepare and complete callbacks for subsystems
Rafael J. Wysocki [Tue, 17 May 2011 21:26:21 +0000 (23:26 +0200)]
Introduce generic .prepare() and .complete() power management
callbacks, currently missing, that can be used by subsystems and
power domains and export them.  Provide NULL definitions of all
the generic system sleep callbacks for CONFIG_PM_SLEEP unset.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

drivers/base/power/generic_ops.c
include/linux/pm.h

index 42f97f9..cb3bb36 100644 (file)
@@ -74,6 +74,23 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
 
 #ifdef CONFIG_PM_SLEEP
 /**
+ * pm_generic_prepare - Generic routine preparing a device for power transition.
+ * @dev: Device to prepare.
+ *
+ * Prepare a device for a system-wide power transition.
+ */
+int pm_generic_prepare(struct device *dev)
+{
+       struct device_driver *drv = dev->driver;
+       int ret = 0;
+
+       if (drv && drv->pm && drv->pm->prepare)
+               ret = drv->pm->prepare(dev);
+
+       return ret;
+}
+
+/**
  * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback.
  * @dev: Device to handle.
  * @event: PM transition of the system under way.
@@ -213,16 +230,38 @@ int pm_generic_restore(struct device *dev)
        return __pm_generic_resume(dev, PM_EVENT_RESTORE);
 }
 EXPORT_SYMBOL_GPL(pm_generic_restore);
+
+/**
+ * pm_generic_complete - Generic routine competing a device power transition.
+ * @dev: Device to handle.
+ *
+ * Complete a device power transition during a system-wide power transition.
+ */
+void pm_generic_complete(struct device *dev)
+{
+       struct device_driver *drv = dev->driver;
+
+       if (drv && drv->pm && drv->pm->complete)
+               drv->pm->complete(dev);
+
+       /*
+        * Let runtime PM try to suspend devices that haven't been in use before
+        * going into the system-wide sleep state we're resuming from.
+        */
+       pm_runtime_idle(dev);
+}
 #endif /* CONFIG_PM_SLEEP */
 
 struct dev_pm_ops generic_subsys_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
+       .prepare = pm_generic_prepare,
        .suspend = pm_generic_suspend,
        .resume = pm_generic_resume,
        .freeze = pm_generic_freeze,
        .thaw = pm_generic_thaw,
        .poweroff = pm_generic_poweroff,
        .restore = pm_generic_restore,
+       .complete = pm_generic_complete,
 #endif
 #ifdef CONFIG_PM_RUNTIME
        .runtime_suspend = pm_generic_runtime_suspend,
index dce7c71..3160648 100644 (file)
@@ -550,6 +550,16 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
        } while (0)
 
 extern int device_pm_wait_for_dev(struct device *sub, struct device *dev);
+
+extern int pm_generic_prepare(struct device *dev);
+extern int pm_generic_suspend(struct device *dev);
+extern int pm_generic_resume(struct device *dev);
+extern int pm_generic_freeze(struct device *dev);
+extern int pm_generic_thaw(struct device *dev);
+extern int pm_generic_restore(struct device *dev);
+extern int pm_generic_poweroff(struct device *dev);
+extern void pm_generic_complete(struct device *dev);
+
 #else /* !CONFIG_PM_SLEEP */
 
 #define device_pm_lock() do {} while (0)
@@ -566,6 +576,15 @@ static inline int device_pm_wait_for_dev(struct device *a, struct device *b)
 {
        return 0;
 }
+
+#define pm_generic_prepare     NULL
+#define pm_generic_suspend     NULL
+#define pm_generic_resume      NULL
+#define pm_generic_freeze      NULL
+#define pm_generic_thaw                NULL
+#define pm_generic_restore     NULL
+#define pm_generic_poweroff    NULL
+#define pm_generic_complete    NULL
 #endif /* !CONFIG_PM_SLEEP */
 
 /* How to reorder dpm_list after device_move() */
@@ -576,11 +595,4 @@ enum dpm_order {
        DPM_ORDER_DEV_LAST,
 };
 
-extern int pm_generic_suspend(struct device *dev);
-extern int pm_generic_resume(struct device *dev);
-extern int pm_generic_freeze(struct device *dev);
-extern int pm_generic_thaw(struct device *dev);
-extern int pm_generic_restore(struct device *dev);
-extern int pm_generic_poweroff(struct device *dev);
-
 #endif /* _LINUX_PM_H */