Merge branch 'video' into release
[sfrench/cifs-2.6.git] / arch / arm / mach-omap2 / powerdomain.c
index 983f1cb676be26ad24f88c7d834035a2c5fea15c..2594cbff3947e12f8d37c966e22fd99a22c5a1d1 100644 (file)
 #include <mach/powerdomain.h>
 #include <mach/clockdomain.h>
 
+#include "pm.h"
+
+enum {
+       PWRDM_STATE_NOW = 0,
+       PWRDM_STATE_PREV,
+};
+
 /* pwrdm_list contains all registered struct powerdomains */
 static LIST_HEAD(pwrdm_list);
 
@@ -83,7 +90,7 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
        if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip))
                return ERR_PTR(-EINVAL);
 
-       for (pd = deps; pd; pd++) {
+       for (pd = deps; pd->pwrdm_name; pd++) {
 
                if (!omap_chip_is(pd->omap_chip))
                        continue;
@@ -96,12 +103,71 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
 
        }
 
-       if (!pd)
+       if (!pd->pwrdm_name)
                return ERR_PTR(-ENOENT);
 
        return pd->pwrdm;
 }
 
+static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
+{
+
+       int prev;
+       int state;
+
+       if (pwrdm == NULL)
+               return -EINVAL;
+
+       state = pwrdm_read_pwrst(pwrdm);
+
+       switch (flag) {
+       case PWRDM_STATE_NOW:
+               prev = pwrdm->state;
+               break;
+       case PWRDM_STATE_PREV:
+               prev = pwrdm_read_prev_pwrst(pwrdm);
+               if (pwrdm->state != prev)
+                       pwrdm->state_counter[prev]++;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (state != prev)
+               pwrdm->state_counter[state]++;
+
+       pm_dbg_update_time(pwrdm, prev);
+
+       pwrdm->state = state;
+
+       return 0;
+}
+
+static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
+{
+       pwrdm_clear_all_prev_pwrst(pwrdm);
+       _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+       return 0;
+}
+
+static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
+{
+       _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
+       return 0;
+}
+
+static __init void _pwrdm_setup(struct powerdomain *pwrdm)
+{
+       int i;
+
+       for (i = 0; i < 4; i++)
+               pwrdm->state_counter[i] = 0;
+
+       pwrdm_wait_transition(pwrdm);
+       pwrdm->state = pwrdm_read_pwrst(pwrdm);
+       pwrdm->state_counter[pwrdm->state] = 1;
+
+}
 
 /* Public functions */
 
@@ -117,9 +183,12 @@ void pwrdm_init(struct powerdomain **pwrdm_list)
 {
        struct powerdomain **p = NULL;
 
-       if (pwrdm_list)
-               for (p = pwrdm_list; *p; p++)
+       if (pwrdm_list) {
+               for (p = pwrdm_list; *p; p++) {
                        pwrdm_register(*p);
+                       _pwrdm_setup(*p);
+               }
+       }
 }
 
 /**
@@ -217,7 +286,8 @@ struct powerdomain *pwrdm_lookup(const char *name)
  * anything else to indicate failure; or -EINVAL if the function
  * pointer is null.
  */
-int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm))
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+                       void *user)
 {
        struct powerdomain *temp_pwrdm;
        unsigned long flags;
@@ -228,7 +298,7 @@ int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm))
 
        read_lock_irqsave(&pwrdm_rwlock, flags);
        list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
-               ret = (*fn)(temp_pwrdm);
+               ret = (*fn)(temp_pwrdm, user);
                if (ret)
                        break;
        }
@@ -1110,4 +1180,36 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm)
        return 0;
 }
 
+int pwrdm_state_switch(struct powerdomain *pwrdm)
+{
+       return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+}
+
+int pwrdm_clkdm_state_switch(struct clockdomain *clkdm)
+{
+       if (clkdm != NULL && clkdm->pwrdm.ptr != NULL) {
+               pwrdm_wait_transition(clkdm->pwrdm.ptr);
+               return pwrdm_state_switch(clkdm->pwrdm.ptr);
+       }
+
+       return -EINVAL;
+}
+int pwrdm_clk_state_switch(struct clk *clk)
+{
+       if (clk != NULL && clk->clkdm != NULL)
+               return pwrdm_clkdm_state_switch(clk->clkdm);
+       return -EINVAL;
+}
+
+int pwrdm_pre_transition(void)
+{
+       pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
+       return 0;
+}
+
+int pwrdm_post_transition(void)
+{
+       pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
+       return 0;
+}