diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 13:58:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 13:58:20 -0500 |
commit | a11da7df6543b5f71a150b47c0d08ecf0799a0f3 (patch) | |
tree | 77eaac99426f64a0a8dc3b5d62c86138a8c72d43 /arch/arm/mach-omap2/vc.c | |
parent | b8edf848e9119bab9d999b9ca80d8520641810f2 (diff) | |
parent | 9c7466b217af784280d9fc841bbd559ef3bf33e9 (diff) |
Merge tag 'pm-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC power management and clock changes from Olof Johansson:
"This branch contains a largeish set of updates of power management and
clock setup. The bulk of it is for OMAP/AM33xx platforms, but also a
few around hotplug/suspend/resume on Exynos.
It includes a split-up of some of the OMAP clock data into separate
files which adds to the diffstat, but gross delta is fairly reasonable."
* tag 'pm-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (60 commits)
ARM: OMAP: Move plat-omap/dma-omap.h to include/linux/omap-dma.h
ASoC: OMAP: mcbsp fixes for enabling ARM multiplatform support
watchdog: OMAP: fixup for ARM multiplatform support
ARM: EXYNOS: Add flush_cache_all in suspend finisher
ARM: EXYNOS: Remove scu_enable from cpuidle
ARM: EXYNOS: Fix soft reboot hang after suspend/resume
ARM: EXYNOS: Add support for rtc wakeup
ARM: EXYNOS: fix the hotplug for Cortex-A15
ARM: OMAP2+: omap_device: Correct resource handling for DT boot
ARM: OMAP2+: hwmod: Add possibility to count hwmod resources based on type
ARM: OMAP2+: hwmod: Add support for per hwmod/module context lost count
ARM: OMAP2+: PRM: initialize some PRM functions early
ARM: OMAP2+: voltage: fixup oscillator handling when CONFIG_PM=n
ARM: OMAP4: USB: power down MUSB PHY during boot
ARM: OMAP2+: clock: Cleanup !CONFIG_COMMON_CLK parts
ARM: OMAP2xxx: clock: drop obsolete clock data
ARM: OMAP2: clock: Cleanup !CONFIG_COMMON_CLK parts
ARM: OMAP3+: DPLL: drop !CONFIG_COMMON_CLK sections
ARM: AM33xx: clock: drop obsolete clock data
ARM: OMAP3xxx: clk: drop obsolete clock data
...
Diffstat (limited to 'arch/arm/mach-omap2/vc.c')
-rw-r--r-- | arch/arm/mach-omap2/vc.c | 453 |
1 files changed, 424 insertions, 29 deletions
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 75878c37959b..49ac7977e03e 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c | |||
@@ -11,13 +11,20 @@ | |||
11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/bug.h> | 13 | #include <linux/bug.h> |
14 | #include <linux/io.h> | ||
14 | 15 | ||
16 | #include <asm/div64.h> | ||
17 | |||
18 | #include "iomap.h" | ||
15 | #include "soc.h" | 19 | #include "soc.h" |
16 | #include "voltage.h" | 20 | #include "voltage.h" |
17 | #include "vc.h" | 21 | #include "vc.h" |
18 | #include "prm-regbits-34xx.h" | 22 | #include "prm-regbits-34xx.h" |
19 | #include "prm-regbits-44xx.h" | 23 | #include "prm-regbits-44xx.h" |
20 | #include "prm44xx.h" | 24 | #include "prm44xx.h" |
25 | #include "pm.h" | ||
26 | #include "scrm44xx.h" | ||
27 | #include "control.h" | ||
21 | 28 | ||
22 | /** | 29 | /** |
23 | * struct omap_vc_channel_cfg - describe the cfg_channel bitfield | 30 | * struct omap_vc_channel_cfg - describe the cfg_channel bitfield |
@@ -63,6 +70,9 @@ static struct omap_vc_channel_cfg vc_mutant_channel_cfg = { | |||
63 | }; | 70 | }; |
64 | 71 | ||
65 | static struct omap_vc_channel_cfg *vc_cfg_bits; | 72 | static struct omap_vc_channel_cfg *vc_cfg_bits; |
73 | |||
74 | /* Default I2C trace length on pcb, 6.3cm. Used for capacitance calculations. */ | ||
75 | static u32 sr_i2c_pcb_length = 63; | ||
66 | #define CFG_CHANNEL_MASK 0x1f | 76 | #define CFG_CHANNEL_MASK 0x1f |
67 | 77 | ||
68 | /** | 78 | /** |
@@ -135,6 +145,8 @@ int omap_vc_pre_scale(struct voltagedomain *voltdm, | |||
135 | vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); | 145 | vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); |
136 | voltdm->write(vc_cmdval, vc->cmdval_reg); | 146 | voltdm->write(vc_cmdval, vc->cmdval_reg); |
137 | 147 | ||
148 | voltdm->vc_param->on = target_volt; | ||
149 | |||
138 | omap_vp_update_errorgain(voltdm, target_volt); | 150 | omap_vp_update_errorgain(voltdm, target_volt); |
139 | 151 | ||
140 | return 0; | 152 | return 0; |
@@ -202,46 +214,389 @@ int omap_vc_bypass_scale(struct voltagedomain *voltdm, | |||
202 | return 0; | 214 | return 0; |
203 | } | 215 | } |
204 | 216 | ||
205 | static void __init omap3_vfsm_init(struct voltagedomain *voltdm) | 217 | /* Convert microsecond value to number of 32kHz clock cycles */ |
218 | static inline u32 omap_usec_to_32k(u32 usec) | ||
219 | { | ||
220 | return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); | ||
221 | } | ||
222 | |||
223 | /* Set oscillator setup time for omap3 */ | ||
224 | static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm) | ||
225 | { | ||
226 | voltdm->write(omap_usec_to_32k(usec), OMAP3_PRM_CLKSETUP_OFFSET); | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * omap3_set_i2c_timings - sets i2c sleep timings for a channel | ||
231 | * @voltdm: channel to configure | ||
232 | * @off_mode: select whether retention or off mode values used | ||
233 | * | ||
234 | * Calculates and sets up voltage controller to use I2C based | ||
235 | * voltage scaling for sleep modes. This can be used for either off mode | ||
236 | * or retention. Off mode has additionally an option to use sys_off_mode | ||
237 | * pad, which uses a global signal to program the whole power IC to | ||
238 | * off-mode. | ||
239 | */ | ||
240 | static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) | ||
206 | { | 241 | { |
242 | unsigned long voltsetup1; | ||
243 | u32 tgt_volt; | ||
244 | |||
245 | /* | ||
246 | * Oscillator is shut down only if we are using sys_off_mode pad, | ||
247 | * thus we set a minimal setup time here | ||
248 | */ | ||
249 | omap3_set_clksetup(1, voltdm); | ||
250 | |||
251 | if (off_mode) | ||
252 | tgt_volt = voltdm->vc_param->off; | ||
253 | else | ||
254 | tgt_volt = voltdm->vc_param->ret; | ||
255 | |||
256 | voltsetup1 = (voltdm->vc_param->on - tgt_volt) / | ||
257 | voltdm->pmic->slew_rate; | ||
258 | |||
259 | voltsetup1 = voltsetup1 * voltdm->sys_clk.rate / 8 / 1000000 + 1; | ||
260 | |||
261 | voltdm->rmw(voltdm->vfsm->voltsetup_mask, | ||
262 | voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask), | ||
263 | voltdm->vfsm->voltsetup_reg); | ||
264 | |||
207 | /* | 265 | /* |
208 | * Voltage Manager FSM parameters init | 266 | * pmic is not controlling the voltage scaling during retention, |
209 | * XXX This data should be passed in from the board file | 267 | * thus set voltsetup2 to 0 |
210 | */ | 268 | */ |
211 | voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET); | 269 | voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET); |
212 | voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET); | ||
213 | voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET); | ||
214 | } | 270 | } |
215 | 271 | ||
216 | static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) | 272 | /** |
273 | * omap3_set_off_timings - sets off-mode timings for a channel | ||
274 | * @voltdm: channel to configure | ||
275 | * | ||
276 | * Calculates and sets up off-mode timings for a channel. Off-mode | ||
277 | * can use either I2C based voltage scaling, or alternatively | ||
278 | * sys_off_mode pad can be used to send a global command to power IC. | ||
279 | * This function first checks which mode is being used, and calls | ||
280 | * omap3_set_i2c_timings() if the system is using I2C control mode. | ||
281 | * sys_off_mode has the additional benefit that voltages can be | ||
282 | * scaled to zero volt level with TWL4030 / TWL5030, I2C can only | ||
283 | * scale to 600mV. | ||
284 | */ | ||
285 | static void omap3_set_off_timings(struct voltagedomain *voltdm) | ||
217 | { | 286 | { |
218 | static bool is_initialized; | 287 | unsigned long clksetup; |
288 | unsigned long voltsetup2; | ||
289 | unsigned long voltsetup2_old; | ||
290 | u32 val; | ||
291 | u32 tstart, tshut; | ||
219 | 292 | ||
220 | if (is_initialized) | 293 | /* check if sys_off_mode is used to control off-mode voltages */ |
294 | val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); | ||
295 | if (!(val & OMAP3430_SEL_OFF_MASK)) { | ||
296 | /* No, omap is controlling them over I2C */ | ||
297 | omap3_set_i2c_timings(voltdm, true); | ||
221 | return; | 298 | return; |
299 | } | ||
300 | |||
301 | omap_pm_get_oscillator(&tstart, &tshut); | ||
302 | omap3_set_clksetup(tstart, voltdm); | ||
303 | |||
304 | clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET); | ||
305 | |||
306 | /* voltsetup 2 in us */ | ||
307 | voltsetup2 = voltdm->vc_param->on / voltdm->pmic->slew_rate; | ||
308 | |||
309 | /* convert to 32k clk cycles */ | ||
310 | voltsetup2 = DIV_ROUND_UP(voltsetup2 * 32768, 1000000); | ||
311 | |||
312 | voltsetup2_old = voltdm->read(OMAP3_PRM_VOLTSETUP2_OFFSET); | ||
313 | |||
314 | /* | ||
315 | * Update voltsetup2 if higher than current value (needed because | ||
316 | * we have multiple channels with different ramp times), also | ||
317 | * update voltoffset always to value recommended by TRM | ||
318 | */ | ||
319 | if (voltsetup2 > voltsetup2_old) { | ||
320 | voltdm->write(voltsetup2, OMAP3_PRM_VOLTSETUP2_OFFSET); | ||
321 | voltdm->write(clksetup - voltsetup2, | ||
322 | OMAP3_PRM_VOLTOFFSET_OFFSET); | ||
323 | } else | ||
324 | voltdm->write(clksetup - voltsetup2_old, | ||
325 | OMAP3_PRM_VOLTOFFSET_OFFSET); | ||
326 | |||
327 | /* | ||
328 | * omap is not controlling voltage scaling during off-mode, | ||
329 | * thus set voltsetup1 to 0 | ||
330 | */ | ||
331 | voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0, | ||
332 | voltdm->vfsm->voltsetup_reg); | ||
333 | |||
334 | /* voltoffset must be clksetup minus voltsetup2 according to TRM */ | ||
335 | voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET); | ||
336 | } | ||
337 | |||
338 | static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) | ||
339 | { | ||
340 | omap3_set_off_timings(voltdm); | ||
341 | } | ||
342 | |||
343 | /** | ||
344 | * omap4_calc_volt_ramp - calculates voltage ramping delays on omap4 | ||
345 | * @voltdm: channel to calculate values for | ||
346 | * @voltage_diff: voltage difference in microvolts | ||
347 | * | ||
348 | * Calculates voltage ramp prescaler + counter values for a voltage | ||
349 | * difference on omap4. Returns a field value suitable for writing to | ||
350 | * VOLTSETUP register for a channel in following format: | ||
351 | * bits[8:9] prescaler ... bits[0:5] counter. See OMAP4 TRM for reference. | ||
352 | */ | ||
353 | static u32 omap4_calc_volt_ramp(struct voltagedomain *voltdm, u32 voltage_diff) | ||
354 | { | ||
355 | u32 prescaler; | ||
356 | u32 cycles; | ||
357 | u32 time; | ||
358 | |||
359 | time = voltage_diff / voltdm->pmic->slew_rate; | ||
360 | |||
361 | cycles = voltdm->sys_clk.rate / 1000 * time / 1000; | ||
362 | |||
363 | cycles /= 64; | ||
364 | prescaler = 0; | ||
365 | |||
366 | /* shift to next prescaler until no overflow */ | ||
367 | |||
368 | /* scale for div 256 = 64 * 4 */ | ||
369 | if (cycles > 63) { | ||
370 | cycles /= 4; | ||
371 | prescaler++; | ||
372 | } | ||
373 | |||
374 | /* scale for div 512 = 256 * 2 */ | ||
375 | if (cycles > 63) { | ||
376 | cycles /= 2; | ||
377 | prescaler++; | ||
378 | } | ||
379 | |||
380 | /* scale for div 2048 = 512 * 4 */ | ||
381 | if (cycles > 63) { | ||
382 | cycles /= 4; | ||
383 | prescaler++; | ||
384 | } | ||
385 | |||
386 | /* check for overflow => invalid ramp time */ | ||
387 | if (cycles > 63) { | ||
388 | pr_warn("%s: invalid setuptime for vdd_%s\n", __func__, | ||
389 | voltdm->name); | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | cycles++; | ||
222 | 394 | ||
223 | omap3_vfsm_init(voltdm); | 395 | return (prescaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) | |
396 | (cycles << OMAP4430_RAMP_UP_COUNT_SHIFT); | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * omap4_usec_to_val_scrm - convert microsecond value to SCRM module bitfield | ||
401 | * @usec: microseconds | ||
402 | * @shift: number of bits to shift left | ||
403 | * @mask: bitfield mask | ||
404 | * | ||
405 | * Converts microsecond value to OMAP4 SCRM bitfield. Bitfield is | ||
406 | * shifted to requested position, and checked agains the mask value. | ||
407 | * If larger, forced to the max value of the field (i.e. the mask itself.) | ||
408 | * Returns the SCRM bitfield value. | ||
409 | */ | ||
410 | static u32 omap4_usec_to_val_scrm(u32 usec, int shift, u32 mask) | ||
411 | { | ||
412 | u32 val; | ||
413 | |||
414 | val = omap_usec_to_32k(usec) << shift; | ||
224 | 415 | ||
225 | is_initialized = true; | 416 | /* Check for overflow, if yes, force to max value */ |
417 | if (val > mask) | ||
418 | val = mask; | ||
419 | |||
420 | return val; | ||
226 | } | 421 | } |
227 | 422 | ||
423 | /** | ||
424 | * omap4_set_timings - set voltage ramp timings for a channel | ||
425 | * @voltdm: channel to configure | ||
426 | * @off_mode: whether off-mode values are used | ||
427 | * | ||
428 | * Calculates and sets the voltage ramp up / down values for a channel. | ||
429 | */ | ||
430 | static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) | ||
431 | { | ||
432 | u32 val; | ||
433 | u32 ramp; | ||
434 | int offset; | ||
435 | u32 tstart, tshut; | ||
436 | |||
437 | if (off_mode) { | ||
438 | ramp = omap4_calc_volt_ramp(voltdm, | ||
439 | voltdm->vc_param->on - voltdm->vc_param->off); | ||
440 | offset = voltdm->vfsm->voltsetup_off_reg; | ||
441 | } else { | ||
442 | ramp = omap4_calc_volt_ramp(voltdm, | ||
443 | voltdm->vc_param->on - voltdm->vc_param->ret); | ||
444 | offset = voltdm->vfsm->voltsetup_reg; | ||
445 | } | ||
446 | |||
447 | if (!ramp) | ||
448 | return; | ||
449 | |||
450 | val = voltdm->read(offset); | ||
451 | |||
452 | val |= ramp << OMAP4430_RAMP_DOWN_COUNT_SHIFT; | ||
453 | |||
454 | val |= ramp << OMAP4430_RAMP_UP_COUNT_SHIFT; | ||
455 | |||
456 | voltdm->write(val, offset); | ||
457 | |||
458 | omap_pm_get_oscillator(&tstart, &tshut); | ||
459 | |||
460 | val = omap4_usec_to_val_scrm(tstart, OMAP4_SETUPTIME_SHIFT, | ||
461 | OMAP4_SETUPTIME_MASK); | ||
462 | val |= omap4_usec_to_val_scrm(tshut, OMAP4_DOWNTIME_SHIFT, | ||
463 | OMAP4_DOWNTIME_MASK); | ||
464 | |||
465 | __raw_writel(val, OMAP4_SCRM_CLKSETUPTIME); | ||
466 | } | ||
228 | 467 | ||
229 | /* OMAP4 specific voltage init functions */ | 468 | /* OMAP4 specific voltage init functions */ |
230 | static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) | 469 | static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) |
231 | { | 470 | { |
232 | static bool is_initialized; | 471 | omap4_set_timings(voltdm, true); |
233 | u32 vc_val; | 472 | omap4_set_timings(voltdm, false); |
473 | } | ||
474 | |||
475 | struct i2c_init_data { | ||
476 | u8 loadbits; | ||
477 | u8 load; | ||
478 | u8 hsscll_38_4; | ||
479 | u8 hsscll_26; | ||
480 | u8 hsscll_19_2; | ||
481 | u8 hsscll_16_8; | ||
482 | u8 hsscll_12; | ||
483 | }; | ||
234 | 484 | ||
235 | if (is_initialized) | 485 | static const __initdata struct i2c_init_data omap4_i2c_timing_data[] = { |
486 | { | ||
487 | .load = 50, | ||
488 | .loadbits = 0x3, | ||
489 | .hsscll_38_4 = 13, | ||
490 | .hsscll_26 = 11, | ||
491 | .hsscll_19_2 = 9, | ||
492 | .hsscll_16_8 = 9, | ||
493 | .hsscll_12 = 8, | ||
494 | }, | ||
495 | { | ||
496 | .load = 25, | ||
497 | .loadbits = 0x2, | ||
498 | .hsscll_38_4 = 13, | ||
499 | .hsscll_26 = 11, | ||
500 | .hsscll_19_2 = 9, | ||
501 | .hsscll_16_8 = 9, | ||
502 | .hsscll_12 = 8, | ||
503 | }, | ||
504 | { | ||
505 | .load = 12, | ||
506 | .loadbits = 0x1, | ||
507 | .hsscll_38_4 = 11, | ||
508 | .hsscll_26 = 10, | ||
509 | .hsscll_19_2 = 9, | ||
510 | .hsscll_16_8 = 9, | ||
511 | .hsscll_12 = 8, | ||
512 | }, | ||
513 | { | ||
514 | .load = 0, | ||
515 | .loadbits = 0x0, | ||
516 | .hsscll_38_4 = 12, | ||
517 | .hsscll_26 = 10, | ||
518 | .hsscll_19_2 = 9, | ||
519 | .hsscll_16_8 = 8, | ||
520 | .hsscll_12 = 8, | ||
521 | }, | ||
522 | }; | ||
523 | |||
524 | /** | ||
525 | * omap4_vc_i2c_timing_init - sets up board I2C timing parameters | ||
526 | * @voltdm: voltagedomain pointer to get data from | ||
527 | * | ||
528 | * Use PMIC + board supplied settings for calculating the total I2C | ||
529 | * channel capacitance and set the timing parameters based on this. | ||
530 | * Pre-calculated values are provided in data tables, as it is not | ||
531 | * too straightforward to calculate these runtime. | ||
532 | */ | ||
533 | static void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm) | ||
534 | { | ||
535 | u32 capacitance; | ||
536 | u32 val; | ||
537 | u16 hsscll; | ||
538 | const struct i2c_init_data *i2c_data; | ||
539 | |||
540 | if (!voltdm->pmic->i2c_high_speed) { | ||
541 | pr_warn("%s: only high speed supported!\n", __func__); | ||
236 | return; | 542 | return; |
543 | } | ||
544 | |||
545 | /* PCB trace capacitance, 0.125pF / mm => mm / 8 */ | ||
546 | capacitance = DIV_ROUND_UP(sr_i2c_pcb_length, 8); | ||
547 | |||
548 | /* OMAP pad capacitance */ | ||
549 | capacitance += 4; | ||
550 | |||
551 | /* PMIC pad capacitance */ | ||
552 | capacitance += voltdm->pmic->i2c_pad_load; | ||
553 | |||
554 | /* Search for capacitance match in the table */ | ||
555 | i2c_data = omap4_i2c_timing_data; | ||
556 | |||
557 | while (i2c_data->load > capacitance) | ||
558 | i2c_data++; | ||
559 | |||
560 | /* Select proper values based on sysclk frequency */ | ||
561 | switch (voltdm->sys_clk.rate) { | ||
562 | case 38400000: | ||
563 | hsscll = i2c_data->hsscll_38_4; | ||
564 | break; | ||
565 | case 26000000: | ||
566 | hsscll = i2c_data->hsscll_26; | ||
567 | break; | ||
568 | case 19200000: | ||
569 | hsscll = i2c_data->hsscll_19_2; | ||
570 | break; | ||
571 | case 16800000: | ||
572 | hsscll = i2c_data->hsscll_16_8; | ||
573 | break; | ||
574 | case 12000000: | ||
575 | hsscll = i2c_data->hsscll_12; | ||
576 | break; | ||
577 | default: | ||
578 | pr_warn("%s: unsupported sysclk rate: %d!\n", __func__, | ||
579 | voltdm->sys_clk.rate); | ||
580 | return; | ||
581 | } | ||
237 | 582 | ||
238 | /* XXX These are magic numbers and do not belong! */ | 583 | /* Loadbits define pull setup for the I2C channels */ |
239 | vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); | 584 | val = i2c_data->loadbits << 25 | i2c_data->loadbits << 29; |
240 | voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); | ||
241 | 585 | ||
242 | is_initialized = true; | 586 | /* Write to SYSCTRL_PADCONF_WKUP_CTRL_I2C_2 to setup I2C pull */ |
587 | __raw_writel(val, OMAP2_L4_IO_ADDRESS(OMAP4_CTRL_MODULE_PAD_WKUP + | ||
588 | OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2)); | ||
589 | |||
590 | /* HSSCLH can always be zero */ | ||
591 | val = hsscll << OMAP4430_HSSCLL_SHIFT; | ||
592 | val |= (0x28 << OMAP4430_SCLL_SHIFT | 0x2c << OMAP4430_SCLH_SHIFT); | ||
593 | |||
594 | /* Write setup times to I2C config register */ | ||
595 | voltdm->write(val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); | ||
243 | } | 596 | } |
244 | 597 | ||
598 | |||
599 | |||
245 | /** | 600 | /** |
246 | * omap_vc_i2c_init - initialize I2C interface to PMIC | 601 | * omap_vc_i2c_init - initialize I2C interface to PMIC |
247 | * @voltdm: voltage domain containing VC data | 602 | * @voltdm: voltage domain containing VC data |
@@ -281,9 +636,51 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) | |||
281 | mcode << __ffs(vc->common->i2c_mcode_mask), | 636 | mcode << __ffs(vc->common->i2c_mcode_mask), |
282 | vc->common->i2c_cfg_reg); | 637 | vc->common->i2c_cfg_reg); |
283 | 638 | ||
639 | if (cpu_is_omap44xx()) | ||
640 | omap4_vc_i2c_timing_init(voltdm); | ||
641 | |||
284 | initialized = true; | 642 | initialized = true; |
285 | } | 643 | } |
286 | 644 | ||
645 | /** | ||
646 | * omap_vc_calc_vsel - calculate vsel value for a channel | ||
647 | * @voltdm: channel to calculate value for | ||
648 | * @uvolt: microvolt value to convert to vsel | ||
649 | * | ||
650 | * Converts a microvolt value to vsel value for the used PMIC. | ||
651 | * This checks whether the microvolt value is out of bounds, and | ||
652 | * adjusts the value accordingly. If unsupported value detected, | ||
653 | * warning is thrown. | ||
654 | */ | ||
655 | static u8 omap_vc_calc_vsel(struct voltagedomain *voltdm, u32 uvolt) | ||
656 | { | ||
657 | if (voltdm->pmic->vddmin > uvolt) | ||
658 | uvolt = voltdm->pmic->vddmin; | ||
659 | if (voltdm->pmic->vddmax < uvolt) { | ||
660 | WARN(1, "%s: voltage not supported by pmic: %u vs max %u\n", | ||
661 | __func__, uvolt, voltdm->pmic->vddmax); | ||
662 | /* Lets try maximum value anyway */ | ||
663 | uvolt = voltdm->pmic->vddmax; | ||
664 | } | ||
665 | |||
666 | return voltdm->pmic->uv_to_vsel(uvolt); | ||
667 | } | ||
668 | |||
669 | #ifdef CONFIG_PM | ||
670 | /** | ||
671 | * omap_pm_setup_sr_i2c_pcb_length - set length of SR I2C traces on PCB | ||
672 | * @mm: length of the PCB trace in millimetres | ||
673 | * | ||
674 | * Sets the PCB trace length for the I2C channel. By default uses 63mm. | ||
675 | * This is needed for properly calculating the capacitance value for | ||
676 | * the PCB trace, and for setting the SR I2C channel timing parameters. | ||
677 | */ | ||
678 | void __init omap_pm_setup_sr_i2c_pcb_length(u32 mm) | ||
679 | { | ||
680 | sr_i2c_pcb_length = mm; | ||
681 | } | ||
682 | #endif | ||
683 | |||
287 | void __init omap_vc_init_channel(struct voltagedomain *voltdm) | 684 | void __init omap_vc_init_channel(struct voltagedomain *voltdm) |
288 | { | 685 | { |
289 | struct omap_vc_channel *vc = voltdm->vc; | 686 | struct omap_vc_channel *vc = voltdm->vc; |
@@ -311,7 +708,6 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) | |||
311 | vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; | 708 | vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; |
312 | vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; | 709 | vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; |
313 | vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; | 710 | vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; |
314 | vc->setup_time = voltdm->pmic->volt_setup_time; | ||
315 | 711 | ||
316 | /* Configure the i2c slave address for this VC */ | 712 | /* Configure the i2c slave address for this VC */ |
317 | voltdm->rmw(vc->smps_sa_mask, | 713 | voltdm->rmw(vc->smps_sa_mask, |
@@ -331,14 +727,18 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) | |||
331 | voltdm->rmw(vc->smps_cmdra_mask, | 727 | voltdm->rmw(vc->smps_cmdra_mask, |
332 | vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), | 728 | vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), |
333 | vc->smps_cmdra_reg); | 729 | vc->smps_cmdra_reg); |
334 | vc->cfg_channel |= vc_cfg_bits->rac | vc_cfg_bits->racen; | 730 | vc->cfg_channel |= vc_cfg_bits->rac; |
335 | } | 731 | } |
336 | 732 | ||
733 | if (vc->cmd_reg_addr == vc->volt_reg_addr) | ||
734 | vc->cfg_channel |= vc_cfg_bits->racen; | ||
735 | |||
337 | /* Set up the on, inactive, retention and off voltage */ | 736 | /* Set up the on, inactive, retention and off voltage */ |
338 | on_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->on_volt); | 737 | on_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->on); |
339 | onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->onlp_volt); | 738 | onlp_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->onlp); |
340 | ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->ret_volt); | 739 | ret_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->ret); |
341 | off_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->off_volt); | 740 | off_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->off); |
741 | |||
342 | val = ((on_vsel << vc->common->cmd_on_shift) | | 742 | val = ((on_vsel << vc->common->cmd_on_shift) | |
343 | (onlp_vsel << vc->common->cmd_onlp_shift) | | 743 | (onlp_vsel << vc->common->cmd_onlp_shift) | |
344 | (ret_vsel << vc->common->cmd_ret_shift) | | 744 | (ret_vsel << vc->common->cmd_ret_shift) | |
@@ -349,11 +749,6 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) | |||
349 | /* Channel configuration */ | 749 | /* Channel configuration */ |
350 | omap_vc_config_channel(voltdm); | 750 | omap_vc_config_channel(voltdm); |
351 | 751 | ||
352 | /* Configure the setup times */ | ||
353 | voltdm->rmw(voltdm->vfsm->voltsetup_mask, | ||
354 | vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask), | ||
355 | voltdm->vfsm->voltsetup_reg); | ||
356 | |||
357 | omap_vc_i2c_init(voltdm); | 752 | omap_vc_i2c_init(voltdm); |
358 | 753 | ||
359 | if (cpu_is_omap34xx()) | 754 | if (cpu_is_omap34xx()) |