Просмотр исходного кода

Merge branch 'power' of git://github.com/hzhuang1/linux into next/pm

* 'power' of git://github.com/hzhuang1/linux:
  ARM: mmp: add pm support for pxa910
  ARM: mmp: ttc_dkb: add PMIC support
  ARM: cache: tauros2: add disable and resume callback
  ARM: mm: proc-mohawk: add suspend resume for mohawk
  ARM: mmp: add PM support for mmp2
  ARM: mmp: move XX_REG definition to addr-map.h

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Arnd Bergmann 13 лет назад
Родитель
Сommit
602b9ba2cb

+ 1 - 1
arch/arm/Kconfig

@@ -2275,7 +2275,7 @@ source "kernel/power/Kconfig"
 config ARCH_SUSPEND_POSSIBLE
 	depends on !ARCH_S5PC100
 	depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
-		CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
+		CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK
 	def_bool y
 
 config ARM_CPU_SUSPEND

+ 5 - 0
arch/arm/mach-mmp/Makefile

@@ -9,6 +9,11 @@ obj-$(CONFIG_CPU_PXA168)	+= pxa168.o
 obj-$(CONFIG_CPU_PXA910)	+= pxa910.o
 obj-$(CONFIG_CPU_MMP2)		+= mmp2.o sram.o
 
+ifeq ($(CONFIG_PM),y)
+obj-$(CONFIG_CPU_PXA910)	+= pm-pxa910.o
+obj-$(CONFIG_CPU_MMP2)		+= pm-mmp2.o
+endif
+
 # board support
 obj-$(CONFIG_MACH_ASPENITE)	+= aspenite.o
 obj-$(CONFIG_MACH_ZYLONITE2)	+= aspenite.o

+ 12 - 0
arch/arm/mach-mmp/include/mach/addr-map.h

@@ -31,4 +31,16 @@
 #define SMC_CS1_PHYS_BASE	0x90000000
 #define SMC_CS1_PHYS_SIZE	0x10000000
 
+#define APMU_VIRT_BASE		(AXI_VIRT_BASE + 0x82800)
+#define APMU_REG(x)		(APMU_VIRT_BASE + (x))
+
+#define APBC_VIRT_BASE		(APB_VIRT_BASE + 0x015000)
+#define APBC_REG(x)		(APBC_VIRT_BASE + (x))
+
+#define MPMU_VIRT_BASE		(APB_VIRT_BASE + 0x50000)
+#define MPMU_REG(x)		(MPMU_VIRT_BASE + (x))
+
+#define CIU_VIRT_BASE		(AXI_VIRT_BASE + 0x82c00)
+#define CIU_REG(x)		(CIU_VIRT_BASE + (x))
+
 #endif /* __ASM_MACH_ADDR_MAP_H */

+ 61 - 0
arch/arm/mach-mmp/include/mach/pm-mmp2.h

