diff options
Diffstat (limited to 'arch/arm/mach-omap2/pm.c')
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 113 |
1 files changed, 91 insertions, 22 deletions
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 184ae21feea7..52787b0eaec6 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -15,11 +15,13 @@ | |||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/opp.h> | 16 | #include <linux/opp.h> |
17 | #include <linux/export.h> | 17 | #include <linux/export.h> |
18 | #include <linux/suspend.h> | ||
18 | 19 | ||
19 | #include <plat/omap-pm.h> | 20 | #include <plat/omap-pm.h> |
20 | #include <plat/omap_device.h> | 21 | #include <plat/omap_device.h> |
21 | #include "common.h" | 22 | #include "common.h" |
22 | 23 | ||
24 | #include "prcm-common.h" | ||
23 | #include "voltage.h" | 25 | #include "voltage.h" |
24 | #include "powerdomain.h" | 26 | #include "powerdomain.h" |
25 | #include "clockdomain.h" | 27 | #include "clockdomain.h" |
@@ -28,6 +30,12 @@ | |||
28 | 30 | ||
29 | static struct omap_device_pm_latency *pm_lats; | 31 | static struct omap_device_pm_latency *pm_lats; |
30 | 32 | ||
33 | /* | ||
34 | * omap_pm_suspend: points to a function that does the SoC-specific | ||
35 | * suspend work | ||
36 | */ | ||
37 | int (*omap_pm_suspend)(void); | ||
38 | |||
31 | static int __init _init_omap_device(char *name) | 39 | static int __init _init_omap_device(char *name) |
32 | { | 40 | { |
33 | struct omap_hwmod *oh; | 41 | struct omap_hwmod *oh; |
@@ -68,32 +76,41 @@ static void __init omap2_init_processor_devices(void) | |||
68 | #define FORCEWAKEUP_SWITCH 0 | 76 | #define FORCEWAKEUP_SWITCH 0 |
69 | #define LOWPOWERSTATE_SWITCH 1 | 77 | #define LOWPOWERSTATE_SWITCH 1 |
70 | 78 | ||
79 | int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) | ||
80 | { | ||
81 | if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) | ||
82 | clkdm_allow_idle(clkdm); | ||
83 | else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && | ||
84 | atomic_read(&clkdm->usecount) == 0) | ||
85 | clkdm_sleep(clkdm); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
71 | /* | 89 | /* |
72 | * This sets pwrdm state (other than mpu & core. Currently only ON & | 90 | * This sets pwrdm state (other than mpu & core. Currently only ON & |
73 | * RET are supported. | 91 | * RET are supported. |
74 | */ | 92 | */ |
75 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | 93 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) |
76 | { | 94 | { |
77 | u32 cur_state; | 95 | u8 curr_pwrst, next_pwrst; |
78 | int sleep_switch = -1; | 96 | int sleep_switch = -1, ret = 0, hwsup = 0; |
79 | int ret = 0; | ||
80 | int hwsup = 0; | ||
81 | 97 | ||
82 | if (pwrdm == NULL || IS_ERR(pwrdm)) | 98 | if (!pwrdm || IS_ERR(pwrdm)) |
83 | return -EINVAL; | 99 | return -EINVAL; |
84 | 100 | ||
85 | while (!(pwrdm->pwrsts & (1 << state))) { | 101 | while (!(pwrdm->pwrsts & (1 << pwrst))) { |
86 | if (state == PWRDM_POWER_OFF) | 102 | if (pwrst == PWRDM_POWER_OFF) |
87 | return ret; | 103 | return ret; |
88 | state--; | 104 | pwrst--; |
89 | } | 105 | } |
90 | 106 | ||
91 | cur_state = pwrdm_read_next_pwrst(pwrdm); | 107 | next_pwrst = pwrdm_read_next_pwrst(pwrdm); |
92 | if (cur_state == state) | 108 | if (next_pwrst == pwrst) |
93 | return ret; | 109 | return ret; |
94 | 110 | ||
95 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { | 111 | curr_pwrst = pwrdm_read_pwrst(pwrdm); |
96 | if ((pwrdm_read_pwrst(pwrdm) > state) && | 112 | if (curr_pwrst < PWRDM_POWER_ON) { |
113 | if ((curr_pwrst > pwrst) && | ||
97 | (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { | 114 | (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { |
98 | sleep_switch = LOWPOWERSTATE_SWITCH; | 115 | sleep_switch = LOWPOWERSTATE_SWITCH; |
99 | } else { | 116 | } else { |
@@ -103,12 +120,10 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | |||
103 | } | 120 | } |
104 | } | 121 | } |
105 | 122 | ||
106 | ret = pwrdm_set_next_pwrst(pwrdm, state); | 123 | ret = pwrdm_set_next_pwrst(pwrdm, pwrst); |
107 | if (ret) { | 124 | if (ret) |
108 | pr_err("%s: unable to set state of powerdomain: %s\n", | 125 | pr_err("%s: unable to set power state of powerdomain: %s\n", |
109 | __func__, pwrdm->name); | 126 | __func__, pwrdm->name); |
110 | goto err; | ||
111 | } | ||
112 | 127 | ||
113 | switch (sleep_switch) { | 128 | switch (sleep_switch) { |
114 | case FORCEWAKEUP_SWITCH: | 129 | case FORCEWAKEUP_SWITCH: |
@@ -119,16 +134,16 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | |||
119 | break; | 134 | break; |
120 | case LOWPOWERSTATE_SWITCH: | 135 | case LOWPOWERSTATE_SWITCH: |
121 | pwrdm_set_lowpwrstchange(pwrdm); | 136 | pwrdm_set_lowpwrstchange(pwrdm); |
137 | pwrdm_wait_transition(pwrdm); | ||
138 | pwrdm_state_switch(pwrdm); | ||
122 | break; | 139 | break; |
123 | default: | ||
124 | return ret; | ||
125 | } | 140 | } |
126 | 141 | ||
127 | pwrdm_state_switch(pwrdm); | ||
128 | err: | ||
129 | return ret; | 142 | return ret; |
130 | } | 143 | } |
131 | 144 | ||
145 | |||
146 | |||
132 | /* | 147 | /* |
133 | * This API is to be called during init to set the various voltage | 148 | * This API is to be called during init to set the various voltage |
134 | * domains to the voltage as per the opp table. Typically we boot up | 149 | * domains to the voltage as per the opp table. Typically we boot up |
@@ -199,6 +214,56 @@ exit: | |||
199 | return -EINVAL; | 214 | return -EINVAL; |
200 | } | 215 | } |
201 | 216 | ||
217 | #ifdef CONFIG_SUSPEND | ||
218 | static int omap_pm_enter(suspend_state_t suspend_state) | ||
219 | { | ||
220 | int ret = 0; | ||
221 | |||
222 | if (!omap_pm_suspend) | ||
223 | return -ENOENT; /* XXX doublecheck */ | ||
224 | |||
225 | switch (suspend_state) { | ||
226 | case PM_SUSPEND_STANDBY: | ||
227 | case PM_SUSPEND_MEM: | ||
228 | ret = omap_pm_suspend(); | ||
229 | break; | ||
230 | default: | ||
231 | ret = -EINVAL; | ||
232 | } | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | static int omap_pm_begin(suspend_state_t state) | ||
238 | { | ||
239 | disable_hlt(); | ||
240 | if (cpu_is_omap34xx()) | ||
241 | omap_prcm_irq_prepare(); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static void omap_pm_end(void) | ||
246 | { | ||
247 | enable_hlt(); | ||
248 | return; | ||
249 | } | ||
250 | |||
251 | static void omap_pm_finish(void) | ||
252 | { | ||
253 | if (cpu_is_omap34xx()) | ||
254 | omap_prcm_irq_complete(); | ||
255 | } | ||
256 | |||
257 | static const struct platform_suspend_ops omap_pm_ops = { | ||
258 | .begin = omap_pm_begin, | ||
259 | .end = omap_pm_end, | ||
260 | .enter = omap_pm_enter, | ||
261 | .finish = omap_pm_finish, | ||
262 | .valid = suspend_valid_only_mem, | ||
263 | }; | ||
264 | |||
265 | #endif /* CONFIG_SUSPEND */ | ||
266 | |||
202 | static void __init omap3_init_voltages(void) | 267 | static void __init omap3_init_voltages(void) |
203 | { | 268 | { |
204 | if (!cpu_is_omap34xx()) | 269 | if (!cpu_is_omap34xx()) |
@@ -241,6 +306,10 @@ static int __init omap2_common_pm_late_init(void) | |||
241 | /* Smartreflex device init */ | 306 | /* Smartreflex device init */ |
242 | omap_devinit_smartreflex(); | 307 | omap_devinit_smartreflex(); |
243 | 308 | ||
309 | #ifdef CONFIG_SUSPEND | ||
310 | suspend_set_ops(&omap_pm_ops); | ||
311 | #endif | ||
312 | |||
244 | return 0; | 313 | return 0; |
245 | } | 314 | } |
246 | late_initcall(omap2_common_pm_late_init); | 315 | late_initcall(omap2_common_pm_late_init); |