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/