@@ -0,0 +1,61 @@
+/*
+ * MMP2 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2010 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#ifndef __MMP2_PM_H__
+#define __MMP2_PM_H__
+
+#include <mach/addr-map.h>
+
+#define APMU_PJ_IDLE_CFG			APMU_REG(0x018)
+#define APMU_PJ_IDLE_CFG_PJ_IDLE		(1 << 1)
+#define APMU_PJ_IDLE_CFG_PJ_PWRDWN		(1 << 5)
+#define APMU_PJ_IDLE_CFG_PWR_SW(x)		((x) << 16)
+#define APMU_PJ_IDLE_CFG_L2_PWR_SW		(1 << 19)
+#define APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK	(3 << 28)
+
+#define APMU_SRAM_PWR_DWN			APMU_REG(0x08c)
+
+#define MPMU_SCCR				MPMU_REG(0x038)
+#define MPMU_PCR_PJ				MPMU_REG(0x1000)
+#define MPMU_PCR_PJ_AXISD			(1 << 31)
+#define MPMU_PCR_PJ_SLPEN			(1 << 29)
+#define MPMU_PCR_PJ_SPSD			(1 << 28)
+#define MPMU_PCR_PJ_DDRCORSD			(1 << 27)
+#define MPMU_PCR_PJ_APBSD			(1 << 26)
+#define MPMU_PCR_PJ_INTCLR			(1 << 24)
+#define MPMU_PCR_PJ_SLPWP0			(1 << 23)
+#define MPMU_PCR_PJ_SLPWP1			(1 << 22)
+#define MPMU_PCR_PJ_SLPWP2			(1 << 21)
+#define MPMU_PCR_PJ_SLPWP3			(1 << 20)
+#define MPMU_PCR_PJ_VCTCXOSD			(1 << 19)
+#define MPMU_PCR_PJ_SLPWP4			(1 << 18)
+#define MPMU_PCR_PJ_SLPWP5			(1 << 17)
+#define MPMU_PCR_PJ_SLPWP6			(1 << 16)
+#define MPMU_PCR_PJ_SLPWP7			(1 << 15)
+
+#define MPMU_PLL2_CTRL1				MPMU_REG(0x0414)
+#define MPMU_CGR_PJ				MPMU_REG(0x1024)
+#define MPMU_WUCRM_PJ				MPMU_REG(0x104c)
+#define MPMU_WUCRM_PJ_WAKEUP(x)			(1 << (x))
+#define MPMU_WUCRM_PJ_RTC_ALARM			(1 << 17)
+
+enum {
+	POWER_MODE_ACTIVE = 0,
+	POWER_MODE_CORE_INTIDLE,
+	POWER_MODE_CORE_EXTIDLE,
+	POWER_MODE_APPS_IDLE,
+	POWER_MODE_APPS_SLEEP,
+	POWER_MODE_CHIP_SLEEP,
+	POWER_MODE_SYS_SLEEP,
+};
+
+extern void mmp2_pm_enter_lowpower_mode(int state);
+extern int mmp2_set_wake(struct irq_data *d, unsigned int on);
+#endif

+ 77 - 0
arch/arm/mach-mmp/include/mach/pm-pxa910.h

@@ -0,0 +1,77 @@
+/*
+ * PXA910 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2009 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#ifndef __PXA910_PM_H__
+#define __PXA910_PM_H__
+
+#define APMU_MOH_IDLE_CFG			APMU_REG(0x0018)
+#define APMU_MOH_IDLE_CFG_MOH_IDLE		(1 << 1)
+#define APMU_MOH_IDLE_CFG_MOH_PWRDWN		(1 << 5)
+#define APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN	(1 << 6)
+#define APMU_MOH_IDLE_CFG_MOH_PWR_SW(x)		(((x) & 0x3) << 16)
+#define APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(x)	(((x) & 0x3) << 18)
+#define APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ	(1 << 21)
+#define APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN	(1 << 20)
+
+#define APMU_SQU_CLK_GATE_CTRL			APMU_REG(0x001c)
+#define APMU_MC_HW_SLP_TYPE			APMU_REG(0x00b0)
+
+#define MPMU_FCCR				MPMU_REG(0x0008)
+#define MPMU_APCR				MPMU_REG(0x1000)
+#define MPMU_APCR_AXISD				(1 << 31)
+#define MPMU_APCR_DSPSD				(1 << 30)
+#define MPMU_APCR_SLPEN				(1 << 29)
+#define MPMU_APCR_DTCMSD			(1 << 28)
+#define MPMU_APCR_DDRCORSD			(1 << 27)
+#define MPMU_APCR_APBSD				(1 << 26)
+#define MPMU_APCR_BBSD				(1 << 25)
+#define MPMU_APCR_SLPWP0			(1 << 23)
+#define MPMU_APCR_SLPWP1			(1 << 22)
+#define MPMU_APCR_SLPWP2			(1 << 21)
+#define MPMU_APCR_SLPWP3			(1 << 20)
+#define MPMU_APCR_VCTCXOSD			(1 << 19)
+#define MPMU_APCR_SLPWP4			(1 << 18)
+#define MPMU_APCR_SLPWP5			(1 << 17)
+#define MPMU_APCR_SLPWP6			(1 << 16)
+#define MPMU_APCR_SLPWP7			(1 << 15)
+#define MPMU_APCR_MSASLPEN			(1 << 14)
+#define MPMU_APCR_STBYEN			(1 << 13)
+
+#define MPMU_AWUCRM				MPMU_REG(0x104c)
+#define MPMU_AWUCRM_AP_ASYNC_INT		(1 << 25)
+#define MPMU_AWUCRM_AP_FULL_IDLE		(1 << 24)
+#define MPMU_AWUCRM_SDH1			(1 << 23)
+#define MPMU_AWUCRM_SDH2			(1 << 22)
+#define MPMU_AWUCRM_KEYPRESS			(1 << 21)
+#define MPMU_AWUCRM_TRACKBALL			(1 << 20)
+#define MPMU_AWUCRM_NEWROTARY			(1 << 19)
+#define MPMU_AWUCRM_RTC_ALARM			(1 << 17)
+#define MPMU_AWUCRM_AP2_TIMER_3			(1 << 13)
+#define MPMU_AWUCRM_AP2_TIMER_2			(1 << 12)
+#define MPMU_AWUCRM_AP2_TIMER_1			(1 << 11)
+#define MPMU_AWUCRM_AP1_TIMER_3			(1 << 10)
+#define MPMU_AWUCRM_AP1_TIMER_2			(1 << 9)
+#define MPMU_AWUCRM_AP1_TIMER_1			(1 << 8)
+#define MPMU_AWUCRM_WAKEUP(x)			(1 << ((x) & 0x7))
+
+enum {
+	POWER_MODE_ACTIVE = 0,
+	POWER_MODE_CORE_INTIDLE,
+	POWER_MODE_CORE_EXTIDLE,
+	POWER_MODE_APPS_IDLE,
+	POWER_MODE_APPS_SLEEP,
+	POWER_MODE_SYS_SLEEP,
+	POWER_MODE_HIBERNATE,
+	POWER_MODE_UDR,
+};
+
+extern int pxa910_set_wake(struct irq_data *data, unsigned int on);
+
+#endif

+ 0 - 3
arch/arm/mach-mmp/include/mach/regs-apbc.h

@@ -13,9 +13,6 @@
 
 #include <mach/addr-map.h>
 
-#define APBC_VIRT_BASE	(APB_VIRT_BASE + 0x015000)
-#define APBC_REG(x)	(APBC_VIRT_BASE + (x))
-
 /*
  * APB clock register offsets for PXA168
  */

