PM / Domains: Use subsystem runtime suspend/resume callbacks by default
Rafael J. Wysocki [Fri, 15 Jun 2012 22:02:22 +0000 (00:02 +0200)]
Currently, the default "save state" and "restore state" routines
for generic PM domains, pm_genpd_default_save_state() and
pm_genpd_default_restore_state(), respectively, only use runtime PM
callbacks provided by device drivers, but in general those callbacks
need not provide the entire necessary functionality.  Namely, in
general it may be necessary to execute subsystem (i.e. device type,
device class or bus type) callbacks that will carry out all of the
necessary operations.

For this reason, modify pm_genpd_default_save_state() and
pm_genpd_default_restore_state() to execute subsystem callbacks,
if they are provided, and fall back to driver callbacks otherwise.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
(cherry picked from commit 0b589741b8b83a33e25fb32bb714ea1b972af5aa)

Change-Id: I573c7f62ea6ebd24a4dc643eb69da73d4b543017
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Reviewed-on: http://git-master/r/145218
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>

drivers/base/power/domain.c

index 83aa694..49fdd40 100644 (file)
@@ -1615,16 +1615,24 @@ EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
 static int pm_genpd_default_save_state(struct device *dev)
 {
        int (*cb)(struct device *__dev);
-       struct device_driver *drv = dev->driver;
 
        cb = dev_gpd_data(dev)->ops.save_state;
        if (cb)
                return cb(dev);
 
-       if (drv && drv->pm && drv->pm->runtime_suspend)
-               return drv->pm->runtime_suspend(dev);
+       if (dev->type && dev->type->pm)
+               cb = dev->type->pm->runtime_suspend;
+       else if (dev->class && dev->class->pm)
+               cb = dev->class->pm->runtime_suspend;
+       else if (dev->bus && dev->bus->pm)
+               cb = dev->bus->pm->runtime_suspend;
+       else
+               cb = NULL;
 
-       return 0;
+       if (!cb && dev->driver && dev->driver->pm)
+               cb = dev->driver->pm->runtime_suspend;
+
+       return cb ? cb(dev) : 0;
 }
 
 /**
@@ -1634,16 +1642,24 @@ static int pm_genpd_default_save_state(struct device *dev)
 static int pm_genpd_default_restore_state(struct device *dev)
 {
        int (*cb)(struct device *__dev);
-       struct device_driver *drv = dev->driver;
 
        cb = dev_gpd_data(dev)->ops.restore_state;
        if (cb)
                return cb(dev);
 
-       if (drv && drv->pm && drv->pm->runtime_resume)
-               return drv->pm->runtime_resume(dev);
+       if (dev->type && dev->type->pm)
+               cb = dev->type->pm->runtime_resume;
+       else if (dev->class && dev->class->pm)
+               cb = dev->class->pm->runtime_resume;
+       else if (dev->bus && dev->bus->pm)
+               cb = dev->bus->pm->runtime_resume;
+       else
+               cb = NULL;
 
-       return 0;
+       if (!cb && dev->driver && dev->driver->pm)
+               cb = dev->driver->pm->runtime_resume;
+
+       return cb ? cb(dev) : 0;
 }
 
 #ifdef CONFIG_PM_SLEEP