diff options
Diffstat (limited to 'arch/arm/mach-imx/pm-imx5.c')
-rw-r--r-- | arch/arm/mach-imx/pm-imx5.c | 67 |
1 files changed, 41 insertions, 26 deletions
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index e26a9cb05ed8..baf93214f899 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -13,18 +13,27 @@ #include <linux/io.h> #include <linux/err.h> #include <asm/cacheflush.h> +#include <asm/system_misc.h> #include <asm/tlbflush.h> #include <mach/common.h> #include <mach/hardware.h> #include "crm-regs-imx5.h" -static struct clk *gpc_dvfs_clk; +/* + * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit. + * This is also the lowest power state possible without affecting + * non-cpu parts of the system. For these reasons, imx5 should default + * to always using this state for cpu idling. The PM_SUSPEND_STANDBY also + * uses this state and needs to take no action when registers remain confgiured + * for this state. + */ +#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF /* * set cpu low power mode before WFI instruction. This function is called * mx5 because it can be used for mx50, mx51, and mx53. */ -void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) +static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) { u32 plat_lpc, arm_srpgcr, ccm_clpcr; u32 empgc0, empgc1; @@ -87,11 +96,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) } } -static int mx5_suspend_prepare(void) -{ - return clk_prepare_enable(gpc_dvfs_clk); -} - static int mx5_suspend_enter(suspend_state_t state) { switch (state) { @@ -99,7 +103,7 @@ static int mx5_suspend_enter(suspend_state_t state) mx5_cpu_lp_set(STOP_POWER_OFF); break; case PM_SUSPEND_STANDBY: - mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + /* DEFAULT_IDLE_STATE already configured */ break; default: return -EINVAL; @@ -114,12 +118,10 @@ static int mx5_suspend_enter(suspend_state_t state) __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); } cpu_do_idle(); - return 0; -} -static void mx5_suspend_finish(void) -{ - clk_disable_unprepare(gpc_dvfs_clk); + /* return registers to default idle state */ + mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE); + return 0; } static int mx5_pm_valid(suspend_state_t state) @@ -129,25 +131,38 @@ static int mx5_pm_valid(suspend_state_t state) static const struct platform_suspend_ops mx5_suspend_ops = { .valid = mx5_pm_valid, - .prepare = mx5_suspend_prepare, .enter = mx5_suspend_enter, - .finish = mx5_suspend_finish, }; -static int __init mx5_pm_init(void) +static void imx5_pm_idle(void) { - if (!cpu_is_mx51() && !cpu_is_mx53()) - return 0; + if (likely(!tzic_enable_wake())) + cpu_do_idle(); +} + +static int __init imx5_pm_common_init(void) +{ + int ret; + struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); + + if (IS_ERR(gpc_dvfs_clk)) + return PTR_ERR(gpc_dvfs_clk); - if (gpc_dvfs_clk == NULL) - gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); + ret = clk_prepare_enable(gpc_dvfs_clk); + if (ret) + return ret; - if (!IS_ERR(gpc_dvfs_clk)) { - if (cpu_is_mx51()) - suspend_set_ops(&mx5_suspend_ops); - } else - return -EPERM; + arm_pm_idle = imx5_pm_idle; + + /* Set the registers to the default cpu idle state. */ + mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE); return 0; } -device_initcall(mx5_pm_init); + +void __init imx51_pm_init(void) +{ + int ret = imx5_pm_common_init(); + if (!ret) + suspend_set_ops(&mx5_suspend_ops); +} |