Merge branch 'pm-runtime'
[linux-2.6-block.git] / drivers / base / power / domain.c
index 7c5c7410d76c031b955bf3bf7246a674c9d84e8c..6a103a35ea9b375f9328573c2fdece516690c2f1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
 #include <linux/pm_qos.h>
+#include <linux/pm_clock.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sched.h>
@@ -151,6 +152,59 @@ static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
        genpd->cpuidle_data->idle_state->exit_latency = usecs64;
 }
 
+static int genpd_power_on(struct generic_pm_domain *genpd)
+{
+       ktime_t time_start;
+       s64 elapsed_ns;
+       int ret;
+
+       if (!genpd->power_on)
+               return 0;
+
+       time_start = ktime_get();
+       ret = genpd->power_on(genpd);
+       if (ret)
+               return ret;
+
+       elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+       if (elapsed_ns <= genpd->power_on_latency_ns)
+               return ret;
+
+       genpd->power_on_latency_ns = elapsed_ns;
+       genpd->max_off_time_changed = true;
+       genpd_recalc_cpu_exit_latency(genpd);
+       pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
+               genpd->name, "on", elapsed_ns);
+
+       return ret;
+}
+
+static int genpd_power_off(struct generic_pm_domain *genpd)
+{
+       ktime_t time_start;
+       s64 elapsed_ns;
+       int ret;
+
+       if (!genpd->power_off)
+               return 0;
+
+       time_start = ktime_get();
+       ret = genpd->power_off(genpd);
+       if (ret == -EBUSY)
+               return ret;
+
+       elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+       if (elapsed_ns <= genpd->power_off_latency_ns)
+               return ret;
+
+       genpd->power_off_latency_ns = elapsed_ns;
+       genpd->max_off_time_changed = true;
+       pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
+               genpd->name, "off", elapsed_ns);
+
+       return ret;
+}
+
 /**
  * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
@@ -222,25 +276,9 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
                }
        }
 
-       if (genpd->power_on) {
-               ktime_t time_start = ktime_get();
-               s64 elapsed_ns;
-
-               ret = genpd->power_on(genpd);
-               if (ret)
-                       goto err;
-
-               elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-               if (elapsed_ns > genpd->power_on_latency_ns) {
-                       genpd->power_on_latency_ns = elapsed_ns;
-                       genpd->max_off_time_changed = true;
-                       genpd_recalc_cpu_exit_latency(genpd);
-                       if (genpd->name)
-                               pr_warning("%s: Power-on latency exceeded, "
-                                       "new value %lld ns\n", genpd->name,
-                                       elapsed_ns);
-               }
-       }
+       ret = genpd_power_on(genpd);
+       if (ret)
+               goto err;
 
  out:
        genpd_set_active(genpd);
@@ -542,16 +580,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        }
 
        if (genpd->power_off) {
-               ktime_t time_start;
-               s64 elapsed_ns;
-
                if (atomic_read(&genpd->sd_count) > 0) {
                        ret = -EBUSY;
                        goto out;
                }
 
-               time_start = ktime_get();
-
                /*
                 * If sd_count > 0 at this point, one of the subdomains hasn't
                 * managed to call pm_genpd_poweron() for the master yet after
@@ -560,21 +593,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
                 * the pm_genpd_poweron() restore power for us (this shouldn't
                 * happen very often).
                 */
-               ret = genpd->power_off(genpd);
+               ret = genpd_power_off(genpd);
                if (ret == -EBUSY) {
                        genpd_set_active(genpd);
                        goto out;
                }
-
-               elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-               if (elapsed_ns > genpd->power_off_latency_ns) {
-                       genpd->power_off_latency_ns = elapsed_ns;
-                       genpd->max_off_time_changed = true;
-                       if (genpd->name)
-                               pr_warning("%s: Power-off latency exceeded, "
-                                       "new value %lld ns\n", genpd->name,
-                                       elapsed_ns);
-               }
        }
 
        genpd->status = GPD_STATE_POWER_OFF;
@@ -759,9 +782,9 @@ late_initcall(genpd_poweroff_unused);
  * pm_genpd_present - Check if the given PM domain has been initialized.
  * @genpd: PM domain to check.
  */
-static bool pm_genpd_present(struct generic_pm_domain *genpd)
+static bool pm_genpd_present(const struct generic_pm_domain *genpd)
 {
-       struct generic_pm_domain *gpd;
+       const struct generic_pm_domain *gpd;
 
        if (IS_ERR_OR_NULL(genpd))
                return false;
@@ -802,8 +825,7 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
            || atomic_read(&genpd->sd_count) > 0)
                return;
 
-       if (genpd->power_off)
-               genpd->power_off(genpd);
+       genpd_power_off(genpd);
 
        genpd->status = GPD_STATE_POWER_OFF;
 
@@ -834,8 +856,7 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
                genpd_sd_counter_inc(link->master);
        }
 
-       if (genpd->power_on)
-               genpd->power_on(genpd);
+       genpd_power_on(genpd);
 
        genpd->status = GPD_STATE_ACTIVE;
 }
@@ -1257,8 +1278,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
                         * If the domain was off before the hibernation, make
                         * sure it will be off going forward.
                         */
-                       if (genpd->power_off)
-                               genpd->power_off(genpd);
+                       genpd_power_off(genpd);
 
                        return 0;
                }
@@ -1909,6 +1929,12 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        genpd->domain.ops.complete = pm_genpd_complete;
        genpd->dev_ops.save_state = pm_genpd_default_save_state;
        genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
+
+       if (genpd->flags & GENPD_FLAG_PM_CLK) {
+               genpd->dev_ops.stop = pm_clk_suspend;
+               genpd->dev_ops.start = pm_clk_resume;
+       }
+
        mutex_lock(&gpd_list_lock);
        list_add(&genpd->gpd_list_node, &gpd_list);
        mutex_unlock(&gpd_list_lock);
@@ -2196,6 +2222,7 @@ int genpd_dev_pm_attach(struct device *dev)
        }
 
        dev->pm_domain->detach = genpd_dev_pm_detach;
+       pm_genpd_poweron(pd);
 
        return 0;
 }