+ 0 - 3
arch/arm/mach-mmp/include/mach/regs-apmu.h

@@ -13,9 +13,6 @@
 
 #include <mach/addr-map.h>
 
-#define APMU_VIRT_BASE	(AXI_VIRT_BASE + 0x82800)
-#define APMU_REG(x)	(APMU_VIRT_BASE + (x))
-
 /* Clock Reset Control */
 #define APMU_IRE	APMU_REG(0x048)
 #define APMU_LCD	APMU_REG(0x04c)

+ 13 - 0
arch/arm/mach-mmp/irq.c

@@ -23,6 +23,13 @@
 
 #include <mach/irqs.h>
 
+#ifdef CONFIG_CPU_MMP2
+#include <mach/pm-mmp2.h>
+#endif
+#ifdef CONFIG_CPU_PXA910
+#include <mach/pm-pxa910.h>
+#endif
+
 #include "common.h"
 
 #define MAX_ICU_NR		16
@@ -209,6 +216,9 @@ void __init icu_init_irq(void)
 		set_irq_flags(irq, IRQF_VALID);
 	}
 	irq_set_default_host(icu_data[0].domain);
+#ifdef CONFIG_CPU_PXA910
+	icu_irq_chip.irq_set_wake = pxa910_set_wake;
+#endif
 }
 
 /* MMP2 (ARMv7) */
@@ -305,6 +315,9 @@ void __init mmp2_init_icu(void)
 		set_irq_flags(irq, IRQF_VALID);
 	}
 	irq_set_default_host(icu_data[0].domain);
+#ifdef CONFIG_CPU_MMP2
+	icu_irq_chip.irq_set_wake = mmp2_set_wake;
+#endif
 }
 
 #ifdef CONFIG_OF

+ 264 - 0
arch/arm/mach-mmp/pm-mmp2.c

