]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/base/power/domain.c
Merge branches 'pm-cpufreq', 'pm-cpuidle' and 'pm-domains'
[linux.git] / drivers / base / power / domain.c
index 0c80bea05bcb92be79b90e3210fbfdbbb65d0bac..1ea0e2502e8ed4db0792935be700da3909aa83b3 100644 (file)
@@ -1032,15 +1032,12 @@ static int genpd_prepare(struct device *dev)
 static int genpd_finish_suspend(struct device *dev, bool poweroff)
 {
        struct generic_pm_domain *genpd;
-       int ret;
+       int ret = 0;
 
        genpd = dev_to_genpd(dev);
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd))
-               return 0;
-
        if (poweroff)
                ret = pm_generic_poweroff_noirq(dev);
        else
@@ -1048,10 +1045,19 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff)
        if (ret)
                return ret;
 
-       if (genpd->dev_ops.stop && genpd->dev_ops.start) {
-               ret = pm_runtime_force_suspend(dev);
-               if (ret)
+       if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd))
+               return 0;
+
+       if (genpd->dev_ops.stop && genpd->dev_ops.start &&
+           !pm_runtime_status_suspended(dev)) {
+               ret = genpd_stop_dev(genpd, dev);
+               if (ret) {
+                       if (poweroff)
+                               pm_generic_restore_noirq(dev);
+                       else
+                               pm_generic_resume_noirq(dev);
                        return ret;
+               }
        }
 
        genpd_lock(genpd);
@@ -1085,7 +1091,7 @@ static int genpd_suspend_noirq(struct device *dev)
 static int genpd_resume_noirq(struct device *dev)
 {
        struct generic_pm_domain *genpd;
-       int ret = 0;
+       int ret;
 
        dev_dbg(dev, "%s()\n", __func__);
 
@@ -1094,21 +1100,21 @@ static int genpd_resume_noirq(struct device *dev)
                return -EINVAL;
 
        if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd))
-               return 0;
+               return pm_generic_resume_noirq(dev);
 
        genpd_lock(genpd);
        genpd_sync_power_on(genpd, true, 0);
        genpd->suspended_count--;
        genpd_unlock(genpd);
 
-       if (genpd->dev_ops.stop && genpd->dev_ops.start)
-               ret = pm_runtime_force_resume(dev);
-
-       ret = pm_generic_resume_noirq(dev);
-       if (ret)
-               return ret;
+       if (genpd->dev_ops.stop && genpd->dev_ops.start &&
+           !pm_runtime_status_suspended(dev)) {
+               ret = genpd_start_dev(genpd, dev);
+               if (ret)
+                       return ret;
+       }
 
-       return ret;
+       return pm_generic_resume_noirq(dev);
 }
 
 /**
@@ -1135,8 +1141,9 @@ static int genpd_freeze_noirq(struct device *dev)
        if (ret)
                return ret;
 
-       if (genpd->dev_ops.stop && genpd->dev_ops.start)
-               ret = pm_runtime_force_suspend(dev);
+       if (genpd->dev_ops.stop && genpd->dev_ops.start &&
+           !pm_runtime_status_suspended(dev))
+               ret = genpd_stop_dev(genpd, dev);
 
        return ret;
 }
@@ -1159,8 +1166,9 @@ static int genpd_thaw_noirq(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       if (genpd->dev_ops.stop && genpd->dev_ops.start) {
-               ret = pm_runtime_force_resume(dev);
+       if (genpd->dev_ops.stop && genpd->dev_ops.start &&
+           !pm_runtime_status_suspended(dev)) {
+               ret = genpd_start_dev(genpd, dev);
                if (ret)
                        return ret;
        }
@@ -1217,8 +1225,9 @@ static int genpd_restore_noirq(struct device *dev)
        genpd_sync_power_on(genpd, true, 0);
        genpd_unlock(genpd);
 
-       if (genpd->dev_ops.stop && genpd->dev_ops.start) {
-               ret = pm_runtime_force_resume(dev);
+       if (genpd->dev_ops.stop && genpd->dev_ops.start &&
+           !pm_runtime_status_suspended(dev)) {
+               ret = genpd_start_dev(genpd, dev);
                if (ret)
                        return ret;
        }
@@ -2199,20 +2208,8 @@ int genpd_dev_pm_attach(struct device *dev)
 
        ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
                                        "#power-domain-cells", 0, &pd_args);
-       if (ret < 0) {
-               if (ret != -ENOENT)
-                       return ret;
-
-               /*
-                * Try legacy Samsung-specific bindings
-                * (for backwards compatibility of DT ABI)
-                */
-               pd_args.args_count = 0;
-               pd_args.np = of_parse_phandle(dev->of_node,
-                                               "samsung,power-domain", 0);
-               if (!pd_args.np)
-                       return -ENOENT;
-       }
+       if (ret < 0)
+               return ret;
 
        mutex_lock(&gpd_list_lock);
        pd = genpd_get_from_provider(&pd_args);
