aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>2014-03-04 16:31:59 -0500
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:02 -0400
commitfa82e467da1c2e44d0a80b57be6e9ff5ed8746cd (patch)
tree33b86cfe53237cc7b14232b9e90531ccfc4e074a
parent706e6b4cd46aea01d0fbb1f5ba2c19a5f5e035a7 (diff)
ENGR00299939-2 ARM: imx6sl: Add dummy LDO2p5 regulator to support VBUS wakeup
LDO2p5 cannot be disabled in low power idle mode when the USB driver enables VBUS wakeup. To identify when LDO2p5 can be disabled add a dummy regulator that the USB driver will enable when VBUS wakeup is required. This patch ensures that the low power idle code checks the status of the dummy ldo2p5 regulator before disabling LDO2p5. Signed-off-by: Ranjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sl.c90
-rw-r--r--arch/arm/mach-imx/imx6sl_wfi.S49
2 files changed, 118 insertions, 21 deletions
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
index d0c8fccf450f..cd4e1fda4e35 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sl.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -12,6 +12,9 @@
12#include <linux/of.h> 12#include <linux/of.h>
13#include <linux/of_address.h> 13#include <linux/of_address.h>
14#include <linux/of_device.h> 14#include <linux/of_device.h>
15#include <linux/regulator/consumer.h>
16#include <linux/regulator/driver.h>
17#include <linux/regulator/machine.h>
15#include <asm/cpuidle.h> 18#include <asm/cpuidle.h>
16#include <asm/fncpy.h> 19#include <asm/fncpy.h>
17#include <asm/mach/map.h> 20#include <asm/mach/map.h>
@@ -33,9 +36,18 @@ extern unsigned long iram_tlb_phys_addr;
33 36
34static void __iomem *iomux_base; 37static void __iomem *iomux_base;
35static void *wfi_iram_base; 38static void *wfi_iram_base;
39static struct regulator *vbus_ldo;
40
41static struct regulator_dev *ldo2p5_dummy_regulator_rdev;
42static struct regulator_init_data ldo2p5_dummy_initdata = {
43 .constraints = {
44 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
45 },
46};
47static int ldo2p5_dummy_enable;
36 48
37void (*imx6sl_wfi_in_iram_fn)(void *wfi_iram_base, 49void (*imx6sl_wfi_in_iram_fn)(void *wfi_iram_base,
38 void *iomux_addr, u32 audio_mode) = NULL; 50 bool vbus_ldo, u32 audio_mode) = NULL;
39 51
40 52
41static int imx6sl_enter_wait(struct cpuidle_device *dev, 53static int imx6sl_enter_wait(struct cpuidle_device *dev,
@@ -50,7 +62,7 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev,
50 * Also float DDR IO pads. 62 * Also float DDR IO pads.
51 */ 63 */
52 ttbr1 = save_ttbr1(); 64 ttbr1 = save_ttbr1();
53 imx6sl_wfi_in_iram_fn(wfi_iram_base, iomux_base, 65 imx6sl_wfi_in_iram_fn(wfi_iram_base, regulator_is_enabled(vbus_ldo),
54 audio_bus_freq_mode); 66 audio_bus_freq_mode);
55 restore_ttbr1(ttbr1); 67 restore_ttbr1(ttbr1);
56 } else { 68 } else {
@@ -96,6 +108,10 @@ int __init imx6sl_cpuidle_init(void)
96 iomux_base = of_iomap(node, 0); 108 iomux_base = of_iomap(node, 0);
97 WARN(!iomux_base, "unable to map iomux registers\n"); 109 WARN(!iomux_base, "unable to map iomux registers\n");
98 110
111 vbus_ldo = regulator_get(NULL, "ldo2p5-dummy");
112 if (IS_ERR(vbus_ldo))
113 vbus_ldo = NULL;
114
99 /* Calculate the virtual address of the code */ 115 /* Calculate the virtual address of the code */
100 wfi_iram_base = (void *)IMX_IO_P2V(iram_tlb_phys_addr) + 116 wfi_iram_base = (void *)IMX_IO_P2V(iram_tlb_phys_addr) +
101 MX6SL_WFI_IRAM_ADDR_OFFSET; 117 MX6SL_WFI_IRAM_ADDR_OFFSET;
@@ -105,3 +121,73 @@ int __init imx6sl_cpuidle_init(void)
105 121
106 return cpuidle_register(&imx6sl_cpuidle_driver, NULL); 122 return cpuidle_register(&imx6sl_cpuidle_driver, NULL);
107} 123}
124
125static int imx_ldo2p5_dummy_enable(struct regulator_dev *rdev)
126{
127 ldo2p5_dummy_enable = 1;
128
129 return 0;
130}
131
132static int imx_ldo2p5_dummy_disable(struct regulator_dev *rdev)
133{
134 ldo2p5_dummy_enable = 0;
135
136 return 0;
137}
138
139static int imx_ldo2p5_dummy_is_enable(struct regulator_dev *rdev)
140{
141 return ldo2p5_dummy_enable;
142}
143
144
145static struct regulator_ops ldo2p5_dummy_ops = {
146 .enable = imx_ldo2p5_dummy_enable,
147 .disable = imx_ldo2p5_dummy_disable,
148 .is_enabled = imx_ldo2p5_dummy_is_enable,
149};
150
151static struct regulator_desc ldo2p5_dummy_desc = {
152 .name = "ldo2p5-dummy",
153 .id = -1,
154 .type = REGULATOR_VOLTAGE,
155 .owner = THIS_MODULE,
156 .ops = &ldo2p5_dummy_ops,
157};
158
159static int ldo2p5_dummy_probe(struct platform_device *pdev)
160{
161 struct regulator_config config = { };
162 int ret;
163
164 config.dev = &pdev->dev;
165 config.init_data = &ldo2p5_dummy_initdata;
166 config.of_node = pdev->dev.of_node;
167
168 ldo2p5_dummy_regulator_rdev = regulator_register(&ldo2p5_dummy_desc, &config);
169 if (IS_ERR(ldo2p5_dummy_regulator_rdev)) {
170 ret = PTR_ERR(ldo2p5_dummy_regulator_rdev);
171 dev_err(&pdev->dev, "Failed to register dummy ldo2p5 regulator: %d\n", ret);
172 return ret;
173 }
174
175 return 0;
176}
177
178static const struct of_device_id imx_ldo2p5_dummy_ids[] = {
179 { .compatible = "fsl,imx6-dummy-ldo2p5" },
180};
181MODULE_DEVICE_TABLE(of, imx_ldo2p5_dummy_ids);
182
183static struct platform_driver ldo2p5_dummy_driver = {
184 .probe = ldo2p5_dummy_probe,
185 .driver = {
186 .name = "ldo2p5-dummy",
187 .owner = THIS_MODULE,
188 .of_match_table = imx_ldo2p5_dummy_ids,
189 },
190};
191
192module_platform_driver(ldo2p5_dummy_driver);
193
diff --git a/arch/arm/mach-imx/imx6sl_wfi.S b/arch/arm/mach-imx/imx6sl_wfi.S
index 20afe0256f5f..f8556e67631e 100644
--- a/arch/arm/mach-imx/imx6sl_wfi.S
+++ b/arch/arm/mach-imx/imx6sl_wfi.S
@@ -155,15 +155,17 @@ fifo_reset2_wait:
155 * Make sure DDR is in self-refresh. 155 * Make sure DDR is in self-refresh.
156 * IRQs are already disabled. 156 * IRQs are already disabled.
157 * r0: WFI IRAMcode base address. 157 * r0: WFI IRAMcode base address.
158 * r1: IOMUX base address 158 * r1: 1 if vbus_ldo (ldo2p5) cannot be disabled
159 * r2: 1 if in audio_bus_freq_mode 159 * r2: 1 if in audio_bus_freq_mode
160 */ 160 */
161 .align 3 161 .align 3
162ENTRY(imx6sl_low_power_wfi) 162ENTRY(imx6sl_low_power_wfi)
163 163
164 push {r4-r11} 164 push {r4-r12}
165 165
166mx6sl_lpm_wfi: 166mx6sl_lpm_wfi:
167 /* Can LDO2p5 be disabled */
168 mov r12, r1
167 /* Store audio_bus_freq_mode */ 169 /* Store audio_bus_freq_mode */
168 mov r11, r2 170 mov r11, r2
169 171
@@ -402,6 +404,17 @@ podf_loop:
402 bic r6, r6, #0x2 404 bic r6, r6, #0x2
403 str r6, [r3, #0x110] 405 str r6, [r3, #0x110]
404 406
407 /*
408 * Set the OSC bias current to -37.5%
409 * to drop the power on VDDHIGH.
410 */
411 ldr r6, [r3, #0x150]
412 orr r6, r6, #0xC000
413 str r6, [r3, #0x150]
414
415 cmp r12, #0x1
416 beq leave_2p5_on
417
405 /* Enable the weak 2P5 */ 418 /* Enable the weak 2P5 */
406 ldr r6, [r3, #0x130] 419 ldr r6, [r3, #0x130]
407 orr r6, r6, #0x40000 420 orr r6, r6, #0x40000
@@ -412,14 +425,6 @@ podf_loop:
412 bic r6, r6, #0x1 425 bic r6, r6, #0x1
413 str r6, [r3, #0x130] 426 str r6, [r3, #0x130]
414 427
415 /*
416 * Set the OSC bias current to -37.5%
417 * to drop the power on VDDHIGH.
418 */
419 ldr r6, [r3, #0x150]
420 orr r6, r6, #0xC000
421 str r6, [r3, #0x150]
422
423 /* Enable low power bandgap */ 428 /* Enable low power bandgap */
424 ldr r6, [r3, #0x260] 429 ldr r6, [r3, #0x260]
425 orr r6, r6, #0x20 430 orr r6, r6, #0x20
@@ -448,6 +453,7 @@ podf_loop:
448 orr r6, r6, #0x1 453 orr r6, r6, #0x1
449 str r6, [r3, #0x150] 454 str r6, [r3, #0x150]
450 455
456leave_2p5_on:
451 b do_wfi 457 b do_wfi
452 458
453do_audio_arm_clk: 459do_audio_arm_clk:
@@ -497,6 +503,9 @@ podf_loop1:
497 cmp r7, #0x1 503 cmp r7, #0x1
498 bne skip_analog_restore 504 bne skip_analog_restore
499 505
506 cmp r12, #1
507 beq ldo2p5_not_disabled
508
500 /* Power up the regular bandgap. */ 509 /* Power up the regular bandgap. */
501 ldr r6, [r3, #0x150] 510 ldr r6, [r3, #0x150]
502 bic r6, r6, #0x1 511 bic r6, r6, #0x1
@@ -515,14 +524,6 @@ podf_loop1:
515 bic r6, r6, #0x20 524 bic r6, r6, #0x20
516 str r6, [r3, #0x260] 525 str r6, [r3, #0x260]
517 526
518 /*
519 * Set the OSC bias current to max
520 * value for normal operation.
521 */
522 ldr r6, [r3, #0x150]
523 bic r6, r6, #0xC000
524 str r6, [r3, #0x150]
525
526 /* Enable main 2p5. */ 527 /* Enable main 2p5. */
527 ldr r6, [r3, #0x130] 528 ldr r6, [r3, #0x130]
528 orr r6, r6, #0x1 529 orr r6, r6, #0x1
@@ -540,6 +541,16 @@ loop_2p5:
540 bic r6, r6, #0x40000 541 bic r6, r6, #0x40000
541 str r6, [r3, #0x130] 542 str r6, [r3, #0x130]
542 543
544ldo2p5_not_disabled:
545 /*
546 * Set the OSC bias current to max
547 * value for normal operation.
548 */
549 ldr r6, [r3, #0x150]
550 bic r6, r6, #0xC000
551 str r6, [r3, #0x150]
552
553
543 /* Enable 1p1 brown out. */ 554 /* Enable 1p1 brown out. */
544 ldr r6, [r3, #0x110] 555 ldr r6, [r3, #0x110]
545 orr r6, r6, #0x2 556 orr r6, r6, #0x2
@@ -683,7 +694,7 @@ poll_dvfs_clear_1:
683 nop 694 nop
684 695
685 696
686 pop {r4-r11} 697 pop {r4-r12}
687 698
688 /* Restore registers */ 699 /* Restore registers */
689 mov pc, lr 700 mov pc, lr