@@ -0,0 +1,264 @@
+/*
+ * MMP2 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2012 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/cputype.h>
+#include <mach/addr-map.h>
+#include <mach/pm-mmp2.h>
+#include <mach/regs-icu.h>
+#include <mach/irqs.h>
+
+int mmp2_set_wake(struct irq_data *d, unsigned int on)
+{
+	int irq = d->irq;
+	struct irq_desc *desc = irq_to_desc(irq);
+	unsigned long data = 0;
+
+	if (unlikely(irq >= nr_irqs)) {
+		pr_err("IRQ nubmers are out of boundary!\n");
+		return -EINVAL;
+	}
+
+	if (on) {
+		if (desc->action)
+			desc->action->flags |= IRQF_NO_SUSPEND;
+	} else {
+		if (desc->action)
+			desc->action->flags &= ~IRQF_NO_SUSPEND;
+	}
+
+	/* enable wakeup sources */
+	switch (irq) {
+	case IRQ_MMP2_RTC:
+	case IRQ_MMP2_RTC_ALARM:
+		data = MPMU_WUCRM_PJ_WAKEUP(4) | MPMU_WUCRM_PJ_RTC_ALARM;
+		break;
+	case IRQ_MMP2_PMIC:
+		data = MPMU_WUCRM_PJ_WAKEUP(7);
+		break;
+	case IRQ_MMP2_MMC2:
+		/* mmc use WAKEUP2, same as GPIO wakeup source */
+		data = MPMU_WUCRM_PJ_WAKEUP(2);
+		break;
+	}
+	if (on) {
+		if (data) {
+			data |= __raw_readl(MPMU_WUCRM_PJ);
+			__raw_writel(data, MPMU_WUCRM_PJ);
+		}
+	} else {
+		if (data) {
+			data = ~data & __raw_readl(MPMU_WUCRM_PJ);
+			__raw_writel(data, MPMU_WUCRM_PJ);
+		}
+	}
+	return 0;
+}
+
+static void pm_scu_clk_disable(void)
+{
+	unsigned int val;
+
+	/* close AXI fabric clock gate */
+	__raw_writel(0x0, CIU_REG(0x64));
+	__raw_writel(0x0, CIU_REG(0x68));
+
+	/* close MCB master clock gate */
+	val = __raw_readl(CIU_REG(0x1c));
+	val |= 0xf0;
+	__raw_writel(val, CIU_REG(0x1c));
+
+	return ;
+}
+
+static void pm_scu_clk_enable(void)
+{
+	unsigned int val;
+
+	/* open AXI fabric clock gate */
+	__raw_writel(0x03003003, CIU_REG(0x64));
+	__raw_writel(0x00303030, CIU_REG(0x68));
+
+	/* open MCB master clock gate */
+	val = __raw_readl(CIU_REG(0x1c));
+	val &= ~(0xf0);
+	__raw_writel(val, CIU_REG(0x1c));
+
+	return ;
+}
+
+static void pm_mpmu_clk_disable(void)
+{
+	/*
+	 * disable clocks in MPMU_CGR_PJ register
+	 * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M
+	 */
+	__raw_writel(0x0000a010, MPMU_CGR_PJ);
+}
+
+static void pm_mpmu_clk_enable(void)
+{
+	unsigned int val;
+
+	__raw_writel(0xdffefffe, MPMU_CGR_PJ);
+	val = __raw_readl(MPMU_PLL2_CTRL1);
+	val |= (1 << 29);
+	__raw_writel(val, MPMU_PLL2_CTRL1);
+
+	return ;
+}
+
+void mmp2_pm_enter_lowpower_mode(int state)
+{
+	uint32_t idle_cfg, apcr;
+
+	idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG);
+	apcr = __raw_readl(MPMU_PCR_PJ);
+	apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD
+		 | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13));
+	idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE;
+
+	switch (state) {
+	case POWER_MODE_SYS_SLEEP:
+		apcr |= MPMU_PCR_PJ_SLPEN;		/* set the SLPEN bit */
+		apcr |= MPMU_PCR_PJ_VCTCXOSD;		/* set VCTCXOSD */
+		/* fall through */
+	case POWER_MODE_CHIP_SLEEP:
+		apcr |= MPMU_PCR_PJ_SLPEN;
+		/* fall through */
+	case POWER_MODE_APPS_SLEEP:
+		apcr |= MPMU_PCR_PJ_APBSD;		/* set APBSD */
+		/* fall through */
+	case POWER_MODE_APPS_IDLE:
+		apcr |= MPMU_PCR_PJ_AXISD;		/* set AXISDD bit */
+		apcr |= MPMU_PCR_PJ_DDRCORSD;		/* set DDRCORSD bit */
+		idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN;	/* PJ power down */
+		apcr |= MPMU_PCR_PJ_SPSD;
+		/* fall through */
+	case POWER_MODE_CORE_EXTIDLE:
+		idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE;	/* set the IDLE bit */
+		idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK;
+		idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3)
+			| APMU_PJ_IDLE_CFG_L2_PWR_SW;
+		break;
+	case POWER_MODE_CORE_INTIDLE:
+		apcr &= ~MPMU_PCR_PJ_SPSD;
+		break;
+	}
+
+	/* set reserve bits */
+	apcr |= (1 << 30) | (1 << 25);
+
+	/* finally write the registers back */
+	__raw_writel(idle_cfg, APMU_PJ_IDLE_CFG);
+	__raw_writel(apcr, MPMU_PCR_PJ);	/* 0xfe086000 */
+}
+
+static int mmp2_pm_enter(suspend_state_t state)
+{
+	int temp;
+
+	temp = __raw_readl(MMP2_ICU_INT4_MASK);
+	if (temp & (1 << 1)) {
+		printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__);
+		return -EAGAIN;
+	}
+
+	temp = __raw_readl(APMU_SRAM_PWR_DWN);
+	temp |= ((1 << 19) | (1 << 18));
+	__raw_writel(temp, APMU_SRAM_PWR_DWN);
+	pm_mpmu_clk_disable();
+	pm_scu_clk_disable();
+
+	printk(KERN_INFO "%s: before suspend\n", __func__);
+	cpu_do_idle();
+	printk(KERN_INFO "%s: after suspend\n", __func__);
+
+	pm_mpmu_clk_enable();		/* enable clocks in MPMU */
+	pm_scu_clk_enable();		/* enable clocks in SCU */
+
+	return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int mmp2_pm_prepare(void)
+{
+	mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP);
+
+	return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static void mmp2_pm_finish(void)
+{
+	mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
+}
+
+static int mmp2_pm_valid(suspend_state_t state)
+{
+	return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static const struct platform_suspend_ops mmp2_pm_ops = {
+	.valid		= mmp2_pm_valid,
+	.prepare	= mmp2_pm_prepare,
+	.enter		= mmp2_pm_enter,
+	.finish		= mmp2_pm_finish,
+};
+
+static int __init mmp2_pm_init(void)
+{
+	uint32_t apcr;
+
+	if (!cpu_is_mmp2())
+		return -EIO;
+
+	suspend_set_ops(&mmp2_pm_ops);
+
+	/*
+	 * Set bit 0, Slow clock Select 32K clock input instead of VCXO
+	 * VCXO is chosen by default, which would be disabled in suspend
+	 */
+	__raw_writel(0x5, MPMU_SCCR);
+
+	/*
+	 * Clear bit 23 of CIU_CPU_CONF
+	 * direct PJ4 to DDR access through Memory Controller slow queue
+	 * fast queue has issue and cause lcd will flick
+	 */
+	__raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8));
+
+	/* Clear default low power control bit */
+	apcr = __raw_readl(MPMU_PCR_PJ);
+	apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD
+			| MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13);
+	__raw_writel(apcr, MPMU_PCR_PJ);
+
+	return 0;
+}
+
+late_initcall(mmp2_pm_init);

