]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00299939-2 ARM: imx6sl: Add dummy LDO2p5 regulator to support VBUS wakeup
authorRanjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>
Tue, 4 Mar 2014 21:31:59 +0000 (15:31 -0600)
committerRanjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>
Wed, 5 Mar 2014 22:48:39 +0000 (16:48 -0600)
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>
arch/arm/mach-imx/cpuidle-imx6sl.c
arch/arm/mach-imx/imx6sl_wfi.S

index 6b98392d10e877e867082b348edf1ff4cda08796..573a4076da6df2d92fbc4a0af33dd9643d281180 100644 (file)
@@ -12,6 +12,9 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
 #include <asm/cpuidle.h>
 #include <asm/fncpy.h>
 #include <asm/mach/map.h>
@@ -32,9 +35,18 @@ extern void restore_ttbr1(unsigned long ttbr1);
 
 static void __iomem *iomux_base;
 static void *wfi_iram_base;
+static struct regulator *vbus_ldo;
+
+static struct regulator_dev *ldo2p5_dummy_regulator_rdev;
+static struct regulator_init_data ldo2p5_dummy_initdata = {
+       .constraints = {
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+static int ldo2p5_dummy_enable;
 
 void (*imx6sl_wfi_in_iram_fn)(void *wfi_iram_base,
-       void *iomux_addr, u32 audio_mode) = NULL;
+       bool vbus_ldo, u32 audio_mode) = NULL;
 
 
 static int imx6sl_enter_wait(struct cpuidle_device *dev,
@@ -49,7 +61,7 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev,
                 * Also float DDR IO pads.
                 */
                ttbr1 = save_ttbr1();
-               imx6sl_wfi_in_iram_fn(wfi_iram_base, iomux_base,
+               imx6sl_wfi_in_iram_fn(wfi_iram_base, regulator_is_enabled(vbus_ldo),
                                        audio_bus_freq_mode);
                restore_ttbr1(ttbr1);
        } else {
@@ -96,6 +108,10 @@ int __init imx6sl_cpuidle_init(void)
        iomux_base = of_iomap(node, 0);
        WARN(!iomux_base, "unable to map iomux registers\n");
 
+       vbus_ldo = regulator_get(NULL, "ldo2p5-dummy");
+       if (IS_ERR(vbus_ldo))
+               vbus_ldo = NULL;
+
        iram_paddr = MX6SL_WFI_IRAM_ADDR;
        /* Calculate the virtual address of the code */
        wfi_iram_base = (void *)IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) +
@@ -106,3 +122,73 @@ int __init imx6sl_cpuidle_init(void)
 
        return cpuidle_register(&imx6sl_cpuidle_driver, NULL);
 }
+
+static int imx_ldo2p5_dummy_enable(struct regulator_dev *rdev)
+{
+       ldo2p5_dummy_enable = 1;
+
+       return 0;
+}
+
+static int imx_ldo2p5_dummy_disable(struct regulator_dev *rdev)
+{
+       ldo2p5_dummy_enable = 0;
+
+       return 0;
+}
+
+static int imx_ldo2p5_dummy_is_enable(struct regulator_dev *rdev)
+{
+       return ldo2p5_dummy_enable;
+}
+
+
+static struct regulator_ops ldo2p5_dummy_ops = {
+       .enable = imx_ldo2p5_dummy_enable,
+       .disable = imx_ldo2p5_dummy_disable,
+       .is_enabled = imx_ldo2p5_dummy_is_enable,
+};
+
+static struct regulator_desc ldo2p5_dummy_desc = {
+       .name = "ldo2p5-dummy",
+       .id = -1,
+       .type = REGULATOR_VOLTAGE,
+       .owner = THIS_MODULE,
+       .ops = &ldo2p5_dummy_ops,
+};
+
+static int ldo2p5_dummy_probe(struct platform_device *pdev)
+{
+       struct regulator_config config = { };
+       int ret;
+
+       config.dev = &pdev->dev;
+       config.init_data = &ldo2p5_dummy_initdata;
+       config.of_node = pdev->dev.of_node;
+
+       ldo2p5_dummy_regulator_rdev = regulator_register(&ldo2p5_dummy_desc, &config);
+       if (IS_ERR(ldo2p5_dummy_regulator_rdev)) {
+               ret = PTR_ERR(ldo2p5_dummy_regulator_rdev);
+               dev_err(&pdev->dev, "Failed to register dummy ldo2p5 regulator: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id imx_ldo2p5_dummy_ids[] = {
+       { .compatible = "fsl,imx6-dummy-ldo2p5" },
+};
+MODULE_DEVICE_TABLE(of, imx_ldo2p5_dummy_ids);
+
+static struct platform_driver ldo2p5_dummy_driver = {
+       .probe  = ldo2p5_dummy_probe,
+       .driver = {
+               .name   = "ldo2p5-dummy",
+               .owner  = THIS_MODULE,
+               .of_match_table = imx_ldo2p5_dummy_ids,
+       },
+};
+
+module_platform_driver(ldo2p5_dummy_driver);
+
index 20afe0256f5fa4eab12e9d81e9eccaaf088ea395..f8556e67631e301414372eec6759009cec6030e3 100644 (file)
@@ -155,15 +155,17 @@ fifo_reset2_wait:
  *  Make sure DDR is in self-refresh.
  *  IRQs are already disabled.
  * r0: WFI IRAMcode base address.
- * r1: IOMUX base address
+ * r1: 1 if vbus_ldo (ldo2p5) cannot be disabled
  * r2: 1 if in audio_bus_freq_mode
  */
        .align 3
 ENTRY(imx6sl_low_power_wfi)
 
-       push {r4-r11}
+       push {r4-r12}
 
 mx6sl_lpm_wfi:
+       /* Can LDO2p5 be disabled */
+       mov     r12, r1
        /* Store audio_bus_freq_mode */
        mov     r11, r2
 
@@ -402,6 +404,17 @@ podf_loop:
        bic     r6, r6, #0x2
        str     r6, [r3, #0x110]
 
+       /*
+        * Set the OSC bias current to -37.5%
+        * to drop the power on VDDHIGH.
+        */
+       ldr     r6, [r3, #0x150]
+       orr     r6, r6, #0xC000
+       str     r6, [r3, #0x150]
+
+       cmp     r12, #0x1
+       beq     leave_2p5_on
+
        /* Enable the weak 2P5 */
        ldr     r6, [r3, #0x130]
        orr     r6, r6, #0x40000
@@ -412,14 +425,6 @@ podf_loop:
        bic     r6, r6, #0x1
        str     r6, [r3, #0x130]
 
-       /*
-        * Set the OSC bias current to -37.5%
-        * to drop the power on VDDHIGH.
-        */
-       ldr     r6, [r3, #0x150]
-       orr     r6, r6, #0xC000
-       str     r6, [r3, #0x150]
-
        /* Enable low power bandgap */
        ldr     r6, [r3, #0x260]
        orr     r6, r6, #0x20
@@ -448,6 +453,7 @@ podf_loop:
        orr     r6, r6, #0x1
        str     r6, [r3, #0x150]
 
+leave_2p5_on:
        b       do_wfi
 
 do_audio_arm_clk:
@@ -497,6 +503,9 @@ podf_loop1:
        cmp     r7, #0x1
        bne     skip_analog_restore
 
+       cmp     r12, #1
+       beq     ldo2p5_not_disabled
+
        /* Power up the regular bandgap. */
        ldr     r6, [r3, #0x150]
        bic     r6, r6, #0x1
@@ -515,14 +524,6 @@ podf_loop1:
        bic     r6, r6, #0x20
        str     r6, [r3, #0x260]
 
-       /*
-        * Set the OSC bias current to max
-        * value for normal operation.
-        */
-       ldr     r6, [r3, #0x150]
-       bic     r6, r6, #0xC000
-       str     r6, [r3, #0x150]
-
        /* Enable main 2p5. */
        ldr     r6, [r3, #0x130]
        orr     r6, r6, #0x1
@@ -540,6 +541,16 @@ loop_2p5:
        bic     r6, r6, #0x40000
        str     r6, [r3, #0x130]
 
+ldo2p5_not_disabled:
+       /*
+        * Set the OSC bias current to max
+        * value for normal operation.
+        */
+       ldr     r6, [r3, #0x150]
+       bic     r6, r6, #0xC000
+       str     r6, [r3, #0x150]
+
+
        /* Enable 1p1 brown out. */
        ldr     r6, [r3, #0x110]
        orr     r6, r6, #0x2
@@ -683,7 +694,7 @@ poll_dvfs_clear_1:
        nop
 
 
-       pop {r4-r11}
+       pop {r4-r12}
 
        /* Restore registers */
        mov     pc, lr