aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/pm.c')
-rw-r--r--arch/arm/mach-omap2/pm.c144
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
24static struct omap_device_pm_latency *pm_lats; 27static 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 */
97int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) 103int 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);
135err: 156err:
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 */
168static 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
215exit:
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
221static 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
230static 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
139static int __init omap2_common_pm_init(void) 240static 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}
146device_initcall(omap2_common_pm_init); 247postcore_initcall(omap2_common_pm_init);
248
249static 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}
267late_initcall(omap2_common_pm_late_init);