From 8febcb2f8747fb6a575555f42db4f2b586775d73 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 25 Jan 2011 20:34:43 +0800 Subject: [PATCH] rk29: add pm support --- arch/arm/mach-rk29/Makefile | 1 + arch/arm/mach-rk29/clock.c | 50 +------ arch/arm/mach-rk29/cpufreq.c | 74 +++++++++- arch/arm/mach-rk29/include/mach/cru.h | 147 +++++++++++++++++++ arch/arm/mach-rk29/pm.c | 196 ++++++++++++++++++++++++++ 5 files changed, 416 insertions(+), 52 deletions(-) create mode 100644 arch/arm/mach-rk29/pm.c diff --git a/arch/arm/mach-rk29/Makefile b/arch/arm/mach-rk29/Makefile index dde268b1161c..352e1c6fc1cc 100755 --- a/arch/arm/mach-rk29/Makefile +++ b/arch/arm/mach-rk29/Makefile @@ -1,4 +1,5 @@ obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o gpio.o ddr.o sram.o +obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_RK29_VPU) += vpu.o vpu_mem.o obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o diff --git a/arch/arm/mach-rk29/clock.c b/arch/arm/mach-rk29/clock.c index 34123cb6f383..cd75bfd39982 100755 --- a/arch/arm/mach-rk29/clock.c +++ b/arch/arm/mach-rk29/clock.c @@ -33,48 +33,6 @@ #include -/* CRU PLL CON */ -#define PLL_HIGH_BAND (0x01 << 16) -#define PLL_LOW_BAND (0x00 << 16) -#define PLL_PD (0x01 << 15) - -#define PLL_CLKR(i) ((((i) - 1) & 0x1f) << 10) -#define PLL_NR(v) ((((v) >> 10) & 0x1f) + 1) - -#define PLL_CLKF(i) ((((i) - 1) & 0x7f) << 3) -#define PLL_NF(v) ((((v) >> 3) & 0x7f) + 1) -#define PLL_NF2(v) (((((v) >> 3) & 0x7f) + 1) << 1) - -#define PLL_CLKOD(i) (((i) & 0x03) << 1) -#define PLL_NO_1 PLL_CLKOD(0) -#define PLL_NO_2 PLL_CLKOD(1) -#define PLL_NO_4 PLL_CLKOD(2) -#define PLL_NO_8 PLL_CLKOD(3) -#define PLL_NO_SHIFT(v) (((v) >> 1) & 0x03) - -#define PLL_BYPASS (0x01) - -/* CRU MODE CON */ -#define CRU_CPU_MODE_MASK (0x03u << 0) -#define CRU_CPU_MODE_SLOW (0x00u << 0) -#define CRU_CPU_MODE_NORMAL (0x01u << 0) -#define CRU_CPU_MODE_SLOW27 (0x02u << 0) - -#define CRU_GENERAL_MODE_MASK (0x03u << 2) -#define CRU_GENERAL_MODE_SLOW (0x00u << 2) -#define CRU_GENERAL_MODE_NORMAL (0x01u << 2) -#define CRU_GENERAL_MODE_SLOW27 (0x02u << 2) - -#define CRU_CODEC_MODE_MASK (0x03u << 4) -#define CRU_CODEC_MODE_SLOW (0x00u << 4) -#define CRU_CODEC_MODE_NORMAL (0x01u << 4) -#define CRU_CODEC_MODE_SLOW27 (0x02u << 4) - -#define CRU_DDR_MODE_MASK (0x03u << 6) -#define CRU_DDR_MODE_SLOW (0x00u << 6) -#define CRU_DDR_MODE_NORMAL (0x01u << 6) -#define CRU_DDR_MODE_SLOW27 (0x02u << 6) - /* Clock flags */ /* bit 0 is free */ #define RATE_FIXED (1 << 1) /* Fixed clock rate */ @@ -480,14 +438,16 @@ static struct clk ddr_pll_clk = { static int codec_pll_clk_mode(struct clk *clk, int on) { + u32 cpll = cru_readl(CRU_CPLL_CON); if (on) { - cru_writel(cru_readl(CRU_CPLL_CON) & ~PLL_PD, CRU_CPLL_CON); + cru_writel(cpll & ~(PLL_PD | PLL_BYPASS), CRU_CPLL_CON); delay_300us(); pll_wait_lock(CODEC_PLL_IDX); cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | CRU_CODEC_MODE_NORMAL, CRU_MODE_CON); } else { cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | CRU_CODEC_MODE_SLOW, CRU_MODE_CON); - cru_writel(cru_readl(CRU_CPLL_CON) | PLL_PD, CRU_CPLL_CON); + cru_writel(cpll | PLL_BYPASS, CRU_CPLL_CON); + cru_writel(cpll | PLL_PD | PLL_BYPASS, CRU_CPLL_CON); delay_500ns(); } return 0; @@ -2241,10 +2201,10 @@ static void __init rk29_clock_common_init(void) /* codec pll */ clk_set_rate_nolock(&codec_pll_clk, 552 * MHZ); clk_set_parent_nolock(&clk_gpu, &codec_pll_clk); - clk_set_parent_nolock(&clk_mac_ref_div, &codec_pll_clk); /* arm pll */ clk_set_rate_nolock(&arm_pll_clk, armclk); + clk_set_parent_nolock(&clk_mac_ref_div, &arm_pll_clk); } static void __init clk_enable_init_clocks(void) diff --git a/arch/arm/mach-rk29/cpufreq.c b/arch/arm/mach-rk29/cpufreq.c index 907eaa15409b..a1a737d92b9d 100755 --- a/arch/arm/mach-rk29/cpufreq.c +++ b/arch/arm/mach-rk29/cpufreq.c @@ -13,11 +13,26 @@ * */ +#ifdef CONFIG_CPU_FREQ_DEBUG +#define DEBUG +#endif +#define pr_fmt(fmt) "cpufreq: %s: " fmt, __func__ + #include #include #include #include #include +#include + +#define SLEEP_FREQ (800 * 1000) /* Use 800MHz when entering sleep */ + +/* additional symantics for "relation" in cpufreq with pm */ +#define DISABLE_FURTHER_CPUFREQ 0x10 +#define ENABLE_FURTHER_CPUFREQ 0x20 +#define MASK_FURTHER_CPUFREQ 0x30 +/* With 0x00(NOCHANGE), it depends on the previous "further" status */ +static int no_cpufreq_access; static struct cpufreq_frequency_table freq_table[] = { // { .index = 950000, .frequency = 204000 }, @@ -46,8 +61,28 @@ static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int targe if (policy->cpu != 0) return -EINVAL; + + if ((relation & ENABLE_FURTHER_CPUFREQ) && + (relation & DISABLE_FURTHER_CPUFREQ)) { + /* Invalidate both if both marked */ + relation &= ~ENABLE_FURTHER_CPUFREQ; + relation &= ~DISABLE_FURTHER_CPUFREQ; + pr_err("denied marking FURTHER_CPUFREQ as both marked.\n"); + } + if (relation & ENABLE_FURTHER_CPUFREQ) + no_cpufreq_access--; + if (no_cpufreq_access) { +#ifdef CONFIG_PM_VERBOSE + pr_err("denied access to %s as it is disabled temporarily\n", __func__); +#endif + return -EINVAL; + } + if (relation & DISABLE_FURTHER_CPUFREQ) + no_cpufreq_access++; + relation &= ~MASK_FURTHER_CPUFREQ; + if (cpufreq_frequency_table_target(policy, freq_table, target_freq, relation, &index)) { - pr_err("cpufreq: invalid target_freq: %d\n", target_freq); + pr_err("invalid target_freq: %d\n", target_freq); return -EINVAL; } freq = &freq_table[index]; @@ -58,15 +93,13 @@ static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int targe freqs.old = policy->cur; freqs.new = freq->frequency; freqs.cpu = 0; -#ifdef CONFIG_CPU_FREQ_DEBUG - printk(KERN_DEBUG "%s %d r %d (%d-%d) selected %d (%duV)\n", __func__, target_freq, relation, policy->min, policy->max, freq->frequency, freq->index); -#endif + pr_debug("%d r %d (%d-%d) selected %d (%duV)\n", target_freq, relation, policy->min, policy->max, freq->frequency, freq->index); #ifdef CONFIG_REGULATOR if (vcore && freqs.new > freqs.old) { err = regulator_set_voltage(vcore, freq->index, freq->index); if (err) { - pr_err("cpufreq: fail to set vcore (%duV) for %dkHz: %d\n", + pr_err("fail to set vcore (%duV) for %dkHz: %d\n", freq->index, freqs.new, err); goto err_vol; } @@ -82,7 +115,7 @@ static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int targe if (vcore && freqs.new < freqs.old) { err = regulator_set_voltage(vcore, freq->index, freq->index); if (err) { - pr_err("cpufreq: fail to set vcore (%duV) for %dkHz: %d\n", + pr_err("fail to set vcore (%duV) for %dkHz: %d\n", freq->index, freqs.new, err); } } @@ -106,7 +139,7 @@ static int __init rk29_cpufreq_init(struct cpufreq_policy *policy) #ifdef CONFIG_REGULATOR vcore = regulator_get(NULL, "vcore"); if (IS_ERR(vcore)) { - pr_err("cpufreq: fail to get regulator vcore: %ld\n", PTR_ERR(vcore)); + pr_err("fail to get regulator vcore: %ld\n", PTR_ERR(vcore)); vcore = NULL; } #endif @@ -143,8 +176,35 @@ static struct cpufreq_driver rk29_cpufreq_driver = { .attr = rk29_cpufreq_attr, }; +static int rk29_cpufreq_pm_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + int ret; + + switch (event) { + case PM_SUSPEND_PREPARE: + ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, + DISABLE_FURTHER_CPUFREQ); + if (ret < 0) + return NOTIFY_BAD; + return NOTIFY_OK; + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, + ENABLE_FURTHER_CPUFREQ); + return NOTIFY_OK; + } + return NOTIFY_DONE; +} + +static struct notifier_block rk29_cpufreq_pm_notifier = { + .notifier_call = rk29_cpufreq_pm_notifier_event, +}; + static int __init rk29_cpufreq_register(void) { + register_pm_notifier(&rk29_cpufreq_pm_notifier); + return cpufreq_register_driver(&rk29_cpufreq_driver); } diff --git a/arch/arm/mach-rk29/include/mach/cru.h b/arch/arm/mach-rk29/include/mach/cru.h index 2d973a775491..cc2124324418 100644 --- a/arch/arm/mach-rk29/include/mach/cru.h +++ b/arch/arm/mach-rk29/include/mach/cru.h @@ -137,6 +137,133 @@ enum cru_clk_gate CLK_GATE_MAX, }; +enum cru_soft_reset { + SOFT_RST_ARM_CORE = 0, + SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_AXI, + SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_AHB, + SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_APB, + SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_ATB, + SOFT_RST_CPU_SYSTEM_INTERCONNECT_2, + SOFT_RST_DMA0 = 7, + SOFT_RST_GIC, + SOFT_RST_INTERNAL_MEMORY, + SOFT_RST_TZPC = 11, + SOFT_RST_ROM, + SOFT_RST_I2S0, + SOFT_RST_I2S1, + SOFT_RST_SPDIF, + SOFT_RST_UART0, + SOFT_RST_RTC, + SOFT_RST_DDR_PHY, + SOFT_RST_DDR_DLL_BYTE0, + SOFT_RST_DDR_DLL_BYTE1, + SOFT_RST_DDR_DLL_BYTE2, + SOFT_RST_DDR_DLL_BYTE3, + SOFT_RST_DDR_DLL_CMD, + SOFT_RST_DDR_CONTROLLER, + SOFT_RST_ARM_CORE_DEBUG, + SOFT_RST_DAP_DBG, + SOFT_RST_CPU_VODEC_A2A_AHB, + SOFT_RST_CPU_DISPLAY_A2A_AHB, + SOFT_RST_DAP_SYS, + + SOFT_RST_PERI_SYSTEM_INTERCONNECT_1_AXI = 32, + SOFT_RST_PERI_SYSTEM_INTERCONNECT_1_AHB, + SOFT_RST_PERI_SYSTEM_INTERCONNECT_1_APB, + SOFT_RST_PERIPH_EMEM = 32 + 4, + SOFT_RST_PERIPH_USB, + SOFT_RST_DMA1, + SOFT_RST_MAC, + SOFT_RST_HIF, + SOFT_RST_NANDC, + SOFT_RST_SMC, + SOFT_RST_HSADC, + SOFT_RST_SDMMC, + SOFT_RST_SDIO, + SOFT_RST_EMMC, + SOFT_RST_USB_OTG_2_0_AHB_BUS, + SOFT_RST_USB_OTG_2_0_PHY, + SOFT_RST_USB_OTG_2_0_CONTROLLER, + SOFT_RST_USB_HOST_2_0_AHB_BUS, + SOFT_RST_USB_HOST_2_0_PHY, + SOFT_RST_USB_HOST_2_0_CONTROLLER, + SOFT_RST_UHOST, + SOFT_RST_VIP, + SOFT_RST_VIP_MATRIX_AHB, + SOFT_RST_SPI0, + SOFT_RST_SPI1, + SOFT_RST_SARADC, + SOFT_RST_UART1, + SOFT_RST_UART2, + SOFT_RST_UART3, + SOFT_RST_PWM, + + SOFT_RST_DISPLAY_INTERCONNECTOR_AXI = 64, + SOFT_RST_DISPLAY_INTERCONNECTOR_AHB, + SOFT_RST_LCDC, + SOFT_RST_IPP, + SOFT_RST_EBC, + SOFT_RST_GPU = 64 + 7, + SOFT_RST_DDR_REG_PORT, + SOFT_RST_DDR_CPU_PORT, + SOFT_RST_PERIPH_USED_CPU_AXI, + SOFT_RST_DDR_PERIPH_PORT, + SOFT_RST_DDR_LCDC_PORT, + SOFT_RST_DDR_VCODEC_PORT = 64 + 15, + SOFT_RST_DDR_GPU_PORT, + SOFT_RST_PID_FILTER_AHB, + SOFT_RST_VCODEC_AXI_BUS, + SOFT_RST_VCODEC_AHB_BUS, + SOFT_RST_TIMER0, + SOFT_RST_TIMER1, + SOFT_RST_TIMER2, + SOFT_RST_TIMER3, + + SOFT_RST_MAX, +}; + +/* CRU MODE CON */ +#define CRU_CPU_MODE_MASK (0x03u << 0) +#define CRU_CPU_MODE_SLOW (0x00u << 0) +#define CRU_CPU_MODE_NORMAL (0x01u << 0) +#define CRU_CPU_MODE_SLOW27 (0x02u << 0) + +#define CRU_GENERAL_MODE_MASK (0x03u << 2) +#define CRU_GENERAL_MODE_SLOW (0x00u << 2) +#define CRU_GENERAL_MODE_NORMAL (0x01u << 2) +#define CRU_GENERAL_MODE_SLOW27 (0x02u << 2) + +#define CRU_CODEC_MODE_MASK (0x03u << 4) +#define CRU_CODEC_MODE_SLOW (0x00u << 4) +#define CRU_CODEC_MODE_NORMAL (0x01u << 4) +#define CRU_CODEC_MODE_SLOW27 (0x02u << 4) + +#define CRU_DDR_MODE_MASK (0x03u << 6) +#define CRU_DDR_MODE_SLOW (0x00u << 6) +#define CRU_DDR_MODE_NORMAL (0x01u << 6) +#define CRU_DDR_MODE_SLOW27 (0x02u << 6) + +/* CRU PLL CON */ +#define PLL_HIGH_BAND (0x01 << 16) +#define PLL_LOW_BAND (0x00 << 16) +#define PLL_PD (0x01 << 15) + +#define PLL_CLKR(i) ((((i) - 1) & 0x1f) << 10) +#define PLL_NR(v) ((((v) >> 10) & 0x1f) + 1) + +#define PLL_CLKF(i) ((((i) - 1) & 0x7f) << 3) +#define PLL_NF(v) ((((v) >> 3) & 0x7f) + 1) +#define PLL_NF2(v) (((((v) >> 3) & 0x7f) + 1) << 1) + +#define PLL_CLKOD(i) (((i) & 0x03) << 1) +#define PLL_NO_1 PLL_CLKOD(0) +#define PLL_NO_2 PLL_CLKOD(1) +#define PLL_NO_4 PLL_CLKOD(2) +#define PLL_NO_8 PLL_CLKOD(3) +#define PLL_NO_SHIFT(v) (((v) >> 1) & 0x03) + +#define PLL_BYPASS (0x01) + /* Register definitions */ #define CRU_APLL_CON 0x00 #define CRU_DPLL_CON 0x04 @@ -169,4 +296,24 @@ enum cru_clk_gate #define CRU_SOFTRST1_CON 0x70 #define CRU_SOFTRST2_CON 0x74 +static inline void cru_set_soft_reset(enum cru_soft_reset idx, bool on) +{ + unsigned long flags; + u32 addr = RK29_CRU_BASE + CRU_SOFTRST0_CON + ((idx >> 5) << 2); + u32 mask = 1 << (idx & 31); + u32 v; + + if (idx >= SOFT_RST_MAX) + return; + + local_irq_save(flags); + v = readl(addr); + if (on) + v |= mask; + else + v &= ~mask; + writel(v, addr); + local_irq_restore(flags); +} + #endif diff --git a/arch/arm/mach-rk29/pm.c b/arch/arm/mach-rk29/pm.c new file mode 100644 index 000000000000..f0ebc58295e8 --- /dev/null +++ b/arch/arm/mach-rk29/pm.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define cru_readl(offset) readl(RK29_CRU_BASE + offset) +#define cru_writel(v, offset) do { writel(v, RK29_CRU_BASE + offset); readl(RK29_CRU_BASE + offset); } while (0) +#define pmu_readl(offset) readl(RK29_PMU_BASE + offset) +#define pmu_writel(v, offset) do { writel(v, RK29_PMU_BASE + offset); readl(RK29_PMU_BASE + offset); } while (0) +static unsigned long save_sp; + +static inline void delay_500ns(void) +{ + int delay = 12; + while (delay--) + barrier(); +} + +static inline void delay_300us(void) +{ + int i; + for (i = 0; i < 600; i++) + delay_500ns(); +} + +static u32 apll; +static u32 lpj; +static struct regulator *vcore; +static int vcore_uV; + +extern void ddr_suspend(void); +extern void ddr_resume(void); + +static void __sramfunc rk29_pm_enter_ddr(void) +{ + u32 clksel0, dpll, mode; + + asm("dsb"); + ddr_suspend(); + + /* suspend ddr pll */ + mode = cru_readl(CRU_MODE_CON); + dpll = cru_readl(CRU_DPLL_CON); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_DDR_MODE_MASK) | CRU_DDR_MODE_SLOW, CRU_MODE_CON); + cru_writel(dpll | PLL_BYPASS, CRU_DPLL_CON); + cru_writel(dpll | PLL_PD | PLL_BYPASS, CRU_DPLL_CON); + delay_500ns(); + + /* set arm clk 24MHz/32 = 750KHz */ + clksel0 = cru_readl(CRU_CLKSEL0_CON); + cru_writel(clksel0 | 0x1F, CRU_CLKSEL0_CON); + + asm("wfi"); + + /* resume arm clk */ + cru_writel(clksel0, CRU_CLKSEL0_CON); + + /* resume ddr pll */ + cru_writel(dpll, CRU_DPLL_CON); + delay_300us(); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_DDR_MODE_MASK) | (mode & CRU_DDR_MODE_MASK), CRU_MODE_CON); + + ddr_resume(); +} + +static int rk29_pm_enter(suspend_state_t state) +{ + u32 cpll, gpll, mode; + + mode = cru_readl(CRU_MODE_CON); + + /* suspend codec pll */ + cpll = cru_readl(CRU_CPLL_CON); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | CRU_CODEC_MODE_SLOW, CRU_MODE_CON); + cru_writel(cpll | PLL_BYPASS, CRU_CPLL_CON); + cru_writel(cpll | PLL_PD | PLL_BYPASS, CRU_CPLL_CON); + delay_500ns(); + + /* suspend general pll */ + gpll = cru_readl(CRU_GPLL_CON); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_GENERAL_MODE_MASK) | CRU_GENERAL_MODE_SLOW, CRU_MODE_CON); + cru_writel(gpll | PLL_BYPASS, CRU_GPLL_CON); + cru_writel(gpll | PLL_PD | PLL_BYPASS, CRU_GPLL_CON); + delay_500ns(); + + DDR_SAVE_SP(save_sp); + rk29_pm_enter_ddr(); + DDR_RESTORE_SP(save_sp); + + /* resume general pll */ + cru_writel(gpll, CRU_GPLL_CON); + delay_300us(); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_GENERAL_MODE_MASK) | (mode & CRU_GENERAL_MODE_MASK), CRU_MODE_CON); + + /* resume codec pll */ + cru_writel(cpll, CRU_CPLL_CON); + delay_300us(); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | (mode & CRU_CODEC_MODE_MASK), CRU_MODE_CON); + + return 0; +} + +static int rk29_pm_prepare(void) +{ + printk("+%s\n", __func__); + disable_hlt(); // disable entering rk29_idle() by disable_hlt() + + /* suspend arm pll */ + apll = cru_readl(CRU_APLL_CON); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON); + cru_writel(apll | PLL_BYPASS, CRU_APLL_CON); + cru_writel(apll | PLL_PD | PLL_BYPASS, CRU_APLL_CON); + delay_500ns(); + lpj = loops_per_jiffy; + loops_per_jiffy = 120000; // make udelay/mdelay correct + + if (vcore) { + vcore_uV = regulator_get_voltage(vcore); + regulator_set_voltage(vcore, 1000000, 1000000); + } + printk("-%s\n", __func__); + return 0; +} + +static void rk29_pm_finish(void) +{ + printk("+%s\n", __func__); + if (vcore) { + regulator_set_voltage(vcore, vcore_uV, vcore_uV); + } + + /* resume arm pll */ + loops_per_jiffy = lpj; + cru_writel(apll, CRU_APLL_CON); + delay_300us(); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_NORMAL, CRU_MODE_CON); + + enable_hlt(); + printk("-%s\n", __func__); +} + +static struct platform_suspend_ops rk29_pm_ops = { + .enter = rk29_pm_enter, + .valid = suspend_valid_only_mem, + .prepare = rk29_pm_prepare, + .finish = rk29_pm_finish, +}; + +static void rk29_idle(void) +{ + if (!need_resched()) { + int allow_sleep = 1; +#ifdef CONFIG_HAS_WAKELOCK + allow_sleep = !has_wake_lock(WAKE_LOCK_IDLE); +#endif + if (allow_sleep) { + u32 mode_con = cru_readl(CRU_MODE_CON); + cru_writel((mode_con & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON); + arch_idle(); + cru_writel((mode_con & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_NORMAL, CRU_MODE_CON); + } else { + arch_idle(); + } + } + local_irq_enable(); +} + +static int __init rk29_pm_init(void) +{ + vcore = regulator_get(NULL, "vcore"); + if (IS_ERR(vcore)) { + pr_err("pm: fail to get regulator vcore: %ld\n", PTR_ERR(vcore)); + vcore = NULL; + } + + suspend_set_ops(&rk29_pm_ops); + + /* set idle function */ + pm_idle = rk29_idle; + + return 0; +} +__initcall(rk29_pm_init); -- 2.34.1