+ 285 - 0
arch/arm/mach-mmp/pm-pxa910.c

@@ -0,0 +1,285 @@
+/*
+ * PXA910 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2009 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/cputype.h>
+#include <mach/addr-map.h>
+#include <mach/pm-pxa910.h>
+#include <mach/regs-icu.h>
+#include <mach/irqs.h>
+
+int pxa910_set_wake(struct irq_data *data, unsigned int on)
+{
+	int irq = data->irq;
+	struct irq_desc *desc = irq_to_desc(data->irq);
+	uint32_t awucrm = 0, apcr = 0;
+
+	if (unlikely(irq >= nr_irqs)) {
+		pr_err("IRQ nubmers are out of boundary!\n");
+		return -EINVAL;
+	}
+
+	if (on) {
+		if (desc->action)
+			desc->action->flags |= IRQF_NO_SUSPEND;
+	} else {
+		if (desc->action)
+			desc->action->flags &= ~IRQF_NO_SUSPEND;
+	}
+
+	/* setting wakeup sources */
+	switch (irq) {
+	/* wakeup line 2 */
+	case IRQ_PXA910_AP_GPIO:
+		awucrm = MPMU_AWUCRM_WAKEUP(2);
+		apcr |= MPMU_APCR_SLPWP2;
+		break;
+	/* wakeup line 3 */
+	case IRQ_PXA910_KEYPAD:
+		awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_KEYPRESS;
+		apcr |= MPMU_APCR_SLPWP3;
+		break;
+	case IRQ_PXA910_ROTARY:
+		awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_NEWROTARY;
+		apcr |= MPMU_APCR_SLPWP3;
+		break;
+	case IRQ_PXA910_TRACKBALL:
+		awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_TRACKBALL;
+		apcr |= MPMU_APCR_SLPWP3;
+		break;
+	/* wakeup line 4 */
+	case IRQ_PXA910_AP1_TIMER1:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_1;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP1_TIMER2:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_2;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP1_TIMER3:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_3;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP2_TIMER1:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_1;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP2_TIMER2:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_2;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_AP2_TIMER3:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_3;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	case IRQ_PXA910_RTC_ALARM:
+		awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_RTC_ALARM;
+		apcr |= MPMU_APCR_SLPWP4;
+		break;
+	/* wakeup line 5 */
+	case IRQ_PXA910_USB1:
+	case IRQ_PXA910_USB2:
+		awucrm = MPMU_AWUCRM_WAKEUP(5);
+		apcr |= MPMU_APCR_SLPWP5;
+		break;
+	/* wakeup line 6 */
+	case IRQ_PXA910_MMC:
+		awucrm = MPMU_AWUCRM_WAKEUP(6)
+			| MPMU_AWUCRM_SDH1
+			| MPMU_AWUCRM_SDH2;
+		apcr |= MPMU_APCR_SLPWP6;
+		break;
+	/* wakeup line 7 */
+	case IRQ_PXA910_PMIC_INT:
+		awucrm = MPMU_AWUCRM_WAKEUP(7);
+		apcr |= MPMU_APCR_SLPWP7;
+		break;
+	default:
+		if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
+			awucrm = MPMU_AWUCRM_WAKEUP(2);
+			apcr |= MPMU_APCR_SLPWP2;
+		} else
+			printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
+				irq);
+	}
+
+	if (on) {
+		if (awucrm) {
+			awucrm |= __raw_readl(MPMU_AWUCRM);
+			__raw_writel(awucrm, MPMU_AWUCRM);
+		}
+		if (apcr) {
+			apcr = ~apcr & __raw_readl(MPMU_APCR);
+			__raw_writel(apcr, MPMU_APCR);
+		}
+	} else {
+		if (awucrm) {
+			awucrm = ~awucrm & __raw_readl(MPMU_AWUCRM);
+			__raw_writel(awucrm, MPMU_AWUCRM);
+		}
+		if (apcr) {
+			apcr |= __raw_readl(MPMU_APCR);
+			__raw_writel(apcr, MPMU_APCR);
+		}
+	}
+	return 0;
+}
+
+void pxa910_pm_enter_lowpower_mode(int state)
+{
+	uint32_t idle_cfg, apcr;
+
+	idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+	apcr = __raw_readl(MPMU_APCR);
+
+	apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD
+		| MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN);
+	idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE
+		| APMU_MOH_IDLE_CFG_MOH_PWRDWN);
+
+	switch (state) {
+	case POWER_MODE_UDR:
+		/* only shutdown APB in UDR */
+		apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD;
+		/* fall through */
+	case POWER_MODE_SYS_SLEEP:
+		apcr |= MPMU_APCR_SLPEN;		/* set the SLPEN bit */
+		apcr |= MPMU_APCR_VCTCXOSD;		/* set VCTCXOSD */
+		/* fall through */
+	case POWER_MODE_APPS_SLEEP:
+		apcr |= MPMU_APCR_DDRCORSD;		/* set DDRCORSD */
+		/* fall through */
+	case POWER_MODE_APPS_IDLE:
+		apcr |= MPMU_APCR_AXISD;		/* set AXISDD bit */
+		/* fall through */
+	case POWER_MODE_CORE_EXTIDLE:
+		idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE;
+		idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN;
+		idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3)
+			| APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3);
+		/* fall through */
+	case POWER_MODE_CORE_INTIDLE:
+		break;
+	}
+
+	/* program the memory controller hardware sleep type and auto wakeup */
+	idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ;
+	idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN;
+	__raw_writel(0x0, APMU_MC_HW_SLP_TYPE);		/* auto refresh */
+
+	/* set DSPSD, DTCMSD, BBSD, MSASLPEN */
+	apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD
+		| MPMU_APCR_MSASLPEN;
+
+	/*always set SLEPEN bit mainly for MSA*/
+	apcr |= MPMU_APCR_SLPEN;
+
+	/* finally write the registers back */
+	__raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+	__raw_writel(apcr, MPMU_APCR);
+
+}
+
+static int pxa910_pm_enter(suspend_state_t state)
+{
+	unsigned int idle_cfg, reg = 0;
+
+	/*pmic thread not completed,exit;otherwise system can't be waked up*/
+	reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT));
+	if ((reg & 0x3) == 0)
+		return -EAGAIN;
+
+	idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+	idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN
+		| APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN;
+	__raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+
+	/* disable L2 */
+	outer_disable();
+	/* wait for l2 idle */
+	while (!(readl(CIU_REG(0x8)) & (1 << 16)))
+		udelay(1);
+
+	cpu_do_idle();
+
+	/* enable L2 */
+	outer_resume();
+	/* wait for l2 idle */
+	while (!(readl(CIU_REG(0x8)) & (1 << 16)))
+		udelay(1);
+
+	idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+	idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN
+		| APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN);
+	__raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+
+	return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int pxa910_pm_prepare(void)
+{
+	pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR);
+	return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static void pxa910_pm_finish(void)
+{
+	pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
+}
+
+static int pxa910_pm_valid(suspend_state_t state)
+{
+	return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+static const struct platform_suspend_ops pxa910_pm_ops = {
+	.valid		= pxa910_pm_valid,
+	.prepare	= pxa910_pm_prepare,
+	.enter		= pxa910_pm_enter,
+	.finish		= pxa910_pm_finish,
+};
+
+static int __init pxa910_pm_init(void)
+{
+	uint32_t awucrm = 0;
+
+	if (!cpu_is_pxa910())
+		return -EIO;
+
+	suspend_set_ops(&pxa910_pm_ops);
+
+	/* Set the following bits for MMP3 playback with VCTXO on */
+	__raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30),
+		APMU_SQU_CLK_GATE_CTRL);
+	__raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR);
+
+	awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE;
+	__raw_writel(awucrm, MPMU_AWUCRM);
+
+	return 0;
+}
+
+late_initcall(pxa910_pm_init);

