aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/pm-imx5.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/pm-imx5.c')
-rw-r--r--arch/arm/mach-imx/pm-imx5.c67
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 @@
13#include <linux/io.h> 13#include <linux/io.h>
14#include <linux/err.h> 14#include <linux/err.h>
15#include <asm/cacheflush.h> 15#include <asm/cacheflush.h>
16#include <asm/system_misc.h>
16#include <asm/tlbflush.h> 17#include <asm/tlbflush.h>
17#include <mach/common.h> 18#include <mach/common.h>
18#include <mach/hardware.h> 19#include <mach/hardware.h>
19#include "crm-regs-imx5.h" 20#include "crm-regs-imx5.h"
20 21
21static struct clk *gpc_dvfs_clk; 22/*
23 * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
24 * This is also the lowest power state possible without affecting
25 * non-cpu parts of the system. For these reasons, imx5 should default
26 * to always using this state for cpu idling. The PM_SUSPEND_STANDBY also
27 * uses this state and needs to take no action when registers remain confgiured
28 * for this state.
29 */
30#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
22 31
23/* 32/*
24 * set cpu low power mode before WFI instruction. This function is called 33 * set cpu low power mode before WFI instruction. This function is called
25 * mx5 because it can be used for mx50, mx51, and mx53. 34 * mx5 because it can be used for mx50, mx51, and mx53.
26 */ 35 */
27void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) 36static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
28{ 37{
29 u32 plat_lpc, arm_srpgcr, ccm_clpcr; 38 u32 plat_lpc, arm_srpgcr, ccm_clpcr;
30 u32 empgc0, empgc1; 39 u32 empgc0, empgc1;
@@ -87,11 +96,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
87 } 96 }
88} 97}
89 98
90static int mx5_suspend_prepare(void)
91{
92 return clk_prepare_enable(gpc_dvfs_clk);
93}
94
95static int mx5_suspend_enter(suspend_state_t state) 99static int mx5_suspend_enter(suspend_state_t state)
96{ 100{
97 switch (state) { 101 switch (state) {
@@ -99,7 +103,7 @@ static int mx5_suspend_enter(suspend_state_t state)
99 mx5_cpu_lp_set(STOP_POWER_OFF); 103 mx5_cpu_lp_set(STOP_POWER_OFF);
100 break; 104 break;
101 case PM_SUSPEND_STANDBY: 105 case PM_SUSPEND_STANDBY:
102 mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); 106 /* DEFAULT_IDLE_STATE already configured */
103 break; 107 break;
104 default: 108 default:
105 return -EINVAL; 109 return -EINVAL;
@@ -114,12 +118,10 @@ static int mx5_suspend_enter(suspend_state_t state)
114 __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); 118 __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
115 } 119 }
116 cpu_do_idle(); 120 cpu_do_idle();
117 return 0;
118}
119 121
120static void mx5_suspend_finish(void) 122 /* return registers to default idle state */
121{ 123 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
122 clk_disable_unprepare(gpc_dvfs_clk); 124 return 0;
123} 125}
124 126
125static int mx5_pm_valid(suspend_state_t state) 127static int mx5_pm_valid(suspend_state_t state)
@@ -129,25 +131,38 @@ static int mx5_pm_valid(suspend_state_t state)
129 131
130static const struct platform_suspend_ops mx5_suspend_ops = { 132static const struct platform_suspend_ops mx5_suspend_ops = {
131 .valid = mx5_pm_valid, 133 .valid = mx5_pm_valid,
132 .prepare = mx5_suspend_prepare,
133 .enter = mx5_suspend_enter, 134 .enter = mx5_suspend_enter,
134 .finish = mx5_suspend_finish,
135}; 135};
136 136
137static int __init mx5_pm_init(void) 137static void imx5_pm_idle(void)
138{ 138{
139 if (!cpu_is_mx51() && !cpu_is_mx53()) 139 if (likely(!tzic_enable_wake()))
140 return 0; 140 cpu_do_idle();
141}
142
143static int __init imx5_pm_common_init(void)
144{
145 int ret;
146 struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
147
148 if (IS_ERR(gpc_dvfs_clk))
149 return PTR_ERR(gpc_dvfs_clk);
141 150
142 if (gpc_dvfs_clk == NULL) 151 ret = clk_prepare_enable(gpc_dvfs_clk);
143 gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); 152 if (ret)
153 return ret;
144 154
145 if (!IS_ERR(gpc_dvfs_clk)) { 155 arm_pm_idle = imx5_pm_idle;
146 if (cpu_is_mx51()) 156
147 suspend_set_ops(&mx5_suspend_ops); 157 /* Set the registers to the default cpu idle state. */
148 } else 158 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
149 return -EPERM;
150 159
151 return 0; 160 return 0;
152} 161}
153device_initcall(mx5_pm_init); 162
163void __init imx51_pm_init(void)
164{
165 int ret = imx5_pm_common_init();
166 if (!ret)
167 suspend_set_ops(&mx5_suspend_ops);
168}