|
@@ -35,6 +35,11 @@
|
|
|
#include <mach/powerdomain.h>
|
|
|
#include <mach/clockdomain.h>
|
|
|
|
|
|
+enum {
|
|
|
+ PWRDM_STATE_NOW = 0,
|
|
|
+ PWRDM_STATE_PREV,
|
|
|
+};
|
|
|
+
|
|
|
/* pwrdm_list contains all registered struct powerdomains */
|
|
|
static LIST_HEAD(pwrdm_list);
|
|
|
|
|
@@ -102,6 +107,63 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
|
|
|
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]++;
|
|
|
+
|
|
|
+ pwrdm->state = state;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm)
|
|
|
+{
|
|
|
+ pwrdm_clear_all_prev_pwrst(pwrdm);
|
|
|
+ _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm)
|
|
|
+{
|
|
|
+ _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 +179,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);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1110,4 +1175,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);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pwrdm_post_transition(void)
|
|
|
+{
|
|
|
+ pwrdm_for_each(_pwrdm_post_transition_cb);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|