xref: /OK3568_Linux_fs/kernel/arch/arm/mach-omap1/pm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * linux/arch/arm/mach-omap1/pm.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * OMAP Power Management Routines
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Original code for the SA11x0:
7*4882a593Smuzhiyun  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Modified for the PXA250 by Nicolas Pitre:
10*4882a593Smuzhiyun  * Copyright (c) 2002 Monta Vista Software, Inc.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Modified for the OMAP1510 by David Singleton:
13*4882a593Smuzhiyun  * Copyright (c) 2002 Monta Vista Software, Inc.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify it
18*4882a593Smuzhiyun  * under the terms of the GNU General Public License as published by the
19*4882a593Smuzhiyun  * Free Software Foundation; either version 2 of the License, or (at your
20*4882a593Smuzhiyun  * option) any later version.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
23*4882a593Smuzhiyun  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24*4882a593Smuzhiyun  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
25*4882a593Smuzhiyun  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26*4882a593Smuzhiyun  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27*4882a593Smuzhiyun  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28*4882a593Smuzhiyun  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29*4882a593Smuzhiyun  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31*4882a593Smuzhiyun  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License along
34*4882a593Smuzhiyun  * with this program; if not, write to the Free Software Foundation, Inc.,
35*4882a593Smuzhiyun  * 675 Mass Ave, Cambridge, MA 02139, USA.
36*4882a593Smuzhiyun  */
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include <linux/suspend.h>
39*4882a593Smuzhiyun #include <linux/sched.h>
40*4882a593Smuzhiyun #include <linux/debugfs.h>
41*4882a593Smuzhiyun #include <linux/seq_file.h>
42*4882a593Smuzhiyun #include <linux/interrupt.h>
43*4882a593Smuzhiyun #include <linux/sysfs.h>
44*4882a593Smuzhiyun #include <linux/module.h>
45*4882a593Smuzhiyun #include <linux/io.h>
46*4882a593Smuzhiyun #include <linux/atomic.h>
47*4882a593Smuzhiyun #include <linux/cpu.h>
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #include <asm/fncpy.h>
50*4882a593Smuzhiyun #include <asm/system_misc.h>
51*4882a593Smuzhiyun #include <asm/irq.h>
52*4882a593Smuzhiyun #include <asm/mach/time.h>
53*4882a593Smuzhiyun #include <asm/mach/irq.h>
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #include <mach/tc.h>
56*4882a593Smuzhiyun #include <mach/mux.h>
57*4882a593Smuzhiyun #include <linux/omap-dma.h>
58*4882a593Smuzhiyun #include <clocksource/timer-ti-dm.h>
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #include <mach/irqs.h>
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #include "iomap.h"
63*4882a593Smuzhiyun #include "clock.h"
64*4882a593Smuzhiyun #include "pm.h"
65*4882a593Smuzhiyun #include "soc.h"
66*4882a593Smuzhiyun #include "sram.h"
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
69*4882a593Smuzhiyun static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
70*4882a593Smuzhiyun static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
71*4882a593Smuzhiyun static unsigned int mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_SIZE];
72*4882a593Smuzhiyun static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
73*4882a593Smuzhiyun static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun static unsigned short enable_dyn_sleep;
76*4882a593Smuzhiyun 
idle_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)77*4882a593Smuzhiyun static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
78*4882a593Smuzhiyun 			 char *buf)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	return sprintf(buf, "%hu\n", enable_dyn_sleep);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
idle_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t n)83*4882a593Smuzhiyun static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
84*4882a593Smuzhiyun 			  const char * buf, size_t n)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	unsigned short value;
87*4882a593Smuzhiyun 	if (sscanf(buf, "%hu", &value) != 1 ||
88*4882a593Smuzhiyun 	    (value != 0 && value != 1) ||
89*4882a593Smuzhiyun 	    (value != 0 && !IS_ENABLED(CONFIG_OMAP_32K_TIMER))) {
90*4882a593Smuzhiyun 		pr_err("idle_sleep_store: Invalid value\n");
91*4882a593Smuzhiyun 		return -EINVAL;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 	enable_dyn_sleep = value;
94*4882a593Smuzhiyun 	return n;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun static struct kobj_attribute sleep_while_idle_attr =
98*4882a593Smuzhiyun 	__ATTR(sleep_while_idle, 0644, idle_show, idle_store);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * Let's power down on idle, but only if we are really
105*4882a593Smuzhiyun  * idle, because once we start down the path of
106*4882a593Smuzhiyun  * going idle we continue to do idle even if we get
107*4882a593Smuzhiyun  * a clock tick interrupt . .
108*4882a593Smuzhiyun  */
omap1_pm_idle(void)109*4882a593Smuzhiyun void omap1_pm_idle(void)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	extern __u32 arm_idlect1_mask;
112*4882a593Smuzhiyun 	__u32 use_idlect1 = arm_idlect1_mask;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	local_fiq_disable();
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun #if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER)
117*4882a593Smuzhiyun 	use_idlect1 = use_idlect1 & ~(1 << 9);
118*4882a593Smuzhiyun #endif
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun #ifdef CONFIG_OMAP_DM_TIMER
121*4882a593Smuzhiyun 	use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
122*4882a593Smuzhiyun #endif
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	if (omap_dma_running())
125*4882a593Smuzhiyun 		use_idlect1 &= ~(1 << 6);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/*
128*4882a593Smuzhiyun 	 * We should be able to remove the do_sleep variable and multiple
129*4882a593Smuzhiyun 	 * tests above as soon as drivers, timer and DMA code have been fixed.
130*4882a593Smuzhiyun 	 * Even the sleep block count should become obsolete.
131*4882a593Smuzhiyun 	 */
132*4882a593Smuzhiyun 	if ((use_idlect1 != ~0) || !enable_dyn_sleep) {
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 		__u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
135*4882a593Smuzhiyun 		if (cpu_is_omap15xx())
136*4882a593Smuzhiyun 			use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
137*4882a593Smuzhiyun 		else
138*4882a593Smuzhiyun 			use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
139*4882a593Smuzhiyun 		omap_writel(use_idlect1, ARM_IDLECT1);
140*4882a593Smuzhiyun 		__asm__ volatile ("mcr	p15, 0, r0, c7, c0, 4");
141*4882a593Smuzhiyun 		omap_writel(saved_idlect1, ARM_IDLECT1);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 		local_fiq_enable();
144*4882a593Smuzhiyun 		return;
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 	omap_sram_suspend(omap_readl(ARM_IDLECT1),
147*4882a593Smuzhiyun 			  omap_readl(ARM_IDLECT2));
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	local_fiq_enable();
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun /*
153*4882a593Smuzhiyun  * Configuration of the wakeup event is board specific. For the
154*4882a593Smuzhiyun  * moment we put it into this helper function. Later it may move
155*4882a593Smuzhiyun  * to board specific files.
156*4882a593Smuzhiyun  */
omap_pm_wakeup_setup(void)157*4882a593Smuzhiyun static void omap_pm_wakeup_setup(void)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	u32 level1_wake = 0;
160*4882a593Smuzhiyun 	u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	/*
163*4882a593Smuzhiyun 	 * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
164*4882a593Smuzhiyun 	 * and the L2 wakeup interrupts: keypad and UART2. Note that the
165*4882a593Smuzhiyun 	 * drivers must still separately call omap_set_gpio_wakeup() to
166*4882a593Smuzhiyun 	 * wake up to a GPIO interrupt.
167*4882a593Smuzhiyun 	 */
168*4882a593Smuzhiyun 	if (cpu_is_omap7xx())
169*4882a593Smuzhiyun 		level1_wake = OMAP_IRQ_BIT(INT_7XX_GPIO_BANK1) |
170*4882a593Smuzhiyun 			OMAP_IRQ_BIT(INT_7XX_IH2_IRQ);
171*4882a593Smuzhiyun 	else if (cpu_is_omap15xx())
172*4882a593Smuzhiyun 		level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
173*4882a593Smuzhiyun 			OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
174*4882a593Smuzhiyun 	else if (cpu_is_omap16xx())
175*4882a593Smuzhiyun 		level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
176*4882a593Smuzhiyun 			OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	omap_writel(~level1_wake, OMAP_IH1_MIR);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (cpu_is_omap7xx()) {
181*4882a593Smuzhiyun 		omap_writel(~level2_wake, OMAP_IH2_0_MIR);
182*4882a593Smuzhiyun 		omap_writel(~(OMAP_IRQ_BIT(INT_7XX_WAKE_UP_REQ) |
183*4882a593Smuzhiyun 				OMAP_IRQ_BIT(INT_7XX_MPUIO_KEYPAD)),
184*4882a593Smuzhiyun 				OMAP_IH2_1_MIR);
185*4882a593Smuzhiyun 	} else if (cpu_is_omap15xx()) {
186*4882a593Smuzhiyun 		level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
187*4882a593Smuzhiyun 		omap_writel(~level2_wake,  OMAP_IH2_MIR);
188*4882a593Smuzhiyun 	} else if (cpu_is_omap16xx()) {
189*4882a593Smuzhiyun 		level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
190*4882a593Smuzhiyun 		omap_writel(~level2_wake, OMAP_IH2_0_MIR);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		/* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
193*4882a593Smuzhiyun 		omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ),
194*4882a593Smuzhiyun 			    OMAP_IH2_1_MIR);
195*4882a593Smuzhiyun 		omap_writel(~0x0, OMAP_IH2_2_MIR);
196*4882a593Smuzhiyun 		omap_writel(~0x0, OMAP_IH2_3_MIR);
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/*  New IRQ agreement, recalculate in cascade order */
200*4882a593Smuzhiyun 	omap_writel(1, OMAP_IH2_CONTROL);
201*4882a593Smuzhiyun 	omap_writel(1, OMAP_IH1_CONTROL);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun #define EN_DSPCK	13	/* ARM_CKCTL */
205*4882a593Smuzhiyun #define EN_APICK	6	/* ARM_IDLECT2 */
206*4882a593Smuzhiyun #define DSP_EN		1	/* ARM_RSTCT1 */
207*4882a593Smuzhiyun 
omap1_pm_suspend(void)208*4882a593Smuzhiyun void omap1_pm_suspend(void)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	unsigned long arg0 = 0, arg1 = 0;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	printk(KERN_INFO "PM: OMAP%x is trying to enter deep sleep...\n",
213*4882a593Smuzhiyun 		omap_rev());
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	omap_serial_wake_trigger(1);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	if (!cpu_is_omap15xx())
218*4882a593Smuzhiyun 		omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/*
221*4882a593Smuzhiyun 	 * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
222*4882a593Smuzhiyun 	 */
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	local_irq_disable();
225*4882a593Smuzhiyun 	local_fiq_disable();
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	/*
228*4882a593Smuzhiyun 	 * Step 2: save registers
229*4882a593Smuzhiyun 	 *
230*4882a593Smuzhiyun 	 * The omap is a strange/beautiful device. The caches, memory
231*4882a593Smuzhiyun 	 * and register state are preserved across power saves.
232*4882a593Smuzhiyun 	 * We have to save and restore very little register state to
233*4882a593Smuzhiyun 	 * idle the omap.
234*4882a593Smuzhiyun          *
235*4882a593Smuzhiyun 	 * Save interrupt, MPUI, ARM and UPLD control registers.
236*4882a593Smuzhiyun 	 */
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	if (cpu_is_omap7xx()) {
239*4882a593Smuzhiyun 		MPUI7XX_SAVE(OMAP_IH1_MIR);
240*4882a593Smuzhiyun 		MPUI7XX_SAVE(OMAP_IH2_0_MIR);
241*4882a593Smuzhiyun 		MPUI7XX_SAVE(OMAP_IH2_1_MIR);
242*4882a593Smuzhiyun 		MPUI7XX_SAVE(MPUI_CTRL);
243*4882a593Smuzhiyun 		MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
244*4882a593Smuzhiyun 		MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
245*4882a593Smuzhiyun 		MPUI7XX_SAVE(EMIFS_CONFIG);
246*4882a593Smuzhiyun 		MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	} else if (cpu_is_omap15xx()) {
249*4882a593Smuzhiyun 		MPUI1510_SAVE(OMAP_IH1_MIR);
250*4882a593Smuzhiyun 		MPUI1510_SAVE(OMAP_IH2_MIR);
251*4882a593Smuzhiyun 		MPUI1510_SAVE(MPUI_CTRL);
252*4882a593Smuzhiyun 		MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
253*4882a593Smuzhiyun 		MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
254*4882a593Smuzhiyun 		MPUI1510_SAVE(EMIFS_CONFIG);
255*4882a593Smuzhiyun 		MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
256*4882a593Smuzhiyun 	} else if (cpu_is_omap16xx()) {
257*4882a593Smuzhiyun 		MPUI1610_SAVE(OMAP_IH1_MIR);
258*4882a593Smuzhiyun 		MPUI1610_SAVE(OMAP_IH2_0_MIR);
259*4882a593Smuzhiyun 		MPUI1610_SAVE(OMAP_IH2_1_MIR);
260*4882a593Smuzhiyun 		MPUI1610_SAVE(OMAP_IH2_2_MIR);
261*4882a593Smuzhiyun 		MPUI1610_SAVE(OMAP_IH2_3_MIR);
262*4882a593Smuzhiyun 		MPUI1610_SAVE(MPUI_CTRL);
263*4882a593Smuzhiyun 		MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
264*4882a593Smuzhiyun 		MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
265*4882a593Smuzhiyun 		MPUI1610_SAVE(EMIFS_CONFIG);
266*4882a593Smuzhiyun 		MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
267*4882a593Smuzhiyun 	}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	ARM_SAVE(ARM_CKCTL);
270*4882a593Smuzhiyun 	ARM_SAVE(ARM_IDLECT1);
271*4882a593Smuzhiyun 	ARM_SAVE(ARM_IDLECT2);
272*4882a593Smuzhiyun 	if (!(cpu_is_omap15xx()))
273*4882a593Smuzhiyun 		ARM_SAVE(ARM_IDLECT3);
274*4882a593Smuzhiyun 	ARM_SAVE(ARM_EWUPCT);
275*4882a593Smuzhiyun 	ARM_SAVE(ARM_RSTCT1);
276*4882a593Smuzhiyun 	ARM_SAVE(ARM_RSTCT2);
277*4882a593Smuzhiyun 	ARM_SAVE(ARM_SYSST);
278*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_CLOCK_CTRL);
279*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_STATUS_REQ);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	/* (Step 3 removed - we now allow deep sleep by default) */
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/*
284*4882a593Smuzhiyun 	 * Step 4: OMAP DSP Shutdown
285*4882a593Smuzhiyun 	 */
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	/* stop DSP */
288*4882a593Smuzhiyun 	omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 		/* shut down dsp_ck */
291*4882a593Smuzhiyun 	if (!cpu_is_omap7xx())
292*4882a593Smuzhiyun 		omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* temporarily enabling api_ck to access DSP registers */
295*4882a593Smuzhiyun 	omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	/* save DSP registers */
298*4882a593Smuzhiyun 	DSP_SAVE(DSP_IDLECT2);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	/* Stop all DSP domain clocks */
301*4882a593Smuzhiyun 	__raw_writew(0, DSP_IDLECT2);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	/*
304*4882a593Smuzhiyun 	 * Step 5: Wakeup Event Setup
305*4882a593Smuzhiyun 	 */
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	omap_pm_wakeup_setup();
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	/*
310*4882a593Smuzhiyun 	 * Step 6: ARM and Traffic controller shutdown
311*4882a593Smuzhiyun 	 */
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	/* disable ARM watchdog */
314*4882a593Smuzhiyun 	omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
315*4882a593Smuzhiyun 	omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	/*
318*4882a593Smuzhiyun 	 * Step 6b: ARM and Traffic controller shutdown
319*4882a593Smuzhiyun 	 *
320*4882a593Smuzhiyun 	 * Step 6 continues here. Prepare jump to power management
321*4882a593Smuzhiyun 	 * assembly code in internal SRAM.
322*4882a593Smuzhiyun 	 *
323*4882a593Smuzhiyun 	 * Since the omap_cpu_suspend routine has been copied to
324*4882a593Smuzhiyun 	 * SRAM, we'll do an indirect procedure call to it and pass the
325*4882a593Smuzhiyun 	 * contents of arm_idlect1 and arm_idlect2 so it can restore
326*4882a593Smuzhiyun 	 * them when it wakes up and it will return.
327*4882a593Smuzhiyun 	 */
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
330*4882a593Smuzhiyun 	arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/*
333*4882a593Smuzhiyun 	 * Step 6c: ARM and Traffic controller shutdown
334*4882a593Smuzhiyun 	 *
335*4882a593Smuzhiyun 	 * Jump to assembly code. The processor will stay there
336*4882a593Smuzhiyun 	 * until wake up.
337*4882a593Smuzhiyun 	 */
338*4882a593Smuzhiyun 	omap_sram_suspend(arg0, arg1);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	/*
341*4882a593Smuzhiyun 	 * If we are here, processor is woken up!
342*4882a593Smuzhiyun 	 */
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	/*
345*4882a593Smuzhiyun 	 * Restore DSP clocks
346*4882a593Smuzhiyun 	 */
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* again temporarily enabling api_ck to access DSP registers */
349*4882a593Smuzhiyun 	omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	/* Restore DSP domain clocks */
352*4882a593Smuzhiyun 	DSP_RESTORE(DSP_IDLECT2);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	/*
355*4882a593Smuzhiyun 	 * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
356*4882a593Smuzhiyun 	 */
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if (!(cpu_is_omap15xx()))
359*4882a593Smuzhiyun 		ARM_RESTORE(ARM_IDLECT3);
360*4882a593Smuzhiyun 	ARM_RESTORE(ARM_CKCTL);
361*4882a593Smuzhiyun 	ARM_RESTORE(ARM_EWUPCT);
362*4882a593Smuzhiyun 	ARM_RESTORE(ARM_RSTCT1);
363*4882a593Smuzhiyun 	ARM_RESTORE(ARM_RSTCT2);
364*4882a593Smuzhiyun 	ARM_RESTORE(ARM_SYSST);
365*4882a593Smuzhiyun 	ULPD_RESTORE(ULPD_CLOCK_CTRL);
366*4882a593Smuzhiyun 	ULPD_RESTORE(ULPD_STATUS_REQ);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (cpu_is_omap7xx()) {
369*4882a593Smuzhiyun 		MPUI7XX_RESTORE(EMIFS_CONFIG);
370*4882a593Smuzhiyun 		MPUI7XX_RESTORE(EMIFF_SDRAM_CONFIG);
371*4882a593Smuzhiyun 		MPUI7XX_RESTORE(OMAP_IH1_MIR);
372*4882a593Smuzhiyun 		MPUI7XX_RESTORE(OMAP_IH2_0_MIR);
373*4882a593Smuzhiyun 		MPUI7XX_RESTORE(OMAP_IH2_1_MIR);
374*4882a593Smuzhiyun 	} else if (cpu_is_omap15xx()) {
375*4882a593Smuzhiyun 		MPUI1510_RESTORE(MPUI_CTRL);
376*4882a593Smuzhiyun 		MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
377*4882a593Smuzhiyun 		MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
378*4882a593Smuzhiyun 		MPUI1510_RESTORE(EMIFS_CONFIG);
379*4882a593Smuzhiyun 		MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
380*4882a593Smuzhiyun 		MPUI1510_RESTORE(OMAP_IH1_MIR);
381*4882a593Smuzhiyun 		MPUI1510_RESTORE(OMAP_IH2_MIR);
382*4882a593Smuzhiyun 	} else if (cpu_is_omap16xx()) {
383*4882a593Smuzhiyun 		MPUI1610_RESTORE(MPUI_CTRL);
384*4882a593Smuzhiyun 		MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
385*4882a593Smuzhiyun 		MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
386*4882a593Smuzhiyun 		MPUI1610_RESTORE(EMIFS_CONFIG);
387*4882a593Smuzhiyun 		MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 		MPUI1610_RESTORE(OMAP_IH1_MIR);
390*4882a593Smuzhiyun 		MPUI1610_RESTORE(OMAP_IH2_0_MIR);
391*4882a593Smuzhiyun 		MPUI1610_RESTORE(OMAP_IH2_1_MIR);
392*4882a593Smuzhiyun 		MPUI1610_RESTORE(OMAP_IH2_2_MIR);
393*4882a593Smuzhiyun 		MPUI1610_RESTORE(OMAP_IH2_3_MIR);
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	if (!cpu_is_omap15xx())
397*4882a593Smuzhiyun 		omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/*
400*4882a593Smuzhiyun 	 * Re-enable interrupts
401*4882a593Smuzhiyun 	 */
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	local_irq_enable();
404*4882a593Smuzhiyun 	local_fiq_enable();
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	omap_serial_wake_trigger(0);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	printk(KERN_INFO "PM: OMAP%x is re-starting from deep sleep...\n",
409*4882a593Smuzhiyun 		omap_rev());
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
413*4882a593Smuzhiyun /*
414*4882a593Smuzhiyun  * Read system PM registers for debugging
415*4882a593Smuzhiyun  */
omap_pm_debug_show(struct seq_file * m,void * v)416*4882a593Smuzhiyun static int omap_pm_debug_show(struct seq_file *m, void *v)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	ARM_SAVE(ARM_CKCTL);
419*4882a593Smuzhiyun 	ARM_SAVE(ARM_IDLECT1);
420*4882a593Smuzhiyun 	ARM_SAVE(ARM_IDLECT2);
421*4882a593Smuzhiyun 	if (!(cpu_is_omap15xx()))
422*4882a593Smuzhiyun 		ARM_SAVE(ARM_IDLECT3);
423*4882a593Smuzhiyun 	ARM_SAVE(ARM_EWUPCT);
424*4882a593Smuzhiyun 	ARM_SAVE(ARM_RSTCT1);
425*4882a593Smuzhiyun 	ARM_SAVE(ARM_RSTCT2);
426*4882a593Smuzhiyun 	ARM_SAVE(ARM_SYSST);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_IT_STATUS);
429*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_CLOCK_CTRL);
430*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_SOFT_REQ);
431*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_STATUS_REQ);
432*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_DPLL_CTRL);
433*4882a593Smuzhiyun 	ULPD_SAVE(ULPD_POWER_CTRL);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if (cpu_is_omap7xx()) {
436*4882a593Smuzhiyun 		MPUI7XX_SAVE(MPUI_CTRL);
437*4882a593Smuzhiyun 		MPUI7XX_SAVE(MPUI_DSP_STATUS);
438*4882a593Smuzhiyun 		MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
439*4882a593Smuzhiyun 		MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
440*4882a593Smuzhiyun 		MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);
441*4882a593Smuzhiyun 		MPUI7XX_SAVE(EMIFS_CONFIG);
442*4882a593Smuzhiyun 	} else if (cpu_is_omap15xx()) {
443*4882a593Smuzhiyun 		MPUI1510_SAVE(MPUI_CTRL);
444*4882a593Smuzhiyun 		MPUI1510_SAVE(MPUI_DSP_STATUS);
445*4882a593Smuzhiyun 		MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
446*4882a593Smuzhiyun 		MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
447*4882a593Smuzhiyun 		MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
448*4882a593Smuzhiyun 		MPUI1510_SAVE(EMIFS_CONFIG);
449*4882a593Smuzhiyun 	} else if (cpu_is_omap16xx()) {
450*4882a593Smuzhiyun 		MPUI1610_SAVE(MPUI_CTRL);
451*4882a593Smuzhiyun 		MPUI1610_SAVE(MPUI_DSP_STATUS);
452*4882a593Smuzhiyun 		MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
453*4882a593Smuzhiyun 		MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
454*4882a593Smuzhiyun 		MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
455*4882a593Smuzhiyun 		MPUI1610_SAVE(EMIFS_CONFIG);
456*4882a593Smuzhiyun 	}
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	seq_printf(m,
459*4882a593Smuzhiyun 		   "ARM_CKCTL_REG:            0x%-8x     \n"
460*4882a593Smuzhiyun 		   "ARM_IDLECT1_REG:          0x%-8x     \n"
461*4882a593Smuzhiyun 		   "ARM_IDLECT2_REG:          0x%-8x     \n"
462*4882a593Smuzhiyun 		   "ARM_IDLECT3_REG:	      0x%-8x     \n"
463*4882a593Smuzhiyun 		   "ARM_EWUPCT_REG:           0x%-8x     \n"
464*4882a593Smuzhiyun 		   "ARM_RSTCT1_REG:           0x%-8x     \n"
465*4882a593Smuzhiyun 		   "ARM_RSTCT2_REG:           0x%-8x     \n"
466*4882a593Smuzhiyun 		   "ARM_SYSST_REG:            0x%-8x     \n"
467*4882a593Smuzhiyun 		   "ULPD_IT_STATUS_REG:       0x%-4x     \n"
468*4882a593Smuzhiyun 		   "ULPD_CLOCK_CTRL_REG:      0x%-4x     \n"
469*4882a593Smuzhiyun 		   "ULPD_SOFT_REQ_REG:        0x%-4x     \n"
470*4882a593Smuzhiyun 		   "ULPD_DPLL_CTRL_REG:       0x%-4x     \n"
471*4882a593Smuzhiyun 		   "ULPD_STATUS_REQ_REG:      0x%-4x     \n"
472*4882a593Smuzhiyun 		   "ULPD_POWER_CTRL_REG:      0x%-4x     \n",
473*4882a593Smuzhiyun 		   ARM_SHOW(ARM_CKCTL),
474*4882a593Smuzhiyun 		   ARM_SHOW(ARM_IDLECT1),
475*4882a593Smuzhiyun 		   ARM_SHOW(ARM_IDLECT2),
476*4882a593Smuzhiyun 		   ARM_SHOW(ARM_IDLECT3),
477*4882a593Smuzhiyun 		   ARM_SHOW(ARM_EWUPCT),
478*4882a593Smuzhiyun 		   ARM_SHOW(ARM_RSTCT1),
479*4882a593Smuzhiyun 		   ARM_SHOW(ARM_RSTCT2),
480*4882a593Smuzhiyun 		   ARM_SHOW(ARM_SYSST),
481*4882a593Smuzhiyun 		   ULPD_SHOW(ULPD_IT_STATUS),
482*4882a593Smuzhiyun 		   ULPD_SHOW(ULPD_CLOCK_CTRL),
483*4882a593Smuzhiyun 		   ULPD_SHOW(ULPD_SOFT_REQ),
484*4882a593Smuzhiyun 		   ULPD_SHOW(ULPD_DPLL_CTRL),
485*4882a593Smuzhiyun 		   ULPD_SHOW(ULPD_STATUS_REQ),
486*4882a593Smuzhiyun 		   ULPD_SHOW(ULPD_POWER_CTRL));
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	if (cpu_is_omap7xx()) {
489*4882a593Smuzhiyun 		seq_printf(m,
490*4882a593Smuzhiyun 			   "MPUI7XX_CTRL_REG	     0x%-8x \n"
491*4882a593Smuzhiyun 			   "MPUI7XX_DSP_STATUS_REG:      0x%-8x \n"
492*4882a593Smuzhiyun 			   "MPUI7XX_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
493*4882a593Smuzhiyun 			   "MPUI7XX_DSP_API_CONFIG_REG:  0x%-8x \n"
494*4882a593Smuzhiyun 			   "MPUI7XX_SDRAM_CONFIG_REG:    0x%-8x \n"
495*4882a593Smuzhiyun 			   "MPUI7XX_EMIFS_CONFIG_REG:    0x%-8x \n",
496*4882a593Smuzhiyun 			   MPUI7XX_SHOW(MPUI_CTRL),
497*4882a593Smuzhiyun 			   MPUI7XX_SHOW(MPUI_DSP_STATUS),
498*4882a593Smuzhiyun 			   MPUI7XX_SHOW(MPUI_DSP_BOOT_CONFIG),
499*4882a593Smuzhiyun 			   MPUI7XX_SHOW(MPUI_DSP_API_CONFIG),
500*4882a593Smuzhiyun 			   MPUI7XX_SHOW(EMIFF_SDRAM_CONFIG),
501*4882a593Smuzhiyun 			   MPUI7XX_SHOW(EMIFS_CONFIG));
502*4882a593Smuzhiyun 	} else if (cpu_is_omap15xx()) {
503*4882a593Smuzhiyun 		seq_printf(m,
504*4882a593Smuzhiyun 			   "MPUI1510_CTRL_REG             0x%-8x \n"
505*4882a593Smuzhiyun 			   "MPUI1510_DSP_STATUS_REG:      0x%-8x \n"
506*4882a593Smuzhiyun 			   "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
507*4882a593Smuzhiyun 			   "MPUI1510_DSP_API_CONFIG_REG:  0x%-8x \n"
508*4882a593Smuzhiyun 			   "MPUI1510_SDRAM_CONFIG_REG:    0x%-8x \n"
509*4882a593Smuzhiyun 			   "MPUI1510_EMIFS_CONFIG_REG:    0x%-8x \n",
510*4882a593Smuzhiyun 			   MPUI1510_SHOW(MPUI_CTRL),
511*4882a593Smuzhiyun 			   MPUI1510_SHOW(MPUI_DSP_STATUS),
512*4882a593Smuzhiyun 			   MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
513*4882a593Smuzhiyun 			   MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
514*4882a593Smuzhiyun 			   MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
515*4882a593Smuzhiyun 			   MPUI1510_SHOW(EMIFS_CONFIG));
516*4882a593Smuzhiyun 	} else if (cpu_is_omap16xx()) {
517*4882a593Smuzhiyun 		seq_printf(m,
518*4882a593Smuzhiyun 			   "MPUI1610_CTRL_REG             0x%-8x \n"
519*4882a593Smuzhiyun 			   "MPUI1610_DSP_STATUS_REG:      0x%-8x \n"
520*4882a593Smuzhiyun 			   "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
521*4882a593Smuzhiyun 			   "MPUI1610_DSP_API_CONFIG_REG:  0x%-8x \n"
522*4882a593Smuzhiyun 			   "MPUI1610_SDRAM_CONFIG_REG:    0x%-8x \n"
523*4882a593Smuzhiyun 			   "MPUI1610_EMIFS_CONFIG_REG:    0x%-8x \n",
524*4882a593Smuzhiyun 			   MPUI1610_SHOW(MPUI_CTRL),
525*4882a593Smuzhiyun 			   MPUI1610_SHOW(MPUI_DSP_STATUS),
526*4882a593Smuzhiyun 			   MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
527*4882a593Smuzhiyun 			   MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
528*4882a593Smuzhiyun 			   MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
529*4882a593Smuzhiyun 			   MPUI1610_SHOW(EMIFS_CONFIG));
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	return 0;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun DEFINE_SHOW_ATTRIBUTE(omap_pm_debug);
536*4882a593Smuzhiyun 
omap_pm_init_debugfs(void)537*4882a593Smuzhiyun static void omap_pm_init_debugfs(void)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	struct dentry *d;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	d = debugfs_create_dir("pm_debug", NULL);
542*4882a593Smuzhiyun 	debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO, d, NULL,
543*4882a593Smuzhiyun 			    &omap_pm_debug_fops);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun #endif /* CONFIG_DEBUG_FS */
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun /*
549*4882a593Smuzhiyun  *	omap_pm_prepare - Do preliminary suspend work.
550*4882a593Smuzhiyun  *
551*4882a593Smuzhiyun  */
omap_pm_prepare(void)552*4882a593Smuzhiyun static int omap_pm_prepare(void)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	/* We cannot sleep in idle until we have resumed */
555*4882a593Smuzhiyun 	cpu_idle_poll_ctrl(true);
556*4882a593Smuzhiyun 	return 0;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun /*
561*4882a593Smuzhiyun  *	omap_pm_enter - Actually enter a sleep state.
562*4882a593Smuzhiyun  *	@state:		State we're entering.
563*4882a593Smuzhiyun  *
564*4882a593Smuzhiyun  */
565*4882a593Smuzhiyun 
omap_pm_enter(suspend_state_t state)566*4882a593Smuzhiyun static int omap_pm_enter(suspend_state_t state)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	switch (state)
569*4882a593Smuzhiyun 	{
570*4882a593Smuzhiyun 	case PM_SUSPEND_MEM:
571*4882a593Smuzhiyun 		omap1_pm_suspend();
572*4882a593Smuzhiyun 		break;
573*4882a593Smuzhiyun 	default:
574*4882a593Smuzhiyun 		return -EINVAL;
575*4882a593Smuzhiyun 	}
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	return 0;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun /**
582*4882a593Smuzhiyun  *	omap_pm_finish - Finish up suspend sequence.
583*4882a593Smuzhiyun  *
584*4882a593Smuzhiyun  *	This is called after we wake back up (or if entering the sleep state
585*4882a593Smuzhiyun  *	failed).
586*4882a593Smuzhiyun  */
587*4882a593Smuzhiyun 
omap_pm_finish(void)588*4882a593Smuzhiyun static void omap_pm_finish(void)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	cpu_idle_poll_ctrl(false);
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 
omap_wakeup_interrupt(int irq,void * dev)594*4882a593Smuzhiyun static irqreturn_t omap_wakeup_interrupt(int irq, void *dev)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	return IRQ_HANDLED;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun static const struct platform_suspend_ops omap_pm_ops = {
602*4882a593Smuzhiyun 	.prepare	= omap_pm_prepare,
603*4882a593Smuzhiyun 	.enter		= omap_pm_enter,
604*4882a593Smuzhiyun 	.finish		= omap_pm_finish,
605*4882a593Smuzhiyun 	.valid		= suspend_valid_only_mem,
606*4882a593Smuzhiyun };
607*4882a593Smuzhiyun 
omap_pm_init(void)608*4882a593Smuzhiyun static int __init omap_pm_init(void)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun 	int error = 0;
611*4882a593Smuzhiyun 	int irq;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	if (!cpu_class_is_omap1())
614*4882a593Smuzhiyun 		return -ENODEV;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	pr_info("Power Management for TI OMAP.\n");
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	if (!IS_ENABLED(CONFIG_OMAP_32K_TIMER))
619*4882a593Smuzhiyun 		pr_info("OMAP1 PM: sleep states in idle disabled due to no 32KiHz timer\n");
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	if (!IS_ENABLED(CONFIG_OMAP_DM_TIMER))
622*4882a593Smuzhiyun 		pr_info("OMAP1 PM: sleep states in idle disabled due to no DMTIMER support\n");
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	if (IS_ENABLED(CONFIG_OMAP_32K_TIMER) &&
625*4882a593Smuzhiyun 	    IS_ENABLED(CONFIG_OMAP_DM_TIMER)) {
626*4882a593Smuzhiyun 		/* OMAP16xx only */
627*4882a593Smuzhiyun 		pr_info("OMAP1 PM: sleep states in idle enabled\n");
628*4882a593Smuzhiyun 		enable_dyn_sleep = 1;
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	/*
632*4882a593Smuzhiyun 	 * We copy the assembler sleep/wakeup routines to SRAM.
633*4882a593Smuzhiyun 	 * These routines need to be in SRAM as that's the only
634*4882a593Smuzhiyun 	 * memory the MPU can see when it wakes up.
635*4882a593Smuzhiyun 	 */
636*4882a593Smuzhiyun 	if (cpu_is_omap7xx()) {
637*4882a593Smuzhiyun 		omap_sram_suspend = omap_sram_push(omap7xx_cpu_suspend,
638*4882a593Smuzhiyun 						   omap7xx_cpu_suspend_sz);
639*4882a593Smuzhiyun 	} else if (cpu_is_omap15xx()) {
640*4882a593Smuzhiyun 		omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
641*4882a593Smuzhiyun 						   omap1510_cpu_suspend_sz);
642*4882a593Smuzhiyun 	} else if (cpu_is_omap16xx()) {
643*4882a593Smuzhiyun 		omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
644*4882a593Smuzhiyun 						   omap1610_cpu_suspend_sz);
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	if (omap_sram_suspend == NULL) {
648*4882a593Smuzhiyun 		printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
649*4882a593Smuzhiyun 		return -ENODEV;
650*4882a593Smuzhiyun 	}
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	arm_pm_idle = omap1_pm_idle;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	if (cpu_is_omap7xx())
655*4882a593Smuzhiyun 		irq = INT_7XX_WAKE_UP_REQ;
656*4882a593Smuzhiyun 	else if (cpu_is_omap16xx())
657*4882a593Smuzhiyun 		irq = INT_1610_WAKE_UP_REQ;
658*4882a593Smuzhiyun 	else
659*4882a593Smuzhiyun 		irq = -1;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	if (irq >= 0) {
662*4882a593Smuzhiyun 		if (request_irq(irq, omap_wakeup_interrupt, 0, "peripheral wakeup", NULL))
663*4882a593Smuzhiyun 			pr_err("Failed to request irq %d (peripheral wakeup)\n", irq);
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	/* Program new power ramp-up time
667*4882a593Smuzhiyun 	 * (0 for most boards since we don't lower voltage when in deep sleep)
668*4882a593Smuzhiyun 	 */
669*4882a593Smuzhiyun 	omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	/* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
672*4882a593Smuzhiyun 	omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	/* Configure IDLECT3 */
675*4882a593Smuzhiyun 	if (cpu_is_omap7xx())
676*4882a593Smuzhiyun 		omap_writel(OMAP7XX_IDLECT3_VAL, OMAP7XX_IDLECT3);
677*4882a593Smuzhiyun 	else if (cpu_is_omap16xx())
678*4882a593Smuzhiyun 		omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	suspend_set_ops(&omap_pm_ops);
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
683*4882a593Smuzhiyun 	omap_pm_init_debugfs();
684*4882a593Smuzhiyun #endif
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
687*4882a593Smuzhiyun 	if (error)
688*4882a593Smuzhiyun 		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	if (cpu_is_omap16xx()) {
691*4882a593Smuzhiyun 		/* configure LOW_PWR pin */
692*4882a593Smuzhiyun 		omap_cfg_reg(T20_1610_LOW_PWR);
693*4882a593Smuzhiyun 	}
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return error;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun __initcall(omap_pm_init);
698