PM / Domains: Make it possible to add devices to inactive domains
authorRafael J. Wysocki <rjw@sisk.pl>
Mon, 14 May 2012 19:45:52 +0000 (21:45 +0200)
committerRafael J. Wysocki <rjw@sisk.pl>
Fri, 18 May 2012 18:45:26 +0000 (20:45 +0200)
The generic PM domains core code currently requires domains to be in
the "power on" state for adding devices to them, but this limitation
turns out to be inconvenient in some situations, so remove it.

For this purpose, make __pm_genpd_add_device() set the device's
need_restore flag if the domain is in the "power off" state, so that
the device's "restore state" (usually .runtime_resume()) callback
is executed when it is resumed after the domain has been turned on.
If the domain is in the "power on" state, the device's need_restore
flag will be cleared by __pm_genpd_add_device(), so that its "save
state" (usually .runtime_suspend()) callback is executed when the
domain is about to be turned off.  However, since that default
behavior need not be always desirable, add a helper function
pm_genpd_dev_need_restore() allowing a device's need_restore flag
to be set/unset at any time.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
drivers/base/power/domain.c
include/linux/pm_domain.h

index c3eaa08a8f963a724386e0d5d8e09bb7e353eb37..83aa694a8efe582f92365f193a07afcb5210b80d 100644 (file)
@@ -1263,11 +1263,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 
        genpd_acquire_lock(genpd);
 
-       if (genpd->status == GPD_STATE_POWER_OFF) {
-               ret = -EINVAL;
-               goto out;
-       }
-
        if (genpd->prepared_count > 0) {
                ret = -EAGAIN;
                goto out;
@@ -1290,7 +1285,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        dev->power.subsys_data->domain_data = &gpd_data->base;
        gpd_data->base.dev = dev;
        list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
-       gpd_data->need_restore = false;
+       gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
        if (td)
                gpd_data->td = *td;
 
@@ -1417,6 +1412,26 @@ void pm_genpd_dev_always_on(struct device *dev, bool val)
 }
 EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
 
+/**
+ * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
+ * @dev: Device to set/unset the flag for.
+ * @val: The new value of the device's "need restore" flag.
+ */
+void pm_genpd_dev_need_restore(struct device *dev, bool val)
+{
+       struct pm_subsys_data *psd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->power.lock, flags);
+
+       psd = dev_to_psd(dev);
+       if (psd && psd->domain_data)
+               to_gpd_data(psd->domain_data)->need_restore = val;
+
+       spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
+
 /**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
  * @genpd: Master PM domain to add the subdomain to.
index 1e994eeacdf3dfed0a1e1a2fad533aa337d121c2..30f794eb382654f9017b868b4245986b4e621a31 100644 (file)
@@ -146,6 +146,7 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node,
 extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                                  struct device *dev);
 extern void pm_genpd_dev_always_on(struct device *dev, bool val);
+extern void pm_genpd_dev_need_restore(struct device *dev, bool val);
 extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                                  struct generic_pm_domain *new_subdomain);
 extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
@@ -189,6 +190,7 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd,
        return -ENOSYS;
 }
 static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {}
+static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {}
 static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                                         struct generic_pm_domain *new_sd)
 {