blob: 54fea79b17207a1f8e999cc2faba61903b495fcd [file] [log] [blame]
Kevin Hilman8bd22942009-05-28 10:56:16 -07001/*
2 * OMAP3 Power Management Routines
3 *
4 * Copyright (C) 2006-2008 Nokia Corporation
5 * Tony Lindgren <tony@atomide.com>
6 * Jouni Hogander
7 *
Rajendra Nayak2f5939c2008-09-26 17:50:07 +05308 * Copyright (C) 2007 Texas Instruments, Inc.
9 * Rajendra Nayak <rnayak@ti.com>
10 *
Kevin Hilman8bd22942009-05-28 10:56:16 -070011 * Copyright (C) 2005 Texas Instruments, Inc.
12 * Richard Woodruff <r-woodruff2@ti.com>
13 *
14 * Based on pm.c for omap1
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 */
20
21#include <linux/pm.h>
22#include <linux/suspend.h>
23#include <linux/interrupt.h>
24#include <linux/module.h>
25#include <linux/list.h>
26#include <linux/err.h>
27#include <linux/gpio.h>
28
Tony Lindgrence491cf2009-10-20 09:40:47 -070029#include <plat/sram.h>
30#include <plat/clockdomain.h>
31#include <plat/powerdomain.h>
32#include <plat/control.h>
33#include <plat/serial.h>
Rajendra Nayak61255ab2008-09-26 17:49:56 +053034#include <plat/sdrc.h>
Rajendra Nayak2f5939c2008-09-26 17:50:07 +053035#include <plat/prcm.h>
36#include <plat/gpmc.h>
Tero Kristof2d11852008-08-28 13:13:31 +000037#include <plat/dma.h>
Kevin Hilman8bd22942009-05-28 10:56:16 -070038
Rajendra Nayak57f277b2008-09-26 17:49:34 +053039#include <asm/tlbflush.h>
40
Kevin Hilman8bd22942009-05-28 10:56:16 -070041#include "cm.h"
42#include "cm-regbits-34xx.h"
43#include "prm-regbits-34xx.h"
44
45#include "prm.h"
46#include "pm.h"
47
Rajendra Nayak2f5939c2008-09-26 17:50:07 +053048/* Scratchpad offsets */
49#define OMAP343X_TABLE_ADDRESS_OFFSET 0x31
50#define OMAP343X_TABLE_VALUE_OFFSET 0x30
51#define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32
52
Kevin Hilman8bd22942009-05-28 10:56:16 -070053struct power_state {
54 struct powerdomain *pwrdm;
55 u32 next_state;
Kevin Hilman10f90ed2009-06-24 11:39:18 -070056#ifdef CONFIG_SUSPEND
Kevin Hilman8bd22942009-05-28 10:56:16 -070057 u32 saved_state;
Kevin Hilman10f90ed2009-06-24 11:39:18 -070058#endif
Kevin Hilman8bd22942009-05-28 10:56:16 -070059 struct list_head node;
60};
61
62static LIST_HEAD(pwrst_list);
63
64static void (*_omap_sram_idle)(u32 *addr, int save_state);
65
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +053066static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
67static struct powerdomain *core_pwrdm, *per_pwrdm;
68
69static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
Kevin Hilman8bd22942009-05-28 10:56:16 -070070
Rajendra Nayak2f5939c2008-09-26 17:50:07 +053071static inline void omap3_per_save_context(void)
72{
73 omap_gpio_save_context();
74}
75
76static inline void omap3_per_restore_context(void)
77{
78 omap_gpio_restore_context();
79}
80
81static void omap3_core_save_context(void)
82{
83 u32 control_padconf_off;
84
85 /* Save the padconf registers */
86 control_padconf_off = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF);
87 control_padconf_off |= START_PADCONF_SAVE;
88 omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF);
89 /* wait for the save to complete */
90 while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
91 & PADCONF_SAVE_DONE)
92 ;
93 /* Save the Interrupt controller context */
94 omap_intc_save_context();
95 /* Save the GPMC context */
96 omap3_gpmc_save_context();
97 /* Save the system control module context, padconf already save above*/
98 omap3_control_save_context();
Tero Kristof2d11852008-08-28 13:13:31 +000099 omap_dma_global_context_save();
Rajendra Nayak2f5939c2008-09-26 17:50:07 +0530100}
101
102static void omap3_core_restore_context(void)
103{
104 /* Restore the control module context, padconf restored by h/w */
105 omap3_control_restore_context();
106 /* Restore the GPMC context */
107 omap3_gpmc_restore_context();
108 /* Restore the interrupt controller context */
109 omap_intc_restore_context();
Tero Kristof2d11852008-08-28 13:13:31 +0000110 omap_dma_global_context_restore();
Rajendra Nayak2f5939c2008-09-26 17:50:07 +0530111}
112
Jon Hunter77da2d92009-06-27 00:07:25 -0500113/*
114 * PRCM Interrupt Handler Helper Function
115 *
116 * The purpose of this function is to clear any wake-up events latched
117 * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
118 * may occur whilst attempting to clear a PM_WKST_x register and thus
119 * set another bit in this register. A while loop is used to ensure
120 * that any peripheral wake-up events occurring while attempting to
121 * clear the PM_WKST_x are detected and cleared.
122 */
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700123static int prcm_clear_mod_irqs(s16 module, u8 regs)
Jon Hunter77da2d92009-06-27 00:07:25 -0500124{
Vikram Pandita71a80772009-07-17 19:33:09 -0500125 u32 wkst, fclk, iclk, clken;
Jon Hunter77da2d92009-06-27 00:07:25 -0500126 u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
127 u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
128 u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
Paul Walmsley5d805972009-07-22 10:18:07 -0700129 u16 grpsel_off = (regs == 3) ?
130 OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700131 int c = 0;
Jon Hunter77da2d92009-06-27 00:07:25 -0500132
133 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley5d805972009-07-22 10:18:07 -0700134 wkst &= prm_read_mod_reg(module, grpsel_off);
Jon Hunter77da2d92009-06-27 00:07:25 -0500135 if (wkst) {
136 iclk = cm_read_mod_reg(module, iclk_off);
137 fclk = cm_read_mod_reg(module, fclk_off);
138 while (wkst) {
Vikram Pandita71a80772009-07-17 19:33:09 -0500139 clken = wkst;
140 cm_set_mod_reg_bits(clken, module, iclk_off);
141 /*
142 * For USBHOST, we don't know whether HOST1 or
143 * HOST2 woke us up, so enable both f-clocks
144 */
145 if (module == OMAP3430ES2_USBHOST_MOD)
146 clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
147 cm_set_mod_reg_bits(clken, module, fclk_off);
Jon Hunter77da2d92009-06-27 00:07:25 -0500148 prm_write_mod_reg(wkst, module, wkst_off);
149 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700150 c++;
Jon Hunter77da2d92009-06-27 00:07:25 -0500151 }
152 cm_write_mod_reg(iclk, module, iclk_off);
153 cm_write_mod_reg(fclk, module, fclk_off);
154 }
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700155
156 return c;
157}
158
159static int _prcm_int_handle_wakeup(void)
160{
161 int c;
162
163 c = prcm_clear_mod_irqs(WKUP_MOD, 1);
164 c += prcm_clear_mod_irqs(CORE_MOD, 1);
165 c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
166 if (omap_rev() > OMAP3430_REV_ES1_0) {
167 c += prcm_clear_mod_irqs(CORE_MOD, 3);
168 c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
169 }
170
171 return c;
Jon Hunter77da2d92009-06-27 00:07:25 -0500172}
173
174/*
175 * PRCM Interrupt Handler
176 *
177 * The PRM_IRQSTATUS_MPU register indicates if there are any pending
178 * interrupts from the PRCM for the MPU. These bits must be cleared in
179 * order to clear the PRCM interrupt. The PRCM interrupt handler is
180 * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
181 * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
182 * register indicates that a wake-up event is pending for the MPU and
183 * this bit can only be cleared if the all the wake-up events latched
184 * in the various PM_WKST_x registers have been cleared. The interrupt
185 * handler is implemented using a do-while loop so that if a wake-up
186 * event occurred during the processing of the prcm interrupt handler
187 * (setting a bit in the corresponding PM_WKST_x register and thus
188 * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
189 * this would be handled.
190 */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700191static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
192{
Jon Hunter77da2d92009-06-27 00:07:25 -0500193 u32 irqstatus_mpu;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700194 int c = 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700195
Jon Hunter77da2d92009-06-27 00:07:25 -0500196 do {
Jon Hunter77da2d92009-06-27 00:07:25 -0500197 irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
198 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700199
200 if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) {
201 c = _prcm_int_handle_wakeup();
202
203 /*
204 * Is the MPU PRCM interrupt handler racing with the
205 * IVA2 PRCM interrupt handler ?
206 */
207 WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
208 "but no wakeup sources are marked\n");
209 } else {
210 /* XXX we need to expand our PRCM interrupt handler */
211 WARN(1, "prcm: WARNING: PRCM interrupt received, but "
212 "no code to handle it (%08x)\n", irqstatus_mpu);
213 }
214
Jon Hunter77da2d92009-06-27 00:07:25 -0500215 prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
216 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700217
Jon Hunter77da2d92009-06-27 00:07:25 -0500218 } while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET));
Kevin Hilman8bd22942009-05-28 10:56:16 -0700219
220 return IRQ_HANDLED;
221}
222
Rajendra Nayak57f277b2008-09-26 17:49:34 +0530223static void restore_control_register(u32 val)
224{
225 __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val));
226}
227
228/* Function to restore the table entry that was modified for enabling MMU */
229static void restore_table_entry(void)
230{
231 u32 *scratchpad_address;
232 u32 previous_value, control_reg_value;
233 u32 *address;
234
235 scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD);
236
237 /* Get address of entry that was modified */
238 address = (u32 *)__raw_readl(scratchpad_address +
239 OMAP343X_TABLE_ADDRESS_OFFSET);
240 /* Get the previous value which needs to be restored */
241 previous_value = __raw_readl(scratchpad_address +
242 OMAP343X_TABLE_VALUE_OFFSET);
243 address = __va(address);
244 *address = previous_value;
245 flush_tlb_all();
246 control_reg_value = __raw_readl(scratchpad_address
247 + OMAP343X_CONTROL_REG_VALUE_OFFSET);
248 /* This will enable caches and prediction */
249 restore_control_register(control_reg_value);
250}
251
Kevin Hilman8bd22942009-05-28 10:56:16 -0700252static void omap_sram_idle(void)
253{
254 /* Variable to tell what needs to be saved and restored
255 * in omap_sram_idle*/
256 /* save_state = 0 => Nothing to save and restored */
257 /* save_state = 1 => Only L1 and logic lost */
258 /* save_state = 2 => Only L2 lost */
259 /* save_state = 3 => L1, L2 and logic lost */
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530260 int save_state = 0;
261 int mpu_next_state = PWRDM_POWER_ON;
262 int per_next_state = PWRDM_POWER_ON;
263 int core_next_state = PWRDM_POWER_ON;
Rajendra Nayak2f5939c2008-09-26 17:50:07 +0530264 int core_prev_state, per_prev_state;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700265
266 if (!_omap_sram_idle)
267 return;
268
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530269 pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
270 pwrdm_clear_all_prev_pwrst(neon_pwrdm);
271 pwrdm_clear_all_prev_pwrst(core_pwrdm);
272 pwrdm_clear_all_prev_pwrst(per_pwrdm);
273
Kevin Hilman8bd22942009-05-28 10:56:16 -0700274 mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
275 switch (mpu_next_state) {
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530276 case PWRDM_POWER_ON:
Kevin Hilman8bd22942009-05-28 10:56:16 -0700277 case PWRDM_POWER_RET:
278 /* No need to save context */
279 save_state = 0;
280 break;
Rajendra Nayak61255ab2008-09-26 17:49:56 +0530281 case PWRDM_POWER_OFF:
282 save_state = 3;
283 break;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700284 default:
285 /* Invalid state */
286 printk(KERN_ERR "Invalid mpu state in sram_idle\n");
287 return;
288 }
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300289 pwrdm_pre_transition();
290
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530291 /* NEON control */
292 if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
293 set_pwrdm_state(neon_pwrdm, mpu_next_state);
294
295 /* CORE & PER */
296 core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
297 if (core_next_state < PWRDM_POWER_ON) {
298 omap2_gpio_prepare_for_retention();
299 omap_uart_prepare_idle(0);
300 omap_uart_prepare_idle(1);
301 /* PER changes only with core */
302 per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
Rajendra Nayak2f5939c2008-09-26 17:50:07 +0530303 if (per_next_state < PWRDM_POWER_ON) {
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530304 omap_uart_prepare_idle(2);
Rajendra Nayak2f5939c2008-09-26 17:50:07 +0530305 if (per_next_state == PWRDM_POWER_OFF)
306 omap3_per_save_context();
307 }
308 if (core_next_state == PWRDM_POWER_OFF) {
309 omap3_core_save_context();
310 omap3_prcm_save_context();
311 }
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530312 /* Enable IO-PAD wakeup */
313 prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
314 }
Kevin Hilman8bd22942009-05-28 10:56:16 -0700315
Rajendra Nayak61255ab2008-09-26 17:49:56 +0530316 /*
317 * omap3_arm_context is the location where ARM registers
318 * get saved. The restore path then reads from this
319 * location and restores them back.
320 */
321 _omap_sram_idle(omap3_arm_context, save_state);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700322 cpu_init();
323
Rajendra Nayak57f277b2008-09-26 17:49:34 +0530324 /* Restore table entry modified during MMU restoration */
325 if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF)
326 restore_table_entry();
327
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530328 if (core_next_state < PWRDM_POWER_ON) {
329 if (per_next_state < PWRDM_POWER_ON)
330 omap_uart_resume_idle(2);
331 omap_uart_resume_idle(1);
332 omap_uart_resume_idle(0);
333
334 /* Disable IO-PAD wakeup */
335 prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
Rajendra Nayak2f5939c2008-09-26 17:50:07 +0530336 core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
337 if (core_prev_state == PWRDM_POWER_OFF) {
338 omap3_core_restore_context();
339 omap3_prcm_restore_context();
340 omap3_sram_restore_context();
341 }
342 if (per_next_state < PWRDM_POWER_ON) {
343 per_prev_state =
344 pwrdm_read_prev_pwrst(per_pwrdm);
345 if (per_prev_state == PWRDM_POWER_OFF)
346 omap3_per_restore_context();
347 }
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530348 omap2_gpio_resume_after_retention();
349 }
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300350
351 pwrdm_post_transition();
352
Kevin Hilman8bd22942009-05-28 10:56:16 -0700353}
354
355/*
356 * Check if functional clocks are enabled before entering
357 * sleep. This function could be behind CONFIG_PM_DEBUG
358 * when all drivers are configuring their sysconfig registers
359 * properly and using their clocks properly.
360 */
361static int omap3_fclks_active(void)
362{
363 u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
364 fck_cam = 0, fck_per = 0, fck_usbhost = 0;
365
366 fck_core1 = cm_read_mod_reg(CORE_MOD,
367 CM_FCLKEN1);
368 if (omap_rev() > OMAP3430_REV_ES1_0) {
369 fck_core3 = cm_read_mod_reg(CORE_MOD,
370 OMAP3430ES2_CM_FCLKEN3);
371 fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
372 CM_FCLKEN);
373 fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
374 CM_FCLKEN);
375 } else
376 fck_sgx = cm_read_mod_reg(GFX_MOD,
377 OMAP3430ES2_CM_FCLKEN3);
378 fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
379 CM_FCLKEN);
380 fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
381 CM_FCLKEN);
382 fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
383 CM_FCLKEN);
Kevin Hilman4af40162009-02-04 10:51:40 -0800384
385 /* Ignore UART clocks. These are handled by UART core (serial.c) */
386 fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
387 fck_per &= ~OMAP3430_EN_UART3;
388
Kevin Hilman8bd22942009-05-28 10:56:16 -0700389 if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
390 fck_cam | fck_per | fck_usbhost)
391 return 1;
392 return 0;
393}
394
395static int omap3_can_sleep(void)
396{
Kevin Hilman4af40162009-02-04 10:51:40 -0800397 if (!omap_uart_can_sleep())
398 return 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700399 if (omap3_fclks_active())
400 return 0;
401 return 1;
402}
403
404/* This sets pwrdm state (other than mpu & core. Currently only ON &
405 * RET are supported. Function is assuming that clkdm doesn't have
406 * hw_sup mode enabled. */
407static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
408{
409 u32 cur_state;
410 int sleep_switch = 0;
411 int ret = 0;
412
413 if (pwrdm == NULL || IS_ERR(pwrdm))
414 return -EINVAL;
415
416 while (!(pwrdm->pwrsts & (1 << state))) {
417 if (state == PWRDM_POWER_OFF)
418 return ret;
419 state--;
420 }
421
422 cur_state = pwrdm_read_next_pwrst(pwrdm);
423 if (cur_state == state)
424 return ret;
425
426 if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
427 omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
428 sleep_switch = 1;
429 pwrdm_wait_transition(pwrdm);
430 }
431
432 ret = pwrdm_set_next_pwrst(pwrdm, state);
433 if (ret) {
434 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
435 pwrdm->name);
436 goto err;
437 }
438
439 if (sleep_switch) {
440 omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
441 pwrdm_wait_transition(pwrdm);
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300442 pwrdm_state_switch(pwrdm);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700443 }
444
445err:
446 return ret;
447}
448
449static void omap3_pm_idle(void)
450{
451 local_irq_disable();
452 local_fiq_disable();
453
454 if (!omap3_can_sleep())
455 goto out;
456
457 if (omap_irq_pending())
458 goto out;
459
460 omap_sram_idle();
461
462out:
463 local_fiq_enable();
464 local_irq_enable();
465}
466
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700467#ifdef CONFIG_SUSPEND
Tero Kristo24662112009-03-05 16:32:23 +0200468static suspend_state_t suspend_state;
469
Kevin Hilman8bd22942009-05-28 10:56:16 -0700470static int omap3_pm_prepare(void)
471{
472 disable_hlt();
473 return 0;
474}
475
476static int omap3_pm_suspend(void)
477{
478 struct power_state *pwrst;
479 int state, ret = 0;
480
481 /* Read current next_pwrsts */
482 list_for_each_entry(pwrst, &pwrst_list, node)
483 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
484 /* Set ones wanted by suspend */
485 list_for_each_entry(pwrst, &pwrst_list, node) {
486 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
487 goto restore;
488 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
489 goto restore;
490 }
491
Kevin Hilman4af40162009-02-04 10:51:40 -0800492 omap_uart_prepare_suspend();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700493 omap_sram_idle();
494
495restore:
496 /* Restore next_pwrsts */
497 list_for_each_entry(pwrst, &pwrst_list, node) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700498 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
499 if (state > pwrst->next_state) {
500 printk(KERN_INFO "Powerdomain (%s) didn't enter "
501 "target state %d\n",
502 pwrst->pwrdm->name, pwrst->next_state);
503 ret = -1;
504 }
Jouni Hogander6c5f8032008-10-29 12:06:04 +0200505 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700506 }
507 if (ret)
508 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
509 else
510 printk(KERN_INFO "Successfully put all powerdomains "
511 "to target state\n");
512
513 return ret;
514}
515
Tero Kristo24662112009-03-05 16:32:23 +0200516static int omap3_pm_enter(suspend_state_t unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700517{
518 int ret = 0;
519
Tero Kristo24662112009-03-05 16:32:23 +0200520 switch (suspend_state) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700521 case PM_SUSPEND_STANDBY:
522 case PM_SUSPEND_MEM:
523 ret = omap3_pm_suspend();
524 break;
525 default:
526 ret = -EINVAL;
527 }
528
529 return ret;
530}
531
532static void omap3_pm_finish(void)
533{
534 enable_hlt();
535}
536
Tero Kristo24662112009-03-05 16:32:23 +0200537/* Hooks to enable / disable UART interrupts during suspend */
538static int omap3_pm_begin(suspend_state_t state)
539{
540 suspend_state = state;
541 omap_uart_enable_irqs(0);
542 return 0;
543}
544
545static void omap3_pm_end(void)
546{
547 suspend_state = PM_SUSPEND_ON;
548 omap_uart_enable_irqs(1);
549 return;
550}
551
Kevin Hilman8bd22942009-05-28 10:56:16 -0700552static struct platform_suspend_ops omap_pm_ops = {
Tero Kristo24662112009-03-05 16:32:23 +0200553 .begin = omap3_pm_begin,
554 .end = omap3_pm_end,
Kevin Hilman8bd22942009-05-28 10:56:16 -0700555 .prepare = omap3_pm_prepare,
556 .enter = omap3_pm_enter,
557 .finish = omap3_pm_finish,
558 .valid = suspend_valid_only_mem,
559};
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700560#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700561
Kevin Hilman1155e422008-11-25 11:48:24 -0800562
563/**
564 * omap3_iva_idle(): ensure IVA is in idle so it can be put into
565 * retention
566 *
567 * In cases where IVA2 is activated by bootcode, it may prevent
568 * full-chip retention or off-mode because it is not idle. This
569 * function forces the IVA2 into idle state so it can go
570 * into retention/off and thus allow full-chip retention/off.
571 *
572 **/
573static void __init omap3_iva_idle(void)
574{
575 /* ensure IVA2 clock is disabled */
576 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
577
578 /* if no clock activity, nothing else to do */
579 if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
580 OMAP3430_CLKACTIVITY_IVA2_MASK))
581 return;
582
583 /* Reset IVA2 */
584 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
585 OMAP3430_RST2_IVA2 |
586 OMAP3430_RST3_IVA2,
587 OMAP3430_IVA2_MOD, RM_RSTCTRL);
588
589 /* Enable IVA2 clock */
590 cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
591 OMAP3430_IVA2_MOD, CM_FCLKEN);
592
593 /* Set IVA2 boot mode to 'idle' */
594 omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
595 OMAP343X_CONTROL_IVA2_BOOTMOD);
596
597 /* Un-reset IVA2 */
598 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
599
600 /* Disable IVA2 clock */
601 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
602
603 /* Reset IVA2 */
604 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
605 OMAP3430_RST2_IVA2 |
606 OMAP3430_RST3_IVA2,
607 OMAP3430_IVA2_MOD, RM_RSTCTRL);
608}
609
Kevin Hilman8111b222009-04-28 15:27:44 -0700610static void __init omap3_d2d_idle(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700611{
Kevin Hilman8111b222009-04-28 15:27:44 -0700612 u16 mask, padconf;
613
614 /* In a stand alone OMAP3430 where there is not a stacked
615 * modem for the D2D Idle Ack and D2D MStandby must be pulled
616 * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
617 * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
618 mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
619 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
620 padconf |= mask;
621 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
622
623 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
624 padconf |= mask;
625 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
626
Kevin Hilman8bd22942009-05-28 10:56:16 -0700627 /* reset modem */
628 prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
629 OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
630 CORE_MOD, RM_RSTCTRL);
631 prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
Kevin Hilman8111b222009-04-28 15:27:44 -0700632}
Kevin Hilman8bd22942009-05-28 10:56:16 -0700633
Kevin Hilman8111b222009-04-28 15:27:44 -0700634static void __init prcm_setup_regs(void)
635{
Kevin Hilman8bd22942009-05-28 10:56:16 -0700636 /* XXX Reset all wkdeps. This should be done when initializing
637 * powerdomains */
638 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
639 prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
640 prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
641 prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
642 prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
643 prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
644 if (omap_rev() > OMAP3430_REV_ES1_0) {
645 prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
646 prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
647 } else
648 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
649
650 /*
651 * Enable interface clock autoidle for all modules.
652 * Note that in the long run this should be done by clockfw
653 */
654 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700655 OMAP3430_AUTO_MODEM |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700656 OMAP3430ES2_AUTO_MMC3 |
657 OMAP3430ES2_AUTO_ICR |
658 OMAP3430_AUTO_AES2 |
659 OMAP3430_AUTO_SHA12 |
660 OMAP3430_AUTO_DES2 |
661 OMAP3430_AUTO_MMC2 |
662 OMAP3430_AUTO_MMC1 |
663 OMAP3430_AUTO_MSPRO |
664 OMAP3430_AUTO_HDQ |
665 OMAP3430_AUTO_MCSPI4 |
666 OMAP3430_AUTO_MCSPI3 |
667 OMAP3430_AUTO_MCSPI2 |
668 OMAP3430_AUTO_MCSPI1 |
669 OMAP3430_AUTO_I2C3 |
670 OMAP3430_AUTO_I2C2 |
671 OMAP3430_AUTO_I2C1 |
672 OMAP3430_AUTO_UART2 |
673 OMAP3430_AUTO_UART1 |
674 OMAP3430_AUTO_GPT11 |
675 OMAP3430_AUTO_GPT10 |
676 OMAP3430_AUTO_MCBSP5 |
677 OMAP3430_AUTO_MCBSP1 |
678 OMAP3430ES1_AUTO_FAC | /* This is es1 only */
679 OMAP3430_AUTO_MAILBOXES |
680 OMAP3430_AUTO_OMAPCTRL |
681 OMAP3430ES1_AUTO_FSHOSTUSB |
682 OMAP3430_AUTO_HSOTGUSB |
Kevin Hilman8111b222009-04-28 15:27:44 -0700683 OMAP3430_AUTO_SAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700684 OMAP3430_AUTO_SSI,
685 CORE_MOD, CM_AUTOIDLE1);
686
687 cm_write_mod_reg(
688 OMAP3430_AUTO_PKA |
689 OMAP3430_AUTO_AES1 |
690 OMAP3430_AUTO_RNG |
691 OMAP3430_AUTO_SHA11 |
692 OMAP3430_AUTO_DES1,
693 CORE_MOD, CM_AUTOIDLE2);
694
695 if (omap_rev() > OMAP3430_REV_ES1_0) {
696 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700697 OMAP3430_AUTO_MAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700698 OMAP3430ES2_AUTO_USBTLL,
699 CORE_MOD, CM_AUTOIDLE3);
700 }
701
702 cm_write_mod_reg(
703 OMAP3430_AUTO_WDT2 |
704 OMAP3430_AUTO_WDT1 |
705 OMAP3430_AUTO_GPIO1 |
706 OMAP3430_AUTO_32KSYNC |
707 OMAP3430_AUTO_GPT12 |
708 OMAP3430_AUTO_GPT1 ,
709 WKUP_MOD, CM_AUTOIDLE);
710
711 cm_write_mod_reg(
712 OMAP3430_AUTO_DSS,
713 OMAP3430_DSS_MOD,
714 CM_AUTOIDLE);
715
716 cm_write_mod_reg(
717 OMAP3430_AUTO_CAM,
718 OMAP3430_CAM_MOD,
719 CM_AUTOIDLE);
720
721 cm_write_mod_reg(
722 OMAP3430_AUTO_GPIO6 |
723 OMAP3430_AUTO_GPIO5 |
724 OMAP3430_AUTO_GPIO4 |
725 OMAP3430_AUTO_GPIO3 |
726 OMAP3430_AUTO_GPIO2 |
727 OMAP3430_AUTO_WDT3 |
728 OMAP3430_AUTO_UART3 |
729 OMAP3430_AUTO_GPT9 |
730 OMAP3430_AUTO_GPT8 |
731 OMAP3430_AUTO_GPT7 |
732 OMAP3430_AUTO_GPT6 |
733 OMAP3430_AUTO_GPT5 |
734 OMAP3430_AUTO_GPT4 |
735 OMAP3430_AUTO_GPT3 |
736 OMAP3430_AUTO_GPT2 |
737 OMAP3430_AUTO_MCBSP4 |
738 OMAP3430_AUTO_MCBSP3 |
739 OMAP3430_AUTO_MCBSP2,
740 OMAP3430_PER_MOD,
741 CM_AUTOIDLE);
742
743 if (omap_rev() > OMAP3430_REV_ES1_0) {
744 cm_write_mod_reg(
745 OMAP3430ES2_AUTO_USBHOST,
746 OMAP3430ES2_USBHOST_MOD,
747 CM_AUTOIDLE);
748 }
749
750 /*
751 * Set all plls to autoidle. This is needed until autoidle is
752 * enabled by clockfw
753 */
754 cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
755 OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
756 cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
757 MPU_MOD,
758 CM_AUTOIDLE2);
759 cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
760 (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
761 PLL_MOD,
762 CM_AUTOIDLE);
763 cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
764 PLL_MOD,
765 CM_AUTOIDLE2);
766
767 /*
768 * Enable control of expternal oscillator through
769 * sys_clkreq. In the long run clock framework should
770 * take care of this.
771 */
772 prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
773 1 << OMAP_AUTOEXTCLKMODE_SHIFT,
774 OMAP3430_GR_MOD,
775 OMAP3_PRM_CLKSRC_CTRL_OFFSET);
776
777 /* setup wakup source */
778 prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
779 OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
780 WKUP_MOD, PM_WKEN);
781 /* No need to write EN_IO, that is always enabled */
782 prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
783 OMAP3430_EN_GPT12,
784 WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
785 /* For some reason IO doesn't generate wakeup event even if
786 * it is selected to mpu wakeup goup */
787 prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
788 OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
Kevin Hilman1155e422008-11-25 11:48:24 -0800789
Kevin Hilmanb427f922009-10-22 14:48:13 -0700790 /* Enable wakeups in PER */
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000791 prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 |
792 OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 |
Kevin Hilmanb427f922009-10-22 14:48:13 -0700793 OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3,
794 OMAP3430_PER_MOD, PM_WKEN);
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000795 /* and allow them to wake up MPU */
796 prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 |
797 OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 |
Kevin Hilmanb427f922009-10-22 14:48:13 -0700798 OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3,
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000799 OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
800
Kevin Hilmand3fd3292009-05-05 16:34:25 -0700801 /* Don't attach IVA interrupts */
802 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
803 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
804 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
805 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
806
Kevin Hilmanb1340d12009-04-27 16:14:54 -0700807 /* Clear any pending 'reset' flags */
808 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
809 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
810 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
811 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
812 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
813 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
814 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
815
Kevin Hilman014c46d2009-04-27 07:50:23 -0700816 /* Clear any pending PRCM interrupts */
817 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
818
Kevin Hilman040fed02009-05-05 16:34:25 -0700819 /* Don't attach IVA interrupts */
820 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
821 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
822 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
823 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
824
Kevin Hilman3a07ae32009-04-27 16:14:54 -0700825 /* Clear any pending 'reset' flags */
826 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
827 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
828 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
829 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
830 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
831 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
832 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
833
Kevin Hilman3a6667a2009-04-27 07:50:23 -0700834 /* Clear any pending PRCM interrupts */
835 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
836
Kevin Hilman1155e422008-11-25 11:48:24 -0800837 omap3_iva_idle();
Kevin Hilman8111b222009-04-28 15:27:44 -0700838 omap3_d2d_idle();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700839}
840
Tero Kristo68d47782008-11-26 12:26:24 +0200841int omap3_pm_get_suspend_state(struct powerdomain *pwrdm)
842{
843 struct power_state *pwrst;
844
845 list_for_each_entry(pwrst, &pwrst_list, node) {
846 if (pwrst->pwrdm == pwrdm)
847 return pwrst->next_state;
848 }
849 return -EINVAL;
850}
851
852int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state)
853{
854 struct power_state *pwrst;
855
856 list_for_each_entry(pwrst, &pwrst_list, node) {
857 if (pwrst->pwrdm == pwrdm) {
858 pwrst->next_state = state;
859 return 0;
860 }
861 }
862 return -EINVAL;
863}
864
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300865static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700866{
867 struct power_state *pwrst;
868
869 if (!pwrdm->pwrsts)
870 return 0;
871
Ming Leid3d381c2009-08-22 21:20:26 +0800872 pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700873 if (!pwrst)
874 return -ENOMEM;
875 pwrst->pwrdm = pwrdm;
876 pwrst->next_state = PWRDM_POWER_RET;
877 list_add(&pwrst->node, &pwrst_list);
878
879 if (pwrdm_has_hdwr_sar(pwrdm))
880 pwrdm_enable_hdwr_sar(pwrdm);
881
882 return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
883}
884
885/*
886 * Enable hw supervised mode for all clockdomains if it's
887 * supported. Initiate sleep transition for other clockdomains, if
888 * they are not used
889 */
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300890static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700891{
892 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
893 omap2_clkdm_allow_idle(clkdm);
894 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
895 atomic_read(&clkdm->usecount) == 0)
896 omap2_clkdm_sleep(clkdm);
897 return 0;
898}
899
Rajendra Nayak3231fc82008-09-26 17:49:14 +0530900void omap_push_sram_idle(void)
901{
902 _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
903 omap34xx_cpu_suspend_sz);
904}
905
Kevin Hilman7cc515f2009-06-10 09:02:25 -0700906static int __init omap3_pm_init(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700907{
908 struct power_state *pwrst, *tmp;
909 int ret;
910
911 if (!cpu_is_omap34xx())
912 return -ENODEV;
913
914 printk(KERN_ERR "Power Management for TI OMAP3.\n");
915
916 /* XXX prcm_setup_regs needs to be before enabling hw
917 * supervised mode for powerdomains */
918 prcm_setup_regs();
Rajendra Nayak2f5939c2008-09-26 17:50:07 +0530919 omap3_save_scratchpad_contents();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700920
921 ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
922 (irq_handler_t)prcm_interrupt_handler,
923 IRQF_DISABLED, "prcm", NULL);
924 if (ret) {
925 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
926 INT_34XX_PRCM_MPU_IRQ);
927 goto err1;
928 }
929
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300930 ret = pwrdm_for_each(pwrdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700931 if (ret) {
932 printk(KERN_ERR "Failed to setup powerdomains\n");
933 goto err2;
934 }
935
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300936 (void) clkdm_for_each(clkdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700937
938 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
939 if (mpu_pwrdm == NULL) {
940 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
941 goto err2;
942 }
943
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530944 neon_pwrdm = pwrdm_lookup("neon_pwrdm");
945 per_pwrdm = pwrdm_lookup("per_pwrdm");
946 core_pwrdm = pwrdm_lookup("core_pwrdm");
947
Rajendra Nayak3231fc82008-09-26 17:49:14 +0530948 omap_push_sram_idle();
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700949#ifdef CONFIG_SUSPEND
Kevin Hilman8bd22942009-05-28 10:56:16 -0700950 suspend_set_ops(&omap_pm_ops);
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700951#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700952
953 pm_idle = omap3_pm_idle;
954
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530955 pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm);
956 /*
957 * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for
958 * IO-pad wakeup. Otherwise it will unnecessarily waste power
959 * waking up PER with every CORE wakeup - see
960 * http://marc.info/?l=linux-omap&m=121852150710062&w=2
961 */
962 pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
963
Kevin Hilman8bd22942009-05-28 10:56:16 -0700964err1:
965 return ret;
966err2:
967 free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
968 list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
969 list_del(&pwrst->node);
970 kfree(pwrst);
971 }
972 return ret;
973}
974
975late_initcall(omap3_pm_init);