diff options
-rw-r--r-- | arch/arm/mach-omap2/vc.c | 108 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vc.h | 1 |
2 files changed, 91 insertions, 18 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 | ||
207 | static 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 | */ | ||
218 | static 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 | ||
218 | static 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 | */ | ||
257 | static 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 | ||
306 | static 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 */ |
232 | static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) | 312 | static 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()) |
diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index 7618b69811d0..91c8d75bf2ea 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h | |||
@@ -86,7 +86,6 @@ struct omap_vc_channel { | |||
86 | u16 i2c_slave_addr; | 86 | u16 i2c_slave_addr; |
87 | u16 volt_reg_addr; | 87 | u16 volt_reg_addr; |
88 | u16 cmd_reg_addr; | 88 | u16 cmd_reg_addr; |
89 | u16 setup_time; | ||
90 | u8 cfg_channel; | 89 | u8 cfg_channel; |
91 | bool i2c_high_speed; | 90 | bool i2c_high_speed; |
92 | 91 | ||