@@ -2293,6 +2290,38 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state,
        return 0;
 }
 
+static int genpd_iterate_idle_states(struct device_node *dn,
+                                    struct genpd_power_state *states)
+{
+       int ret;
+       struct of_phandle_iterator it;
+       struct device_node *np;
+       int i = 0;
+
+       ret = of_count_phandle_with_args(dn, "domain-idle-states", NULL);
+       if (ret <= 0)
+               return ret;
+
+       /* Loop over the phandles until all the requested entry is found */
+       of_for_each_phandle(&it, ret, dn, "domain-idle-states", NULL, 0) {
+               np = it.node;
+               if (!of_match_node(idle_state_match, np))
+                       continue;
+               if (states) {
+                       ret = genpd_parse_state(&states[i], np);
+                       if (ret) {
+                               pr_err("Parsing idle state node %pOF failed with err %d\n",
+                                      np, ret);
+                               of_node_put(np);
+                               return ret;
+                       }
+               }
+               i++;
+       }
+
+       return i;
+}
+
 /**
  * of_genpd_parse_idle_states: Return array of idle states for the genpd.
  *
@@ -2302,49 +2331,31 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state,
  *
  * Returns the device states parsed from the OF node. The memory for the states
  * is allocated by this function and is the responsibility of the caller to
- * free the memory after use.
+ * free the memory after use. If no domain idle states is found it returns
+ * -EINVAL and in case of errors, a negative error code.
  */
 int of_genpd_parse_idle_states(struct device_node *dn,
                        struct genpd_power_state **states, int *n)
 {
        struct genpd_power_state *st;
-       struct device_node *np;
-       int i = 0;
-       int err, ret;
-       int count;
-       struct of_phandle_iterator it;
-       const struct of_device_id *match_id;
+       int ret;
 
-       count = of_count_phandle_with_args(dn, "domain-idle-states", NULL);
-       if (count <= 0)
-               return -EINVAL;
+       ret = genpd_iterate_idle_states(dn, NULL);
+       if (ret <= 0)
+               return ret < 0 ? ret : -EINVAL;
 
-       st = kcalloc(count, sizeof(*st), GFP_KERNEL);
+       st = kcalloc(ret, sizeof(*st), GFP_KERNEL);
        if (!st)
                return -ENOMEM;
 
-       /* Loop over the phandles until all the requested entry is found */
-       of_for_each_phandle(&it, err, dn, "domain-idle-states", NULL, 0) {
-               np = it.node;
-               match_id = of_match_node(idle_state_match, np);
-               if (!match_id)
-                       continue;
-               ret = genpd_parse_state(&st[i++], np);
-               if (ret) {
-                       pr_err
-                       ("Parsing idle state node %pOF failed with err %d\n",
-                                                       np, ret);
-                       of_node_put(np);
-                       kfree(st);
-                       return ret;
-               }
+       ret = genpd_iterate_idle_states(dn, st);
+       if (ret <= 0) {
+               kfree(st);
+               return ret < 0 ? ret : -EINVAL;
        }
 
-       *n = i;
-       if (!i)
-               kfree(st);
-       else
-               *states = st;
+       *states = st;
+       *n = ret;
 
        return 0;
 }