diff options
author | Olof Johansson <olof@lixom.net> | 2014-05-26 16:24:56 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2014-05-26 16:24:56 -0400 |
commit | 2ca602de42863436cce275dde35c22496344d539 (patch) | |
tree | 9111b81359168bb61767101fb71219a3a6416fd6 /arch/arm/mach-omap2 | |
parent | 98954f4b122c2c5ac03bb3d21fd171a062dc294f (diff) | |
parent | 57b05572267581c2320462e9b606709fa6da4c5a (diff) |
Merge tag 'omap-for-v3.16/pm-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/soc
Merge "ARM: omap pm changes for v3.16 merge window, resend" from Tony Lindgren:
PM related fixes for omap3 that were discovered during omap3
conversion to device tree. This series sets up the PMIC signaling
in a way where we can test for PM regressions easily by
looking at state of the the sys_clkreq and sys_off_mode pins.
Note that this series alone does not make omap3 PM to cut
off core voltage during off-idle, changes to twl4030-power.c
configurations are still needed. Those will be posted
separately.
* tag 'omap-for-v3.16/pm-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
ARM: OMAP2+: Enable CPUidle in omap2plus_defconfig
ARM: dts: Enable N900 keyboard sleep leds by default
ARM: OMAP2+: Fix voltage scaling init for device tree
ARM: dts: Configure omap3 twl4030 I2C4 pins by default
ARM: OMAP3: Fix voltage control for deeper idle states
ARM: OMAP3: Disable broken omap3_set_off_timings function
ARM: OMAP3: Fix idle mode signaling for sys_clkreq and sys_off_mode
ARM: dts: Fix omap serial wake-up when booted with device tree
mfd: twl-core: Fix idle mode signaling for omaps when booted with device tree
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r-- | arch/arm/mach-omap2/omap_twl.c | 60 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 28 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm-regbits-34xx.h | 11 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vc.c | 232 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vc.h | 3 |
6 files changed, 184 insertions, 154 deletions
diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 615e5b1fb025..6bf626700557 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c | |||
@@ -46,15 +46,8 @@ | |||
46 | 46 | ||
47 | static bool is_offset_valid; | 47 | static bool is_offset_valid; |
48 | static u8 smps_offset; | 48 | static u8 smps_offset; |
49 | /* | ||
50 | * Flag to ensure Smartreflex bit in TWL | ||
51 | * being cleared in board file is not overwritten. | ||
52 | */ | ||
53 | static bool __initdata twl_sr_enable_autoinit; | ||
54 | 49 | ||
55 | #define TWL4030_DCDC_GLOBAL_CFG 0x06 | ||
56 | #define REG_SMPS_OFFSET 0xE0 | 50 | #define REG_SMPS_OFFSET 0xE0 |
57 | #define SMARTREFLEX_ENABLE BIT(3) | ||
58 | 51 | ||
59 | static unsigned long twl4030_vsel_to_uv(const u8 vsel) | 52 | static unsigned long twl4030_vsel_to_uv(const u8 vsel) |
60 | { | 53 | { |
@@ -251,18 +244,6 @@ int __init omap3_twl_init(void) | |||
251 | if (!cpu_is_omap34xx()) | 244 | if (!cpu_is_omap34xx()) |
252 | return -ENODEV; | 245 | return -ENODEV; |
253 | 246 | ||
254 | /* | ||
255 | * The smartreflex bit on twl4030 specifies if the setting of voltage | ||
256 | * is done over the I2C_SR path. Since this setting is independent of | ||
257 | * the actual usage of smartreflex AVS module, we enable TWL SR bit | ||
258 | * by default irrespective of whether smartreflex AVS module is enabled | ||
259 | * on the OMAP side or not. This is because without this bit enabled, | ||
260 | * the voltage scaling through vp forceupdate/bypass mechanism of | ||
261 | * voltage scaling will not function on TWL over I2C_SR. | ||
262 | */ | ||
263 | if (!twl_sr_enable_autoinit) | ||
264 | omap3_twl_set_sr_bit(true); | ||
265 | |||
266 | voltdm = voltdm_lookup("mpu_iva"); | 247 | voltdm = voltdm_lookup("mpu_iva"); |
267 | omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic); | 248 | omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic); |
268 | 249 | ||
@@ -271,44 +252,3 @@ int __init omap3_twl_init(void) | |||
271 | 252 | ||
272 | return 0; | 253 | return 0; |
273 | } | 254 | } |
274 | |||
275 | /** | ||
276 | * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL | ||
277 | * @enable: enable SR mode in twl or not | ||
278 | * | ||
279 | * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure | ||
280 | * voltage scaling through OMAP SR works. Else, the smartreflex bit | ||
281 | * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but | ||
282 | * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct | ||
283 | * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages, | ||
284 | * in those scenarios this bit is to be cleared (enable = false). | ||
285 | * | ||
286 | * Returns 0 on success, error is returned if I2C read/write fails. | ||
287 | */ | ||
288 | int __init omap3_twl_set_sr_bit(bool enable) | ||
289 | { | ||
290 | u8 temp; | ||
291 | int ret; | ||
292 | if (twl_sr_enable_autoinit) | ||
293 | pr_warning("%s: unexpected multiple calls\n", __func__); | ||
294 | |||
295 | ret = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, | ||
296 | TWL4030_DCDC_GLOBAL_CFG); | ||
297 | if (ret) | ||
298 | goto err; | ||
299 | |||
300 | if (enable) | ||
301 | temp |= SMARTREFLEX_ENABLE; | ||
302 | else | ||
303 | temp &= ~SMARTREFLEX_ENABLE; | ||
304 | |||
305 | ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, | ||
306 | TWL4030_DCDC_GLOBAL_CFG); | ||
307 | if (!ret) { | ||
308 | twl_sr_enable_autoinit = true; | ||
309 | return 0; | ||
310 | } | ||
311 | err: | ||
312 | pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret); | ||
313 | return ret; | ||
314 | } | ||
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index dd31212d5e20..828aee9ea6a8 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -298,25 +298,21 @@ omap_postcore_initcall(omap2_common_pm_init); | |||
298 | 298 | ||
299 | int __init omap2_common_pm_late_init(void) | 299 | int __init omap2_common_pm_late_init(void) |
300 | { | 300 | { |
301 | /* | 301 | if (of_have_populated_dt()) { |
302 | * In the case of DT, the PMIC and SR initialization will be done using | 302 | omap3_twl_init(); |
303 | * a completely different mechanism. | 303 | omap4_twl_init(); |
304 | * Disable this part if a DT blob is available. | 304 | } |
305 | */ | ||
306 | if (!of_have_populated_dt()) { | ||
307 | |||
308 | /* Init the voltage layer */ | ||
309 | omap_pmic_late_init(); | ||
310 | omap_voltage_late_init(); | ||
311 | 305 | ||
312 | /* Initialize the voltages */ | 306 | /* Init the voltage layer */ |
313 | omap3_init_voltages(); | 307 | omap_pmic_late_init(); |
314 | omap4_init_voltages(); | 308 | omap_voltage_late_init(); |
315 | 309 | ||
316 | /* Smartreflex device init */ | 310 | /* Initialize the voltages */ |
317 | omap_devinit_smartreflex(); | 311 | omap3_init_voltages(); |
312 | omap4_init_voltages(); | ||
318 | 313 | ||
319 | } | 314 | /* Smartreflex device init */ |
315 | omap_devinit_smartreflex(); | ||
320 | 316 | ||
321 | /* cpufreq dummy device instantiation */ | 317 | /* cpufreq dummy device instantiation */ |
322 | omap_init_cpufreq(); | 318 | omap_init_cpufreq(); |
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 90ea2d3ab405..507d8eeaab95 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include "sdrc.h" | 50 | #include "sdrc.h" |
51 | #include "sram.h" | 51 | #include "sram.h" |
52 | #include "control.h" | 52 | #include "control.h" |
53 | #include "vc.h" | ||
53 | 54 | ||
54 | /* pm34xx errata defined in pm.h */ | 55 | /* pm34xx errata defined in pm.h */ |
55 | u16 pm34xx_errata; | 56 | u16 pm34xx_errata; |
@@ -288,6 +289,9 @@ void omap_sram_idle(void) | |||
288 | } | 289 | } |
289 | } | 290 | } |
290 | 291 | ||
292 | /* Configure PMIC signaling for I2C4 or sys_off_mode */ | ||
293 | omap3_vc_set_pmic_signaling(core_next_state); | ||
294 | |||
291 | omap3_intc_prepare_idle(); | 295 | omap3_intc_prepare_idle(); |
292 | 296 | ||
293 | /* | 297 | /* |
diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h index cebad565ed37..106132db532b 100644 --- a/arch/arm/mach-omap2/prm-regbits-34xx.h +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h | |||
@@ -123,8 +123,15 @@ | |||
123 | #define OMAP3430_GLOBAL_SW_RST_SHIFT 1 | 123 | #define OMAP3430_GLOBAL_SW_RST_SHIFT 1 |
124 | #define OMAP3430_GLOBAL_COLD_RST_SHIFT 0 | 124 | #define OMAP3430_GLOBAL_COLD_RST_SHIFT 0 |
125 | #define OMAP3430_GLOBAL_COLD_RST_MASK (1 << 0) | 125 | #define OMAP3430_GLOBAL_COLD_RST_MASK (1 << 0) |
126 | #define OMAP3430_SEL_OFF_MASK (1 << 3) | 126 | #define OMAP3430_PRM_VOLTCTRL_SEL_VMODE (1 << 4) |
127 | #define OMAP3430_AUTO_OFF_MASK (1 << 2) | 127 | #define OMAP3430_PRM_VOLTCTRL_SEL_OFF (1 << 3) |
128 | #define OMAP3430_PRM_VOLTCTRL_AUTO_OFF (1 << 2) | ||
129 | #define OMAP3430_PRM_VOLTCTRL_AUTO_RET (1 << 1) | ||
130 | #define OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP (1 << 0) | ||
128 | #define OMAP3430_SETUP_TIME2_MASK (0xffff << 16) | 131 | #define OMAP3430_SETUP_TIME2_MASK (0xffff << 16) |
129 | #define OMAP3430_SETUP_TIME1_MASK (0xffff << 0) | 132 | #define OMAP3430_SETUP_TIME1_MASK (0xffff << 0) |
133 | #define OMAP3430_PRM_POLCTRL_OFFMODE_POL (1 << 3) | ||
134 | #define OMAP3430_PRM_POLCTRL_CLKOUT_POL (1 << 2) | ||
135 | #define OMAP3430_PRM_POLCTRL_CLKREQ_POL (1 << 1) | ||
136 | #define OMAP3430_PRM_POLCTRL_EXTVOL_POL (1 << 0) | ||
130 | #endif | 137 | #endif |
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 49ac7977e03e..0d1629c5f84e 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c | |||
@@ -220,10 +220,126 @@ static inline u32 omap_usec_to_32k(u32 usec) | |||
220 | return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); | 220 | return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); |
221 | } | 221 | } |
222 | 222 | ||
223 | /* Set oscillator setup time for omap3 */ | 223 | struct omap3_vc_timings { |
224 | static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm) | 224 | u32 voltsetup1; |
225 | u32 voltsetup2; | ||
226 | }; | ||
227 | |||
228 | struct omap3_vc { | ||
229 | struct voltagedomain *vd; | ||
230 | u32 voltctrl; | ||
231 | u32 voltsetup1; | ||
232 | u32 voltsetup2; | ||
233 | struct omap3_vc_timings timings[2]; | ||
234 | }; | ||
235 | static struct omap3_vc vc; | ||
236 | |||
237 | void omap3_vc_set_pmic_signaling(int core_next_state) | ||
238 | { | ||
239 | struct voltagedomain *vd = vc.vd; | ||
240 | struct omap3_vc_timings *c = vc.timings; | ||
241 | u32 voltctrl, voltsetup1, voltsetup2; | ||
242 | |||
243 | voltctrl = vc.voltctrl; | ||
244 | voltsetup1 = vc.voltsetup1; | ||
245 | voltsetup2 = vc.voltsetup2; | ||
246 | |||
247 | switch (core_next_state) { | ||
248 | case PWRDM_POWER_OFF: | ||
249 | voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_RET | | ||
250 | OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); | ||
251 | voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_OFF; | ||
252 | if (voltctrl & OMAP3430_PRM_VOLTCTRL_SEL_OFF) | ||
253 | voltsetup2 = c->voltsetup2; | ||
254 | else | ||
255 | voltsetup1 = c->voltsetup1; | ||
256 | break; | ||
257 | case PWRDM_POWER_RET: | ||
258 | default: | ||
259 | c++; | ||
260 | voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_OFF | | ||
261 | OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); | ||
262 | voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_RET; | ||
263 | voltsetup1 = c->voltsetup1; | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | if (voltctrl != vc.voltctrl) { | ||
268 | vd->write(voltctrl, OMAP3_PRM_VOLTCTRL_OFFSET); | ||
269 | vc.voltctrl = voltctrl; | ||
270 | } | ||
271 | if (voltsetup1 != vc.voltsetup1) { | ||
272 | vd->write(c->voltsetup1, | ||
273 | OMAP3_PRM_VOLTSETUP1_OFFSET); | ||
274 | vc.voltsetup1 = voltsetup1; | ||
275 | } | ||
276 | if (voltsetup2 != vc.voltsetup2) { | ||
277 | vd->write(c->voltsetup2, | ||
278 | OMAP3_PRM_VOLTSETUP2_OFFSET); | ||
279 | vc.voltsetup2 = voltsetup2; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | #define PRM_POLCTRL_TWL_MASK (OMAP3430_PRM_POLCTRL_CLKREQ_POL | \ | ||
284 | OMAP3430_PRM_POLCTRL_CLKREQ_POL) | ||
285 | #define PRM_POLCTRL_TWL_VAL OMAP3430_PRM_POLCTRL_CLKREQ_POL | ||
286 | |||
287 | /* | ||
288 | * Configure signal polarity for sys_clkreq and sys_off_mode pins | ||
289 | * as the default values are wrong and can cause the system to hang | ||
290 | * if any twl4030 scripts are loaded. | ||
291 | */ | ||
292 | static void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm) | ||
293 | { | ||
294 | u32 val; | ||
295 | |||
296 | if (vc.vd) | ||
297 | return; | ||
298 | |||
299 | vc.vd = voltdm; | ||
300 | |||
301 | val = voltdm->read(OMAP3_PRM_POLCTRL_OFFSET); | ||
302 | if (!(val & OMAP3430_PRM_POLCTRL_CLKREQ_POL) || | ||
303 | (val & OMAP3430_PRM_POLCTRL_CLKREQ_POL)) { | ||
304 | val |= OMAP3430_PRM_POLCTRL_CLKREQ_POL; | ||
305 | val &= ~OMAP3430_PRM_POLCTRL_OFFMODE_POL; | ||
306 | pr_debug("PM: fixing sys_clkreq and sys_off_mode polarity to 0x%x\n", | ||
307 | val); | ||
308 | voltdm->write(val, OMAP3_PRM_POLCTRL_OFFSET); | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * By default let's use I2C4 signaling for retention idle | ||
313 | * and sys_off_mode pin signaling for off idle. This way we | ||
314 | * have sys_clk_req pin go down for retention and both | ||
315 | * sys_clk_req and sys_off_mode pins will go down for off | ||
316 | * idle. And we can also scale voltages to zero for off-idle. | ||
317 | * Note that no actual voltage scaling during off-idle will | ||
318 | * happen unless the board specific twl4030 PMIC scripts are | ||
319 | * loaded. | ||
320 | */ | ||
321 | val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); | ||
322 | if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) { | ||
323 | val |= OMAP3430_PRM_VOLTCTRL_SEL_OFF; | ||
324 | pr_debug("PM: setting voltctrl sys_off_mode signaling to 0x%x\n", | ||
325 | val); | ||
326 | voltdm->write(val, OMAP3_PRM_VOLTCTRL_OFFSET); | ||
327 | } | ||
328 | vc.voltctrl = val; | ||
329 | |||
330 | omap3_vc_set_pmic_signaling(PWRDM_POWER_ON); | ||
331 | } | ||
332 | |||
333 | static void omap3_init_voltsetup1(struct voltagedomain *voltdm, | ||
334 | struct omap3_vc_timings *c, u32 idle) | ||
225 | { | 335 | { |
226 | voltdm->write(omap_usec_to_32k(usec), OMAP3_PRM_CLKSETUP_OFFSET); | 336 | unsigned long val; |
337 | |||
338 | val = (voltdm->vc_param->on - idle) / voltdm->pmic->slew_rate; | ||
339 | val *= voltdm->sys_clk.rate / 8 / 1000000 + 1; | ||
340 | val <<= __ffs(voltdm->vfsm->voltsetup_mask); | ||
341 | c->voltsetup1 &= ~voltdm->vfsm->voltsetup_mask; | ||
342 | c->voltsetup1 |= val; | ||
227 | } | 343 | } |
228 | 344 | ||
229 | /** | 345 | /** |
@@ -236,37 +352,21 @@ static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm) | |||
236 | * or retention. Off mode has additionally an option to use sys_off_mode | 352 | * 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 | 353 | * pad, which uses a global signal to program the whole power IC to |
238 | * off-mode. | 354 | * off-mode. |
355 | * | ||
356 | * Note that pmic is not controlling the voltage scaling during | ||
357 | * retention signaled over I2C4, so we can keep voltsetup2 as 0. | ||
358 | * And the oscillator is not shut off over I2C4, so no need to | ||
359 | * set clksetup. | ||
239 | */ | 360 | */ |
240 | static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) | 361 | static void omap3_set_i2c_timings(struct voltagedomain *voltdm) |
241 | { | 362 | { |
242 | unsigned long voltsetup1; | 363 | struct omap3_vc_timings *c = vc.timings; |
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 | 364 | ||
251 | if (off_mode) | 365 | /* Configure PRWDM_POWER_OFF over I2C4 */ |
252 | tgt_volt = voltdm->vc_param->off; | 366 | omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->off); |
253 | else | 367 | c++; |
254 | tgt_volt = voltdm->vc_param->ret; | 368 | /* Configure PRWDM_POWER_RET over I2C4 */ |
255 | 369 | omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->ret); | |
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 | |||
265 | /* | ||
266 | * pmic is not controlling the voltage scaling during retention, | ||
267 | * thus set voltsetup2 to 0 | ||
268 | */ | ||
269 | voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET); | ||
270 | } | 370 | } |
271 | 371 | ||
272 | /** | 372 | /** |
@@ -275,69 +375,49 @@ static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) | |||
275 | * | 375 | * |
276 | * Calculates and sets up off-mode timings for a channel. Off-mode | 376 | * Calculates and sets up off-mode timings for a channel. Off-mode |
277 | * can use either I2C based voltage scaling, or alternatively | 377 | * 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. | 378 | * sys_off_mode pad can be used to send a global command to power IC.n, |
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 | 379 | * sys_off_mode has the additional benefit that voltages can be |
282 | * scaled to zero volt level with TWL4030 / TWL5030, I2C can only | 380 | * scaled to zero volt level with TWL4030 / TWL5030, I2C can only |
283 | * scale to 600mV. | 381 | * scale to 600mV. |
382 | * | ||
383 | * Note that omap is not controlling the voltage scaling during | ||
384 | * off idle signaled by sys_off_mode, so we can keep voltsetup1 | ||
385 | * as 0. | ||
284 | */ | 386 | */ |
285 | static void omap3_set_off_timings(struct voltagedomain *voltdm) | 387 | static void omap3_set_off_timings(struct voltagedomain *voltdm) |
286 | { | 388 | { |
287 | unsigned long clksetup; | 389 | struct omap3_vc_timings *c = vc.timings; |
288 | unsigned long voltsetup2; | 390 | u32 tstart, tshut, clksetup, voltoffset; |
289 | unsigned long voltsetup2_old; | ||
290 | u32 val; | ||
291 | u32 tstart, tshut; | ||
292 | 391 | ||
293 | /* check if sys_off_mode is used to control off-mode voltages */ | 392 | if (c->voltsetup2) |
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); | ||
298 | return; | 393 | return; |
299 | } | ||
300 | 394 | ||
301 | omap_pm_get_oscillator(&tstart, &tshut); | 395 | omap_pm_get_oscillator(&tstart, &tshut); |
302 | omap3_set_clksetup(tstart, voltdm); | 396 | if (tstart == ULONG_MAX) { |
303 | 397 | pr_debug("PM: oscillator start-up time not initialized, using 10ms\n"); | |
304 | clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET); | 398 | clksetup = omap_usec_to_32k(10000); |
305 | 399 | } else { | |
306 | /* voltsetup 2 in us */ | 400 | clksetup = omap_usec_to_32k(tstart); |
307 | voltsetup2 = voltdm->vc_param->on / voltdm->pmic->slew_rate; | 401 | } |
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 | 402 | ||
327 | /* | 403 | /* |
328 | * omap is not controlling voltage scaling during off-mode, | 404 | * For twl4030 errata 27, we need to allow minimum ~488.32 us wait to |
329 | * thus set voltsetup1 to 0 | 405 | * switch from HFCLKIN to internal oscillator. That means timings |
406 | * have voltoffset fixed to 0xa in rounded up 32 KiHz cycles. And | ||
407 | * that means we can calculate the value based on the oscillator | ||
408 | * start-up time since voltoffset2 = clksetup - voltoffset. | ||
330 | */ | 409 | */ |
331 | voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0, | 410 | voltoffset = omap_usec_to_32k(488); |
332 | voltdm->vfsm->voltsetup_reg); | 411 | c->voltsetup2 = clksetup - voltoffset; |
333 | 412 | voltdm->write(clksetup, OMAP3_PRM_CLKSETUP_OFFSET); | |
334 | /* voltoffset must be clksetup minus voltsetup2 according to TRM */ | 413 | voltdm->write(voltoffset, OMAP3_PRM_VOLTOFFSET_OFFSET); |
335 | voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET); | ||
336 | } | 414 | } |
337 | 415 | ||
338 | static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) | 416 | static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) |
339 | { | 417 | { |
418 | omap3_vc_init_pmic_signaling(voltdm); | ||
340 | omap3_set_off_timings(voltdm); | 419 | omap3_set_off_timings(voltdm); |
420 | omap3_set_i2c_timings(voltdm); | ||
341 | } | 421 | } |
342 | 422 | ||
343 | /** | 423 | /** |
diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index 91c8d75bf2ea..cdbdd78e755e 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h | |||
@@ -117,6 +117,9 @@ extern struct omap_vc_param omap4_mpu_vc_data; | |||
117 | extern struct omap_vc_param omap4_iva_vc_data; | 117 | extern struct omap_vc_param omap4_iva_vc_data; |
118 | extern struct omap_vc_param omap4_core_vc_data; | 118 | extern struct omap_vc_param omap4_core_vc_data; |
119 | 119 | ||
120 | void omap3_vc_set_pmic_signaling(int core_next_state); | ||
121 | |||
122 | |||
120 | void omap_vc_init_channel(struct voltagedomain *voltdm); | 123 | void omap_vc_init_channel(struct voltagedomain *voltdm); |
121 | int omap_vc_pre_scale(struct voltagedomain *voltdm, | 124 | int omap_vc_pre_scale(struct voltagedomain *voltdm, |
122 | unsigned long target_volt, | 125 | unsigned long target_volt, |