diff options
Diffstat (limited to 'arch/arm/mach-omap2/pm.c')
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 144 |
1 files changed, 132 insertions, 12 deletions
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 59ca03b0e691..d5a102c71989 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -13,13 +13,16 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/opp.h> | ||
16 | 17 | ||
17 | #include <plat/omap-pm.h> | 18 | #include <plat/omap-pm.h> |
18 | #include <plat/omap_device.h> | 19 | #include <plat/omap_device.h> |
19 | #include <plat/common.h> | 20 | #include <plat/common.h> |
21 | #include <plat/voltage.h> | ||
20 | 22 | ||
21 | #include <plat/powerdomain.h> | 23 | #include "powerdomain.h" |
22 | #include <plat/clockdomain.h> | 24 | #include "clockdomain.h" |
25 | #include "pm.h" | ||
23 | 26 | ||
24 | static struct omap_device_pm_latency *pm_lats; | 27 | static struct omap_device_pm_latency *pm_lats; |
25 | 28 | ||
@@ -89,10 +92,13 @@ static void omap2_init_processor_devices(void) | |||
89 | } | 92 | } |
90 | } | 93 | } |
91 | 94 | ||
95 | /* Types of sleep_switch used in omap_set_pwrdm_state */ | ||
96 | #define FORCEWAKEUP_SWITCH 0 | ||
97 | #define LOWPOWERSTATE_SWITCH 1 | ||
98 | |||
92 | /* | 99 | /* |
93 | * This sets pwrdm state (other than mpu & core. Currently only ON & | 100 | * This sets pwrdm state (other than mpu & core. Currently only ON & |
94 | * RET are supported. Function is assuming that clkdm doesn't have | 101 | * RET are supported. |
95 | * hw_sup mode enabled. | ||
96 | */ | 102 | */ |
97 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | 103 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) |
98 | { | 104 | { |
@@ -114,9 +120,14 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | |||
114 | return ret; | 120 | return ret; |
115 | 121 | ||
116 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { | 122 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { |
117 | omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); | 123 | if ((pwrdm_read_pwrst(pwrdm) > state) && |
118 | sleep_switch = 1; | 124 | (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { |
119 | pwrdm_wait_transition(pwrdm); | 125 | sleep_switch = LOWPOWERSTATE_SWITCH; |
126 | } else { | ||
127 | omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); | ||
128 | pwrdm_wait_transition(pwrdm); | ||
129 | sleep_switch = FORCEWAKEUP_SWITCH; | ||
130 | } | ||
120 | } | 131 | } |
121 | 132 | ||
122 | ret = pwrdm_set_next_pwrst(pwrdm, state); | 133 | ret = pwrdm_set_next_pwrst(pwrdm, state); |
@@ -126,16 +137,106 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | |||
126 | goto err; | 137 | goto err; |
127 | } | 138 | } |
128 | 139 | ||
129 | if (sleep_switch) { | 140 | switch (sleep_switch) { |
130 | omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); | 141 | case FORCEWAKEUP_SWITCH: |
131 | pwrdm_wait_transition(pwrdm); | 142 | if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO) |
132 | pwrdm_state_switch(pwrdm); | 143 | omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); |
144 | else | ||
145 | omap2_clkdm_sleep(pwrdm->pwrdm_clkdms[0]); | ||
146 | break; | ||
147 | case LOWPOWERSTATE_SWITCH: | ||
148 | pwrdm_set_lowpwrstchange(pwrdm); | ||
149 | break; | ||
150 | default: | ||
151 | return ret; | ||
133 | } | 152 | } |
134 | 153 | ||
154 | pwrdm_wait_transition(pwrdm); | ||
155 | pwrdm_state_switch(pwrdm); | ||
135 | err: | 156 | err: |
136 | return ret; | 157 | return ret; |
137 | } | 158 | } |
138 | 159 | ||
160 | /* | ||
161 | * This API is to be called during init to put the various voltage | ||
162 | * domains to the voltage as per the opp table. Typically we boot up | ||
163 | * at the nominal voltage. So this function finds out the rate of | ||
164 | * the clock associated with the voltage domain, finds out the correct | ||
165 | * opp entry and puts the voltage domain to the voltage specifies | ||
166 | * in the opp entry | ||
167 | */ | ||
168 | static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, | ||
169 | struct device *dev) | ||
170 | { | ||
171 | struct voltagedomain *voltdm; | ||
172 | struct clk *clk; | ||
173 | struct opp *opp; | ||
174 | unsigned long freq, bootup_volt; | ||
175 | |||
176 | if (!vdd_name || !clk_name || !dev) { | ||
177 | printk(KERN_ERR "%s: Invalid parameters!\n", __func__); | ||
178 | goto exit; | ||
179 | } | ||
180 | |||
181 | voltdm = omap_voltage_domain_lookup(vdd_name); | ||
182 | if (IS_ERR(voltdm)) { | ||
183 | printk(KERN_ERR "%s: Unable to get vdd pointer for vdd_%s\n", | ||
184 | __func__, vdd_name); | ||
185 | goto exit; | ||
186 | } | ||
187 | |||
188 | clk = clk_get(NULL, clk_name); | ||
189 | if (IS_ERR(clk)) { | ||
190 | printk(KERN_ERR "%s: unable to get clk %s\n", | ||
191 | __func__, clk_name); | ||
192 | goto exit; | ||
193 | } | ||
194 | |||
195 | freq = clk->rate; | ||
196 | clk_put(clk); | ||
197 | |||
198 | opp = opp_find_freq_ceil(dev, &freq); | ||
199 | if (IS_ERR(opp)) { | ||
200 | printk(KERN_ERR "%s: unable to find boot up OPP for vdd_%s\n", | ||
201 | __func__, vdd_name); | ||
202 | goto exit; | ||
203 | } | ||
204 | |||
205 | bootup_volt = opp_get_voltage(opp); | ||
206 | if (!bootup_volt) { | ||
207 | printk(KERN_ERR "%s: unable to find voltage corresponding" | ||
208 | "to the bootup OPP for vdd_%s\n", __func__, vdd_name); | ||
209 | goto exit; | ||
210 | } | ||
211 | |||
212 | omap_voltage_scale_vdd(voltdm, bootup_volt); | ||
213 | return 0; | ||
214 | |||
215 | exit: | ||
216 | printk(KERN_ERR "%s: Unable to put vdd_%s to its init voltage\n\n", | ||
217 | __func__, vdd_name); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | static void __init omap3_init_voltages(void) | ||
222 | { | ||
223 | if (!cpu_is_omap34xx()) | ||
224 | return; | ||
225 | |||
226 | omap2_set_init_voltage("mpu", "dpll1_ck", mpu_dev); | ||
227 | omap2_set_init_voltage("core", "l3_ick", l3_dev); | ||
228 | } | ||
229 | |||
230 | static void __init omap4_init_voltages(void) | ||
231 | { | ||
232 | if (!cpu_is_omap44xx()) | ||
233 | return; | ||
234 | |||
235 | omap2_set_init_voltage("mpu", "dpll_mpu_ck", mpu_dev); | ||
236 | omap2_set_init_voltage("core", "l3_div_ck", l3_dev); | ||
237 | omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", iva_dev); | ||
238 | } | ||
239 | |||
139 | static int __init omap2_common_pm_init(void) | 240 | static int __init omap2_common_pm_init(void) |
140 | { | 241 | { |
141 | omap2_init_processor_devices(); | 242 | omap2_init_processor_devices(); |
@@ -143,5 +244,24 @@ static int __init omap2_common_pm_init(void) | |||
143 | 244 | ||
144 | return 0; | 245 | return 0; |
145 | } | 246 | } |
146 | device_initcall(omap2_common_pm_init); | 247 | postcore_initcall(omap2_common_pm_init); |
248 | |||
249 | static int __init omap2_common_pm_late_init(void) | ||
250 | { | ||
251 | /* Init the OMAP TWL parameters */ | ||
252 | omap3_twl_init(); | ||
253 | omap4_twl_init(); | ||
254 | |||
255 | /* Init the voltage layer */ | ||
256 | omap_voltage_late_init(); | ||
147 | 257 | ||
258 | /* Initialize the voltages */ | ||
259 | omap3_init_voltages(); | ||
260 | omap4_init_voltages(); | ||
261 | |||
262 | /* Smartreflex device init */ | ||
263 | omap_devinit_smartreflex(); | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | late_initcall(omap2_common_pm_late_init); | ||