If a device works as a wakeup source, it will keep working in the period of
sleep/deep sleep. This patch sets the wakeup devices according to the wakeup
attribute of device.

Signed-off-by: Chenhui Zhao <chenhui.z...@freescale.com>
---
 arch/arm/boot/dts/ls1021a.dtsi |   2 +
 arch/arm/mach-imx/pm-ls1.c     | 101 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+)

diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 0c51ce0..64534c0 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -136,6 +136,7 @@
                        sdhci,auto-cmd12;
                        big-endian;
                        bus-width = <4>;
+                       sleep = <&rcpm 0x00000080 0x0>;
                        status = "disabled";
                };
 
@@ -289,6 +290,7 @@
                        interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&sysclk>;
                        clock-names = "ipg";
+                       sleep = <&rcpm 0x0 0x40000000>;
                        status = "disabled";
                };
 
diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c
index 4f9ca80..b11fcb2 100644
--- a/arch/arm/mach-imx/pm-ls1.c
+++ b/arch/arm/mach-imx/pm-ls1.c
@@ -35,6 +35,13 @@
 #define CCSR_SCFG_DPSLPCR      0
 #define CCSR_SCFG_DPSLPCR_VAL  0x1
 #define CCSR_SCFG_PMCINTECR    0x160
+#define CCSR_SCFG_PMCINTECR_LPUART     0x40000000
+#define CCSR_SCFG_PMCINTECR_FTM                0x20000000
+#define CCSR_SCFG_PMCINTECR_GPIO       0x10000000
+#define CCSR_SCFG_PMCINTECR_IRQ0       0x08000000
+#define CCSR_SCFG_PMCINTECR_IRQ1       0x04000000
+#define CCSR_SCFG_PMCINTECR_ETSECRXG0  0x00800000
+#define CCSR_SCFG_PMCINTECR_ETSECRXG1  0x00400000
 #define CCSR_SCFG_PMCINTLECR   0x164
 #define CCSR_SCFG_PMCINTSR     0x168
 #define CCSR_SCFG_SPARECR2     0x504
@@ -50,7 +57,11 @@
 #define CCSR_RCPM_CLPCL10SETR          0x1c4
 #define CCSR_RCPM_CLPCL10SETR_C0       0x1
 #define CCSR_RCPM_IPPDEXPCR0           0x140
+#define CCSR_RCPM_IPPDEXPCR0_ETSEC     0x80000000
+#define CCSR_RCPM_IPPDEXPCR0_GPIO      0x00000040
 #define CCSR_RCPM_IPPDEXPCR1           0x144
+#define CCSR_RCPM_IPPDEXPCR1_LPUART    0x40000000
+#define CCSR_RCPM_IPPDEXPCR1_FLEXTIMER 0x20000000
 
 #define QIXIS_CTL_SYS                  0x5
 #define QIXIS_CTL_SYS_EVTSW_MASK       0x0c
@@ -64,6 +75,10 @@
 /* use the last page of SRAM */
 #define SRAM_CODE_BASE_PHY     (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE)
 
+#define SLEEP_ARRAY_SIZE       3
+
+static u32 ippdexpcr0, ippdexpcr1;
+
 struct ls1_pm_baseaddr {
        void __iomem *rcpm;
        void __iomem *epu;
@@ -242,6 +257,49 @@ static void ls1_board_resume(void)
        iowrite8(tmp, ls1_pm_base.fpga + QIXIS_CTL_SYS);
 }
 
