4 #include <linux/delay.h>
6 #include <linux/kernel.h>
7 #include <linux/init.h>
9 #include <linux/suspend.h>
10 #ifdef CONFIG_RK29_PWM_REGULATOR
11 #include <linux/regulator/rk29-pwm-regulator.h>
14 #include <linux/wakelock.h>
15 #include <asm/tlbflush.h>
16 #include <asm/hardware/gic.h>
18 #include <mach/rk29_iomap.h>
21 #include <mach/board.h>
22 #include <mach/system.h>
23 #include <mach/sram.h>
24 #include <mach/gpio.h>
26 #define cru_readl(offset) readl(RK29_CRU_BASE + offset)
27 #define cru_writel(v, offset) do { writel(v, RK29_CRU_BASE + offset); readl(RK29_CRU_BASE + offset); } while (0)
28 #define pmu_readl(offset) readl(RK29_PMU_BASE + offset)
29 #define pmu_writel(v, offset) do { writel(v, RK29_PMU_BASE + offset); readl(RK29_PMU_BASE + offset); } while (0)
30 static unsigned long save_sp;
32 #define LOOPS_PER_USEC 13
33 #define LOOP(loops) do { int i = loops; barrier(); while (i--) barrier(); } while (0)
35 static inline void delay_500ns(void)
40 static inline void delay_300us(void)
42 LOOP(300 * LOOPS_PER_USEC);
45 extern void ddr_suspend(void);
46 extern void ddr_resume(void);
49 static void inline printch(char byte)
55 local_irq_save(flags);
56 gate1 = cru_readl(CRU_CLKGATE1_CON);
57 gate2 = cru_readl(CRU_CLKGATE2_CON);
58 cru_writel(gate1 & ~((1 << CLK_GATE_PCLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_CPU_PERI % 32)), CRU_CLKGATE1_CON);
59 cru_writel(gate2 & ~(1 << CLK_GATE_UART1 % 32), CRU_CLKGATE2_CON);
62 writel(byte, RK29_UART1_BASE);
64 /* loop check LSR[6], Transmitter Empty bit */
65 while (!(readl(RK29_UART1_BASE + 0x14) & 0x40))
68 cru_writel(gate2, CRU_CLKGATE2_CON);
69 cru_writel(gate1, CRU_CLKGATE1_CON);
70 local_irq_restore(flags);
75 static void inline printascii(const char *s)
83 static void inline printhex(unsigned int hex)
89 unsigned char c = (hex & 0xF0000000) >> 28;
90 printch(c < 0xa ? c + '0' : c - 0xa + 'a');
95 static void inline printch(char byte) {}
96 static void inline printascii(const char *s) {}
97 static void inline printhex(unsigned int hex) {}
100 #ifdef CONFIG_RK29_PWM_REGULATOR
101 #define pwm_write_reg(addr, val) __raw_writel(val, addr + (RK29_PWM_BASE + 2*0x10))
102 #define pwm_read_reg(addr) __raw_readl(addr + (RK29_PWM_BASE + 2*0x10))
104 static u32 __sramdata pwm_lrc, pwm_hrc;
105 static void __sramfunc rk29_set_core_voltage(int uV)
109 gate1 = cru_readl(CRU_CLKGATE1_CON);
110 cru_writel(gate1 & ~((1 << CLK_GATE_PCLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_CPU_PERI % 32)), CRU_CLKGATE1_CON);
113 writel((readl(RK29_GRF_BASE + 0x58) & ~(0x3<<6)) | (0x2<<6), RK29_GRF_BASE + 0x58);
116 pwm_lrc = pwm_read_reg(PWM_REG_LRC);
117 pwm_hrc = pwm_read_reg(PWM_REG_HRC);
120 pwm_write_reg(PWM_REG_CTRL, PWM_DIV|PWM_RESET);
122 pwm_write_reg(PWM_REG_LRC, 12);
123 pwm_write_reg(PWM_REG_HRC, 10);
125 pwm_write_reg(PWM_REG_LRC, pwm_lrc);
126 pwm_write_reg(PWM_REG_HRC, pwm_hrc);
128 pwm_write_reg(PWM_REG_CNTR, 0);
129 pwm_write_reg(PWM_REG_CTRL, PWM_DIV|PWM_ENABLE|PWM_TimeEN);
131 LOOP(5 * 1000 * LOOPS_PER_USEC); /* delay 5ms */
133 cru_writel(gate1, CRU_CLKGATE1_CON);
135 #endif /* CONFIG_RK29_PWM_REGULATOR */
137 static void __sramfunc rk29_sram_suspend(void)
145 #ifdef CONFIG_RK29_PWM_REGULATOR
146 rk29_set_core_voltage(1000000);
149 clksel0 = cru_readl(CRU_CLKSEL0_CON);
150 /* set arm clk 24MHz/32 = 750KHz */
151 cru_writel(clksel0 | 0x1F, CRU_CLKSEL0_CON);
158 cru_writel(clksel0, CRU_CLKSEL0_CON);
161 #ifdef CONFIG_RK29_PWM_REGULATOR
162 rk29_set_core_voltage(0);
170 static void noinline rk29_suspend(void)
172 DDR_SAVE_SP(save_sp);
174 DDR_RESTORE_SP(save_sp);
177 static void dump_irq(void)
179 u32 irq_gpio = (readl(RK29_GICPERI_BASE + GIC_DIST_PENDING_SET + 8) >> 23) & 0x7F;
180 printk("wakeup irq: %08x %08x %01x\n",
181 readl(RK29_GICPERI_BASE + GIC_DIST_PENDING_SET + 4),
182 readl(RK29_GICPERI_BASE + GIC_DIST_PENDING_SET + 8),
183 readl(RK29_GICPERI_BASE + GIC_DIST_PENDING_SET + 12) & 0xf);
185 printk("wakeup gpio0: %08x\n", readl(RK29_GPIO0_BASE + GPIO_INT_STATUS));
187 printk("wakeup gpio1: %08x\n", readl(RK29_GPIO1_BASE + GPIO_INT_STATUS));
189 printk("wakeup gpio2: %08x\n", readl(RK29_GPIO2_BASE + GPIO_INT_STATUS));
191 printk("wakeup gpio3: %08x\n", readl(RK29_GPIO3_BASE + GPIO_INT_STATUS));
193 printk("wakeup gpio4: %08x\n", readl(RK29_GPIO4_BASE + GPIO_INT_STATUS));
195 printk("wakeup gpio5: %08x\n", readl(RK29_GPIO5_BASE + GPIO_INT_STATUS));
197 printk("wakeup gpio6: %08x\n", readl(RK29_GPIO6_BASE + GPIO_INT_STATUS));
200 static int rk29_pm_enter(suspend_state_t state)
202 u32 apll, cpll, gpll, mode, clksel0;
206 #ifdef CONFIG_RK29_PWM_REGULATOR
209 readl(RK29_PWM_BASE);
210 readl(RK29_GRF_BASE);
214 clkgate[0] = cru_readl(CRU_CLKGATE0_CON);
215 clkgate[1] = cru_readl(CRU_CLKGATE1_CON);
216 clkgate[2] = cru_readl(CRU_CLKGATE2_CON);
217 clkgate[3] = cru_clkgate3_con_mirror;
218 cru_writel(~((1 << CLK_GATE_CORE)
219 | (1 << CLK_GATE_ACLK_CPU)
220 | (1 << CLK_GATE_ACLK_CPU2)
221 | (1 << CLK_GATE_PCLK_CPU)
222 | (1 << CLK_GATE_GIC)
223 | (1 << CLK_GATE_INTMEM)
224 | (1 << CLK_GATE_DDR_PHY)
225 | (1 << CLK_GATE_DDR_REG)
226 | (1 << CLK_GATE_DDR_CPU)
227 | (1 << CLK_GATE_GPIO0)
228 | (1 << CLK_GATE_RTC)
229 | (1 << CLK_GATE_GRF)
230 ) | clkgate[0], CRU_CLKGATE0_CON);
231 cru_writel(~0, CRU_CLKGATE1_CON);
232 cru_writel(~((1 << CLK_GATE_GPIO1 % 32)
233 | (1 << CLK_GATE_GPIO2 % 32)
234 | (1 << CLK_GATE_GPIO3 % 32)
235 | (1 << CLK_GATE_GPIO4 % 32)
236 | (1 << CLK_GATE_GPIO5 % 32)
237 | (1 << CLK_GATE_GPIO6 % 32)
238 | (1 << CLK_GATE_PWM % 32)
239 ) | clkgate[2], CRU_CLKGATE2_CON);
240 cru_writel(~0, CRU_CLKGATE3_CON);
243 mode = cru_readl(CRU_MODE_CON);
244 clksel0 = cru_readl(CRU_CLKSEL0_CON);
246 /* suspend arm pll */
247 apll = cru_readl(CRU_APLL_CON);
248 cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON);
249 cru_writel(apll | PLL_BYPASS, CRU_APLL_CON);
250 cru_writel(apll | PLL_PD | PLL_BYPASS, CRU_APLL_CON);
252 /* set core = aclk_cpu = hclk_cpu = pclk_cpu = 24MHz */
253 cru_writel(clksel0 & 0xFFFFF000, CRU_CLKSEL0_CON);
256 /* suspend codec pll */
257 cpll = cru_readl(CRU_CPLL_CON);
258 cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | CRU_CODEC_MODE_SLOW, CRU_MODE_CON);
259 cru_writel(cpll | PLL_BYPASS, CRU_CPLL_CON);
260 cru_writel(cpll | PLL_PD | PLL_BYPASS, CRU_CPLL_CON);
264 /* suspend general pll */
265 gpll = cru_readl(CRU_GPLL_CON);
266 cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_GENERAL_MODE_MASK) | CRU_GENERAL_MODE_SLOW, CRU_MODE_CON);
267 cru_writel(gpll | PLL_BYPASS, CRU_GPLL_CON);
268 cru_writel(gpll | PLL_PD | PLL_BYPASS, CRU_GPLL_CON);
270 /* set aclk_periph = hclk_periph = pclk_periph = 24MHz */
271 cru_writel(clksel0 & ~0x7FC000, CRU_CLKSEL0_CON);
277 /* resume general pll */
278 cru_writel(gpll, CRU_GPLL_CON);
280 /* restore aclk_periph/hclk_periph/pclk_periph */
281 cru_writel(cru_readl(CRU_CLKSEL0_CON) | (clksel0 & 0x7FC000), CRU_CLKSEL0_CON);
282 cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_GENERAL_MODE_MASK) | (mode & CRU_GENERAL_MODE_MASK), CRU_MODE_CON);
285 /* resume codec pll */
286 cru_writel(cpll, CRU_CPLL_CON);
288 cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | (mode & CRU_CODEC_MODE_MASK), CRU_MODE_CON);
292 cru_writel(apll, CRU_APLL_CON);
294 /* restore core/aclk_cpu/hclk_cpu/pclk_cpu */
295 cru_writel(cru_readl(CRU_CLKSEL0_CON) | (clksel0 & 0xFFF), CRU_CLKSEL0_CON);
296 cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | (mode & CRU_CPU_MODE_MASK), CRU_MODE_CON);
300 cru_writel(clkgate[0], CRU_CLKGATE0_CON);
301 cru_writel(clkgate[1], CRU_CLKGATE1_CON);
302 cru_writel(clkgate[2], CRU_CLKGATE2_CON);
303 cru_writel(clkgate[3], CRU_CLKGATE3_CON);
310 static int rk29_pm_prepare(void)
312 /* disable entering rk29_idle() by disable_hlt() */
317 static void rk29_pm_finish(void)
322 static struct platform_suspend_ops rk29_pm_ops = {
323 .enter = rk29_pm_enter,
324 .valid = suspend_valid_only_mem,
325 .prepare = rk29_pm_prepare,
326 .finish = rk29_pm_finish,
329 static void rk29_idle(void)
331 if (!need_resched()) {
333 #ifdef CONFIG_HAS_WAKELOCK
334 allow_sleep = !has_wake_lock(WAKE_LOCK_IDLE);
337 u32 mode_con = cru_readl(CRU_MODE_CON);
338 cru_writel((mode_con & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON);
340 cru_writel(mode_con, CRU_MODE_CON);
348 static int __init rk29_pm_init(void)
350 suspend_set_ops(&rk29_pm_ops);
352 /* set idle function */
357 __initcall(rk29_pm_init);