+ 11 - 0
arch/arm/mach-mmp/ttc_dkb.c

@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/gpio.h>
+#include <linux/mfd/88pm860x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -135,7 +136,17 @@ static struct pca953x_platform_data max7312_data[] = {
 	},
 };
 
+static struct pm860x_platform_data ttc_dkb_pm8607_info = {
+	.irq_base       = IRQ_BOARD_START,
+};
+
 static struct i2c_board_info ttc_dkb_i2c_info[] = {
+	{
+		.type           = "88PM860x",
+		.addr           = 0x34,
+		.platform_data  = &ttc_dkb_pm8607_info,
+		.irq            = IRQ_PXA910_PMIC_INT,
+	},
 	{
 		.type		= "max7312",
 		.addr		= 0x23,

+ 24 - 0
arch/arm/mm/cache-tauros2.c

@@ -108,6 +108,26 @@ static void tauros2_flush_range(unsigned long start, unsigned long end)
 
 	dsb();
 }
+
+static void tauros2_disable(void)
+{
+	__asm__ __volatile__ (
+	"mcr	p15, 1, %0, c7, c11, 0 @L2 Cache Clean All\n\t"
+	"mrc	p15, 0, %0, c1, c0, 0\n\t"
+	"bic	%0, %0, #(1 << 26)\n\t"
+	"mcr	p15, 0, %0, c1, c0, 0  @Disable L2 Cache\n\t"
+	: : "r" (0x0));
+}
+
+static void tauros2_resume(void)
+{
+	__asm__ __volatile__ (
+	"mcr	p15, 1, %0, c7, c7, 0 @L2 Cache Invalidate All\n\t"
+	"mrc	p15, 0, %0, c1, c0, 0\n\t"
+	"orr	%0, %0, #(1 << 26)\n\t"
+	"mcr	p15, 0, %0, c1, c0, 0 @Enable L2 Cache\n\t"
+	: : "r" (0x0));
+}
 #endif
 
 static inline u32 __init read_extra_features(void)
@@ -194,6 +214,8 @@ void __init tauros2_init(void)
 		outer_cache.inv_range = tauros2_inv_range;
 		outer_cache.clean_range = tauros2_clean_range;
 		outer_cache.flush_range = tauros2_flush_range;
+		outer_cache.disable = tauros2_disable;
+		outer_cache.resume = tauros2_resume;
 	}
 #endif
 
