summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
authorPeter 'p2' De Schrijver <peter.de-schrijver@nokia.com>2008-10-15 16:48:43 +0200
committerKevin Hilman <khilman@deeprootsystems.com>2009-09-03 00:08:23 +0200
commitba20bb126940ce4847e146a0d00b7f7b0868d773 (patch)
treed9a8f3c316aa66261ba026e9bd2507fa4ec9a931 /arch/arm/mach-omap2
parentOMAP3: update OMAP3 Beagle defconfig (diff)
downloadlinux-ba20bb126940ce4847e146a0d00b7f7b0868d773.tar.xz
linux-ba20bb126940ce4847e146a0d00b7f7b0868d773.zip
OMAP: PM counter infrastructure.
This patch provides the infrastructure to count how many times a powerdomain entered a given power state (on, inactive, retention, off). A number of functions are provided which will be called by the chip specific powerdomain and clockdomain code whenever a transition might have happened. Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c2
-rw-r--r--arch/arm/mach-omap2/powerdomain.c101
2 files changed, 101 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 0e7d501865b6..26912a95dc18 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -484,6 +484,8 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
v << __ffs(clkdm->clktrctrl_mask),
clkdm->pwrdm.ptr->prcm_offs,
CM_CLKSTCTRL);
+
+ pwrdm_clkdm_state_switch(clkdm);
}
/**
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 983f1cb676be..a2d98718c6d7 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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;
+}