1 /* linux/arch/arm/mach-s5p64x0/include/mach/pm-core.h
2  *
3  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4  *		http://www.samsung.com
5  *
6  * S5P64X0 - PM core support for arch/arm/plat-samsung/pm.c
7  *
8  * Based on PM core support for S3C64XX by Ben Dooks
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14 
15 #include <mach/regs-gpio.h>
16 
s3c_pm_debug_init_uart(void)17 static inline void s3c_pm_debug_init_uart(void)
18 {
19 	u32 tmp = __raw_readl(S5P64X0_CLK_GATE_PCLK);
20 
21 	/*
22 	 * As a note, since the S5P64X0 UARTs generally have multiple
23 	 * clock sources, we simply enable PCLK at the moment and hope
24 	 * that the resume settings for the UART are suitable for the
25 	 * use with PCLK.
26 	 */
27 	tmp |= S5P64X0_CLK_GATE_PCLK_UART0;
28 	tmp |= S5P64X0_CLK_GATE_PCLK_UART1;
29 	tmp |= S5P64X0_CLK_GATE_PCLK_UART2;
30 	tmp |= S5P64X0_CLK_GATE_PCLK_UART3;
31 
32 	__raw_writel(tmp, S5P64X0_CLK_GATE_PCLK);
33 	udelay(10);
34 }
35 
s3c_pm_arch_prepare_irqs(void)36 static inline void s3c_pm_arch_prepare_irqs(void)
37 {
38 	/* VIC should have already been taken care of */
39 
40 	/* clear any pending EINT0 interrupts */
41 	__raw_writel(__raw_readl(S5P64X0_EINT0PEND), S5P64X0_EINT0PEND);
42 }
43 
s3c_pm_arch_stop_clocks(void)44 static inline void s3c_pm_arch_stop_clocks(void) { }
s3c_pm_arch_show_resume_irqs(void)45 static inline void s3c_pm_arch_show_resume_irqs(void) { }
46 
47 /*
48  * make these defines, we currently do not have any need to change
49  * the IRQ wake controls depending on the CPU we are running on
50  */
51 #define s3c_irqwake_eintallow	((1 << 16) - 1)
52 #define s3c_irqwake_intallow	(~0)
53 
s3c_pm_arch_update_uart(void __iomem * regs,struct pm_uart_save * save)54 static inline void s3c_pm_arch_update_uart(void __iomem *regs,
55 					struct pm_uart_save *save)
56 {
57 	u32 ucon = __raw_readl(regs + S3C2410_UCON);
58 	u32 ucon_clk = ucon & S3C6400_UCON_CLKMASK;
59 	u32 save_clk = save->ucon & S3C6400_UCON_CLKMASK;
60 	u32 new_ucon;
61 	u32 delta;
62 
63 	/*
64 	 * S5P64X0 UART blocks only support level interrupts, so ensure that
65 	 * when we restore unused UART blocks we force the level interrupt
66 	 * settings.
67 	 */
68 	save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL;
69 
70 	/*
71 	 * We have a constraint on changing the clock type of the UART
72 	 * between UCLKx and PCLK, so ensure that when we restore UCON
73 	 * that the CLK field is correctly modified if the bootloader
74 	 * has changed anything.
75 	 */
76 	if (ucon_clk != save_clk) {
77 		new_ucon = save->ucon;
78 		delta = ucon_clk ^ save_clk;
79 
80 		/*
81 		 * change from UCLKx => wrong PCLK,
82 		 * either UCLK can be tested for by a bit-test
83 		 * with UCLK0
84 		 */
85 		if (ucon_clk & S3C6400_UCON_UCLK0 &&
86 		!(save_clk & S3C6400_UCON_UCLK0) &&
87 		delta & S3C6400_UCON_PCLK2) {
88 			new_ucon &= ~S3C6400_UCON_UCLK0;
89 		} else if (delta == S3C6400_UCON_PCLK2) {
90 			/*
91 			 * as a precaution, don't change from
92 			 * PCLK2 => PCLK or vice-versa
93 			 */
94 			new_ucon ^= S3C6400_UCON_PCLK2;
95 		}
96 
97 		S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n",
98 			ucon, new_ucon, save->ucon);
99 		save->ucon = new_ucon;
100 	}
101 }
102 
s3c_pm_restored_gpios(void)103 static inline void s3c_pm_restored_gpios(void)
104 {
105 	/* ensure sleep mode has been cleared from the system */
106 	__raw_writel(0, S5P64X0_SLPEN);
107 }
108 
samsung_pm_saved_gpios(void)109 static inline void samsung_pm_saved_gpios(void)
110 {
111 	/*
112 	 * turn on the sleep mode and keep it there, as it seems that during
113 	 * suspend the xCON registers get re-set and thus you can end up with
114 	 * problems between going to sleep and resuming.
115 	 */
116 	__raw_writel(S5P64X0_SLPEN_USE_xSLP, S5P64X0_SLPEN);
117 }
118