@@ -219,6 +241,8 @@ void __init tauros2_init(void)
 		outer_cache.inv_range = tauros2_inv_range;
 		outer_cache.clean_range = tauros2_clean_range;
 		outer_cache.flush_range = tauros2_flush_range;
+		outer_cache.disable = tauros2_disable;
+		outer_cache.resume = tauros2_resume;
 	}
 #endif
 

+ 35 - 0
arch/arm/mm/proc-mohawk.S

@@ -344,6 +344,41 @@ ENTRY(cpu_mohawk_set_pte_ext)
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 	mov	pc, lr
 
+.globl	cpu_mohawk_suspend_size
+.equ	cpu_mohawk_suspend_size, 4 * 6
+#ifdef CONFIG_PM_SLEEP
+ENTRY(cpu_mohawk_do_suspend)
+	stmfd	sp!, {r4 - r9, lr}
+	mrc	p14, 0, r4, c6, c0, 0	@ clock configuration, for turbo mode
+	mrc	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mrc	p15, 0, r6, c13, c0, 0	@ PID
+	mrc 	p15, 0, r7, c3, c0, 0	@ domain ID
+	mrc	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
+	mrc 	p15, 0, r9, c1, c0, 0	@ control reg
+	bic	r4, r4, #2		@ clear frequency change bit
+	stmia	r0, {r4 - r9}		@ store cp regs
+	ldmia	sp!, {r4 - r9, pc}
+ENDPROC(cpu_mohawk_do_suspend)
+
+ENTRY(cpu_mohawk_do_resume)
+	ldmia	r0, {r4 - r9}		@ load cp regs
+	mov	ip, #0
+	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I & D caches, BTB
+	mcr	p15, 0, ip, c7, c10, 4	@ drain write (&fill) buffer
+	mcr	p15, 0, ip, c7, c5, 4	@ flush prefetch buffer
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I & D TLBs
+	mcr	p14, 0, r4, c6, c0, 0	@ clock configuration, turbo mode.
+	mcr	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mcr	p15, 0, r6, c13, c0, 0	@ PID
+	mcr	p15, 0, r7, c3, c0, 0	@ domain ID
+	orr	r1, r1, #0x18		@ cache the page table in L2
+	mcr	p15, 0, r1, c2, c0, 0	@ translation table base addr
+	mcr	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
+	mov	r0, r9			@ control register
+	b	cpu_resume_mmu
+ENDPROC(cpu_mohawk_do_resume)
+#endif
+
 	__CPUINIT
 
 	.type	__mohawk_setup, #function