[PATCH] arm: imx6q: bypass anatop regulator during suspend

Jason Chen jason.chen at linaro.org
Thu Jan 5 00:20:42 EST 2012


enable bit CCM_CLPCR_wb_per_at_lpm to decrease leakage during suspend.
enable bit CCM_CCR_RBC_EN to disable/bypass anatop regulator during suspend.

Signed-off-by: Jason Chen <jason.chen at linaro.org>
Signed-off-by: Jason Chen <jason.chen at freescale.com>
---
 arch/arm/mach-imx/clock-imx6q.c |   31 +++++++++++++++---------
 arch/arm/mach-imx/pm-imx6q.c    |   48 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c
index 56a7a3f..11d2453 100644
--- a/arch/arm/mach-imx/clock-imx6q.c
+++ b/arch/arm/mach-imx/clock-imx6q.c
@@ -115,6 +115,8 @@
 #define CG14		28
 #define CG15		30
 
+#define BM_CCR_RBC_EN			(0x1 << 27)
+
 #define BM_CCSR_PLL1_SW_SEL		(0x1 << 2)
 #define BM_CCSR_STEP_SEL		(0x1 << 8)
 
@@ -1916,33 +1918,38 @@ static struct clk_lookup lookups[] = {
 
 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
 {
-	u32 val = readl_relaxed(CLPCR);
+	u32 clpcr = readl_relaxed(CLPCR);
+	u32 ccr = readl_relaxed(CCR);
 
-	val &= ~BM_CLPCR_LPM;
+	clpcr &= ~(BM_CLPCR_LPM | BM_CLPCR_VSTBY | BM_CLPCR_SBYOS
+			| BM_CLPCR_STBY_COUNT | BM_CLPCR_WB_PER_AT_LPM);
+	ccr &= ~(BM_CCR_RBC_EN);
 	switch (mode) {
 	case WAIT_CLOCKED:
 		break;
 	case WAIT_UNCLOCKED:
-		val |= 0x1 << BP_CLPCR_LPM;
+		clpcr |= 0x1 << BP_CLPCR_LPM;
 		break;
 	case STOP_POWER_ON:
-		val |= 0x2 << BP_CLPCR_LPM;
+		clpcr |= 0x2 << BP_CLPCR_LPM;
 		break;
 	case WAIT_UNCLOCKED_POWER_OFF:
-		val |= 0x1 << BP_CLPCR_LPM;
-		val &= ~BM_CLPCR_VSTBY;
-		val &= ~BM_CLPCR_SBYOS;
+		clpcr |= 0x1 << BP_CLPCR_LPM;
 		break;
 	case STOP_POWER_OFF:
-		val |= 0x2 << BP_CLPCR_LPM;
-		val |= 0x3 << BP_CLPCR_STBY_COUNT;
-		val |= BM_CLPCR_VSTBY;
-		val |= BM_CLPCR_SBYOS;
+		clpcr |= 0x2 << BP_CLPCR_LPM;
+		clpcr |= 0x3 << BP_CLPCR_STBY_COUNT;
+		clpcr |= BM_CLPCR_VSTBY;
+		clpcr |= BM_CLPCR_SBYOS;
+		clpcr |= BM_CLPCR_WB_PER_AT_LPM;
+		/* assert anatop_reg_bypass signal */
+		ccr |= BM_CCR_RBC_EN;
 		break;
 	default:
 		return -EINVAL;
 	}
-	writel_relaxed(val, CLPCR);
+	writel_relaxed(clpcr, CLPCR);
+	writel_relaxed(ccr, CCR);
 
 	return 0;
 }
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
index f20f191..72a1399 100644
--- a/arch/arm/mach-imx/pm-imx6q.c
+++ b/arch/arm/mach-imx/pm-imx6q.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/suspend.h>
 #include <asm/cacheflush.h>
 #include <asm/proc-fns.h>
@@ -22,6 +23,41 @@
 #include <mach/hardware.h>
 
 extern unsigned long phys_l2x0_saved_regs;
+static void __iomem *anatop_base;
+
+#define ANATOP_REG_2P5			0x130
+#define BM_ANATOP_REG_2P5_WEAK_EN	(0x1 << 18)
+
+static int imx6q_anatop_reg_pre_suspend(void)
+{
+	/*
+	 * enable anatop weak 2p5 regulator, which should use
+	 * regulator API after anatop regulator implementation.
+	 */
+	if (anatop_base) {
+		unsigned int reg_2p5;
+		reg_2p5 = readl(anatop_base + ANATOP_REG_2P5);
+		reg_2p5 |= BM_ANATOP_REG_2P5_WEAK_EN;
+		writel(reg_2p5, anatop_base + ANATOP_REG_2P5);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void imx6q_anatop_reg_post_resume(void)
+{
+	/*
+	 * disable anatop weak 2p5 regulator, which should use
+	 * regulator API after anatop regulator implementation.
+	 */
+	if (anatop_base) {
+		unsigned int reg_2p5;
+		reg_2p5 = readl(anatop_base + ANATOP_REG_2P5);
+		reg_2p5 &= ~BM_ANATOP_REG_2P5_WEAK_EN;
+		writel(reg_2p5, anatop_base + ANATOP_REG_2P5);
+	}
+}
 
 static int imx6q_suspend_finish(unsigned long val)
 {
@@ -33,6 +69,8 @@ static int imx6q_pm_enter(suspend_state_t state)
 {
 	switch (state) {
 	case PM_SUSPEND_MEM:
+		if (imx6q_anatop_reg_pre_suspend() < 0)
+			return -EINVAL;
 		imx6q_set_lpm(STOP_POWER_OFF);
 		imx_gpc_pre_suspend();
 		imx_set_cpu_jump(0, v7_cpu_resume);
@@ -40,6 +78,7 @@ static int imx6q_pm_enter(suspend_state_t state)
 		cpu_suspend(0, imx6q_suspend_finish);
 		imx_smp_prepare();
 		imx_gpc_post_resume();
+		imx6q_anatop_reg_post_resume();
 		break;
 	default:
 		return -EINVAL;
@@ -55,6 +94,15 @@ static const struct platform_suspend_ops imx6q_pm_ops = {
 
 void __init imx6q_pm_init(void)
 {
+	struct device_node *np;
+
+	/*
+	 * remap anatop to adjust anatop regulator, which should
+	 * remove after anatop regulator driver implementation.
+	 */
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
+	anatop_base = of_iomap(np, 0);
+
 	/*
 	 * The l2x0 core code provides an infrastucture to save and restore
 	 * l2x0 registers across suspend/resume cycle.  But because imx6q
-- 
1.7.4.1





More information about the linux-arm-kernel mailing list