+static void ls1_setup_pmc_int(void)
+{
+       u32 pmcintecr;
+
+       pmcintecr = 0;
+       if (ippdexpcr0 & CCSR_RCPM_IPPDEXPCR0_ETSEC)
+               pmcintecr |= CCSR_SCFG_PMCINTECR_ETSECRXG0 |
+                               CCSR_SCFG_PMCINTECR_ETSECRXG1;
+
+       if (ippdexpcr0 & CCSR_RCPM_IPPDEXPCR0_GPIO)
+               pmcintecr |= CCSR_SCFG_PMCINTECR_GPIO;
+
+       if (ippdexpcr1 & CCSR_RCPM_IPPDEXPCR1_LPUART)
+               pmcintecr |= CCSR_SCFG_PMCINTECR_LPUART;
+
+       if (ippdexpcr1 & CCSR_RCPM_IPPDEXPCR1_FLEXTIMER)
+               pmcintecr |= CCSR_SCFG_PMCINTECR_FTM;
+
+       /* always set external IRQ pins as wakeup source */
+       pmcintecr |= CCSR_SCFG_PMCINTECR_IRQ0 | CCSR_SCFG_PMCINTECR_IRQ1;
+
+       /* enable wakeup interrupt during deep sleep */
+       iowrite32be(pmcintecr, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR);
+       iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTLECR);
+       /* clear PMC interrupt status */
+       iowrite32be(0xffffffff, ls1_pm_base.scfg + CCSR_SCFG_PMCINTSR);
+}
+
+static void ls1_clear_pmc_int(void)
+{
+       /* disable wakeup interrupt during deep sleep */
+       iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR);
+       /* clear PMC interrupt status */
+       iowrite32be(0xffffffff, ls1_pm_base.scfg + CCSR_SCFG_PMCINTSR);
+}
+
+/* set IP powerdown exception, make them work during sleep/deep sleep */
+static void ls1_set_powerdown(void)
+{
+       iowrite32be(ippdexpcr0, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR0);
+       iowrite32be(ippdexpcr1, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR1);
+}
+
 static void ls1_enter_deepsleep(void)
 {
        /* save DDR data */
@@ -265,8 +323,12 @@ static void ls1_enter_deepsleep(void)
        /* copy the last stage code to sram */
        ls1_copy_sram_code();
 
+       ls1_setup_pmc_int();
+
        cpu_suspend(SRAM_CODE_BASE_PHY, ls1_start_deepsleep);
 
+       ls1_clear_pmc_int();
+
        /* disable Warm Device Reset */
        ls1_clrsetbits_be32(ls1_pm_base.scfg + CCSR_SCFG_DPSLPCR,
                            CCSR_SCFG_DPSLPCR_VAL, 0);
@@ -274,10 +336,45 @@ static void ls1_enter_deepsleep(void)
        ls1_board_resume();
 }
 
+static void ls1_set_power_except(struct device *dev, int on)
+{
+       int ret;
+       u32 value[SLEEP_ARRAY_SIZE];
+
+       /*
+        * Get the values in the "sleep" property. There are three values.
+        * The first points to the RCPM node, the second is the value of
+        * the ippdexpcr0 register, and the third is the value of
+        * the ippdexpcr1 register.
+        */
+       ret = of_property_read_u32_array(dev->of_node, "sleep",
+                                               value, SLEEP_ARRAY_SIZE);
+       if (ret) {
+               dev_err(dev, "%s: Can not find the \"sleep\" property.\n",
+                       __func__);
+               return;
+       }
+
+       ippdexpcr0 |= value[1];
+       ippdexpcr1 |= value[2];
+
+       pr_debug("%s: set %s as a wakeup source", __func__,
+                dev->of_node->full_name);
+}
+
+static void ls1_set_wakeup_device(struct device *dev, void *enable)
+{
+       /* set each device which can act as wakeup source */
+       if (device_may_wakeup(dev))
+               ls1_set_power_except(dev, *((int *)enable));
+}
+
 static int ls1_suspend_enter(suspend_state_t state)
 {
        int ret = 0;
 
+       ls1_set_powerdown();
+
        switch (state) {
        case PM_SUSPEND_STANDBY:
                flush_cache_louis();
@@ -316,6 +413,10 @@ static int ls1_suspend_begin(suspend_state_t state)
 
        ls1_pm_state = state;
 
+       ippdexpcr0 = 0;
+       ippdexpcr1 = 0;
+       dpm_for_each_dev(NULL, ls1_set_wakeup_device);
+
        if (ls1_pm_state == PM_SUSPEND_MEM)
                ret = ls1_pm_iomap();
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to