From e68e8093ed570f9272665112d13d4c5811536680 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 30 Jan 2012 02:47:24 -0700 Subject: ARM: OMAP2+: PM: clean up omap_set_pwrdm_state() Clean up a few different parts of omap_set_pwrdm_state(): - Remove a superfluous call to pwrdm_state_switch(). Not needed unless LOWPOWERSTATECHANGE is used, because the state switch code is called by either clkdm_sleep() or clkdm_allow_idle(). - Add code to wait for the power state transition in the OMAP4+ low power state change. This is speculative, so I would particularly appreciate feedback on this part. - Remove a superfluous call to pwrdm_read_pwrst(). - Update variable names to be more meaningful (hopefully) and precise. - Fix an error path bug that would not place the clockdomain back into hardware-supervised idle or sleep mode if the power state could not be programmed. The documentation for this function still needs major improvements; that's left for a later patch. Signed-off-by: Paul Walmsley Cc: Rajendra Nayak Tested-by: Tero Kristo Acked-by: Santosh Shilimkar Tested-by: Kevin Hilman Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'arch/arm/mach-omap2/pm.c') diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index fb9b85bfc308..c3fe8eada2cc 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -72,28 +72,27 @@ static void omap2_init_processor_devices(void) * This sets pwrdm state (other than mpu & core. Currently only ON & * RET are supported. */ -int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) +int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) { - u32 cur_state; - int sleep_switch = -1; - int ret = 0; - int hwsup = 0; + u8 curr_pwrst, next_pwrst; + int sleep_switch = -1, ret = 0, hwsup = 0; - if (pwrdm == NULL || IS_ERR(pwrdm)) + if (!pwrdm || IS_ERR(pwrdm)) return -EINVAL; - while (!(pwrdm->pwrsts & (1 << state))) { - if (state == PWRDM_POWER_OFF) + while (!(pwrdm->pwrsts & (1 << pwrst))) { + if (pwrst == PWRDM_POWER_OFF) return ret; - state--; + pwrst--; } - cur_state = pwrdm_read_next_pwrst(pwrdm); - if (cur_state == state) + next_pwrst = pwrdm_read_next_pwrst(pwrdm); + if (next_pwrst == pwrst) return ret; - if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { - if ((pwrdm_read_pwrst(pwrdm) > state) && + curr_pwrst = pwrdm_read_pwrst(pwrdm); + if (curr_pwrst < PWRDM_POWER_ON) { + if ((curr_pwrst > pwrst) && (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { sleep_switch = LOWPOWERSTATE_SWITCH; } else { @@ -103,12 +102,10 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) } } - ret = pwrdm_set_next_pwrst(pwrdm, state); - if (ret) { - pr_err("%s: unable to set state of powerdomain: %s\n", + ret = pwrdm_set_next_pwrst(pwrdm, pwrst); + if (ret) + pr_err("%s: unable to set power state of powerdomain: %s\n", __func__, pwrdm->name); - goto err; - } switch (sleep_switch) { case FORCEWAKEUP_SWITCH: @@ -119,13 +116,11 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) break; case LOWPOWERSTATE_SWITCH: pwrdm_set_lowpwrstchange(pwrdm); + pwrdm_wait_transition(pwrdm); + pwrdm_state_switch(pwrdm); break; - default: - return ret; } - pwrdm_state_switch(pwrdm); -err: return ret; } -- cgit v1.2.3 From 92206fd292da7632c039f6c4054bdaac08b030c0 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 2 Feb 2012 02:38:50 -0700 Subject: ARM: OMAP2+: PM: share clkdms_setup() across OMAP2, 3, 4 clkdms_setup() is identical across OMAP2, 3, and 4, so share it. Signed-off-by: Paul Walmsley Tested-by: Santosh Shilimkar Cc: Rajendra Nayak Tested-by: Kevin Hilman Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/arm/mach-omap2/pm.c') diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index c3fe8eada2cc..f9e807958f3e 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -68,6 +68,16 @@ static void omap2_init_processor_devices(void) #define FORCEWAKEUP_SWITCH 0 #define LOWPOWERSTATE_SWITCH 1 +int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) +{ + if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) + clkdm_allow_idle(clkdm); + else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && + atomic_read(&clkdm->usecount) == 0) + clkdm_sleep(clkdm); + return 0; +} + /* * This sets pwrdm state (other than mpu & core. Currently only ON & * RET are supported. -- cgit v1.2.3 From 1416408d31236dc2a80d269aa23ffa93aa01e833 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 2 Feb 2012 02:30:50 -0700 Subject: ARM: OMAP2+: PM: share some suspend-related functions across OMAP2, 3, 4 The platform_suspend_ops can be shared across OMAP2, 3, and 4, along with all of the functions referenced in that structure. This patch shares them. It also removes the suspend_state file-scoped variable in the OMAP2 and 3 PM code; it does not appear to be actually needed by anything. Signed-off-by: Paul Walmsley Cc: Santosh Shilimkar Cc: Rajendra Nayak Reviewed-by: Kevin Hilman [khilman@ti.com: minor rework needed due to rebase/merge with conflicting changes] Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'arch/arm/mach-omap2/pm.c') diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index f9e807958f3e..28706696a341 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -15,11 +15,13 @@ #include #include #include +#include #include #include #include "common.h" +#include "prcm-common.h" #include "voltage.h" #include "powerdomain.h" #include "clockdomain.h" @@ -28,6 +30,12 @@ static struct omap_device_pm_latency *pm_lats; +/* + * omap_pm_suspend: points to a function that does the SoC-specific + * suspend work + */ +int (*omap_pm_suspend)(void); + static int __init _init_omap_device(char *name) { struct omap_hwmod *oh; @@ -134,6 +142,8 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) return ret; } + + /* * This API is to be called during init to set the various voltage * domains to the voltage as per the opp table. Typically we boot up @@ -201,6 +211,56 @@ exit: return -EINVAL; } +#ifdef CONFIG_SUSPEND +static int omap_pm_enter(suspend_state_t suspend_state) +{ + int ret = 0; + + if (!omap_pm_suspend) + return -ENOENT; /* XXX doublecheck */ + + switch (suspend_state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + ret = omap_pm_suspend(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int omap_pm_begin(suspend_state_t state) +{ + disable_hlt(); + if (cpu_is_omap34xx()) + omap_prcm_irq_prepare(); + return 0; +} + +static void omap_pm_end(void) +{ + enable_hlt(); + return; +} + +static void omap_pm_finish(void) +{ + if (cpu_is_omap34xx()) + omap_prcm_irq_complete(); +} + +static const struct platform_suspend_ops omap_pm_ops = { + .begin = omap_pm_begin, + .end = omap_pm_end, + .enter = omap_pm_enter, + .finish = omap_pm_finish, + .valid = suspend_valid_only_mem, +}; + +#endif /* CONFIG_SUSPEND */ + static void __init omap3_init_voltages(void) { if (!cpu_is_omap34xx()) @@ -243,6 +303,10 @@ static int __init omap2_common_pm_late_init(void) /* Smartreflex device init */ omap_devinit_smartreflex(); +#ifdef CONFIG_SUSPEND + suspend_set_ops(&omap_pm_ops); +#endif + return 0; } late_initcall(omap2_common_pm_late_init); -- cgit v1.2.3