aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/vc.c
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2012-09-25 12:33:36 -0400
committerKevin Hilman <khilman@ti.com>2012-11-05 18:08:23 -0500
commitc589eb3869a8ad6185669f5477bf72d6d46068de (patch)
treea36d476657fe2e3654c1a288e819eedd19bba548 /arch/arm/mach-omap2/vc.c
parent8b5d8c0d718379ce29dad74b4bda8b669fc1f1c2 (diff)
ARM: OMAP3: VC: calculate ramp times
OMAP3 VC code now uses voltage deltas + slew rates for calculating actual ramp times for voltage changes. Previously a static value was used. Two calculation methods are provided: i2c_timings and off_timings. I2C timings are used during retention or off mode transition which is initiated over I2C, and OFF timings are used if PMIC signal (nsleep) is used to control all the off mode voltages at the same time. Signed-off-by: Tero Kristo <t-kristo@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/vc.c')
-rw-r--r--arch/arm/mach-omap2/vc.c108
1 files changed, 91 insertions, 17 deletions
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index 4c3c41fd2637..73b4bcd67023 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -204,29 +204,109 @@ int omap_vc_bypass_scale(struct voltagedomain *voltdm,
204 return 0; 204 return 0;
205} 205}
206 206
207static void __init omap3_vfsm_init(struct voltagedomain *voltdm) 207/**
208 * omap3_set_i2c_timings - sets i2c sleep timings for a channel
209 * @voltdm: channel to configure
210 * @off_mode: select whether retention or off mode values used
211 *
212 * Calculates and sets up voltage controller to use I2C based
213 * voltage scaling for sleep modes. This can be used for either off mode
214 * or retention. Off mode has additionally an option to use sys_off_mode
215 * pad, which uses a global signal to program the whole power IC to
216 * off-mode.
217 */
218static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode)
208{ 219{
220 unsigned long voltsetup1;
221 u32 tgt_volt;
222
223 if (off_mode)
224 tgt_volt = voltdm->vc_param->off;
225 else
226 tgt_volt = voltdm->vc_param->ret;
227
228 voltsetup1 = (voltdm->vc_param->on - tgt_volt) /
229 voltdm->pmic->slew_rate;
230
231 voltsetup1 = voltsetup1 * voltdm->sys_clk.rate / 8 / 1000000 + 1;
232
233 voltdm->rmw(voltdm->vfsm->voltsetup_mask,
234 voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask),
235 voltdm->vfsm->voltsetup_reg);
236
209 /* 237 /*
210 * Voltage Manager FSM parameters init 238 * pmic is not controlling the voltage scaling during retention,
211 * XXX This data should be passed in from the board file 239 * thus set voltsetup2 to 0
212 */ 240 */
213 voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET); 241 voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET);
214 voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET);
215 voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET);
216} 242}
217 243
218static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) 244/**
245 * omap3_set_off_timings - sets off-mode timings for a channel
246 * @voltdm: channel to configure
247 *
248 * Calculates and sets up off-mode timings for a channel. Off-mode
249 * can use either I2C based voltage scaling, or alternatively
250 * sys_off_mode pad can be used to send a global command to power IC.
251 * This function first checks which mode is being used, and calls
252 * omap3_set_i2c_timings() if the system is using I2C control mode.
253 * sys_off_mode has the additional benefit that voltages can be
254 * scaled to zero volt level with TWL4030 / TWL5030, I2C can only
255 * scale to 600mV.
256 */
257static void omap3_set_off_timings(struct voltagedomain *voltdm)
219{ 258{
220 static bool is_initialized; 259 unsigned long clksetup;
260 unsigned long voltsetup2;
261 unsigned long voltsetup2_old;
262 u32 val;
221 263
222 if (is_initialized) 264 /* check if sys_off_mode is used to control off-mode voltages */
265 val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET);
266 if (!(val & OMAP3430_SEL_OFF_MASK)) {
267 /* No, omap is controlling them over I2C */
268 omap3_set_i2c_timings(voltdm, true);
223 return; 269 return;
270 }
224 271
225 omap3_vfsm_init(voltdm); 272 clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET);
226 273
227 is_initialized = true; 274 /* voltsetup 2 in us */
275 voltsetup2 = voltdm->vc_param->on / voltdm->pmic->slew_rate;
276
277 /* convert to 32k clk cycles */
278 voltsetup2 = DIV_ROUND_UP(voltsetup2 * 32768, 1000000);
279
280 voltsetup2_old = voltdm->read(OMAP3_PRM_VOLTSETUP2_OFFSET);
281
282 /*
283 * Update voltsetup2 if higher than current value (needed because
284 * we have multiple channels with different ramp times), also
285 * update voltoffset always to value recommended by TRM
286 */
287 if (voltsetup2 > voltsetup2_old) {
288 voltdm->write(voltsetup2, OMAP3_PRM_VOLTSETUP2_OFFSET);
289 voltdm->write(clksetup - voltsetup2,
290 OMAP3_PRM_VOLTOFFSET_OFFSET);
291 } else
292 voltdm->write(clksetup - voltsetup2_old,
293 OMAP3_PRM_VOLTOFFSET_OFFSET);
294
295 /*
296 * omap is not controlling voltage scaling during off-mode,
297 * thus set voltsetup1 to 0
298 */
299 voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0,
300 voltdm->vfsm->voltsetup_reg);
301
302 /* voltoffset must be clksetup minus voltsetup2 according to TRM */
303 voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET);
228} 304}
229 305
306static void __init omap3_vc_init_channel(struct voltagedomain *voltdm)
307{
308 omap3_set_off_timings(voltdm);
309}
230 310
231/* OMAP4 specific voltage init functions */ 311/* OMAP4 specific voltage init functions */
232static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) 312static void __init omap4_vc_init_channel(struct voltagedomain *voltdm)
@@ -337,7 +417,6 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm)
337 vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; 417 vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr;
338 vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; 418 vc->volt_reg_addr = voltdm->pmic->volt_reg_addr;
339 vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; 419 vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr;
340 vc->setup_time = voltdm->pmic->volt_setup_time;
341 420
342 /* Configure the i2c slave address for this VC */ 421 /* Configure the i2c slave address for this VC */
343 voltdm->rmw(vc->smps_sa_mask, 422 voltdm->rmw(vc->smps_sa_mask,
@@ -376,11 +455,6 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm)
376 /* Channel configuration */ 455 /* Channel configuration */
377 omap_vc_config_channel(voltdm); 456 omap_vc_config_channel(voltdm);
378 457
379 /* Configure the setup times */
380 voltdm->rmw(voltdm->vfsm->voltsetup_mask,
381 vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask),
382 voltdm->vfsm->voltsetup_reg);
383
384 omap_vc_i2c_init(voltdm); 458 omap_vc_i2c_init(voltdm);
385 459
386 if (cpu_is_omap34xx()) 460 if (cpu_is_omap34xx())