include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / arm / mach-omap2 / pm34xx.c
index 3f1f656..ea0000b 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
 
 #include <plat/sram.h>
 #include <plat/clockdomain.h>
@@ -35,6 +38,7 @@
 #include <plat/prcm.h>
 #include <plat/gpmc.h>
 #include <plat/dma.h>
+#include <plat/dmtimer.h>
 
 #include <asm/tlbflush.h>
 
 #include "pm.h"
 #include "sdrc.h"
 
-#define SDRC_POWER_AUTOCOUNT_SHIFT 8
-#define SDRC_POWER_AUTOCOUNT_MASK (0xffff << SDRC_POWER_AUTOCOUNT_SHIFT)
-#define SDRC_POWER_CLKCTRL_SHIFT 4
-#define SDRC_POWER_CLKCTRL_MASK (0x3 << SDRC_POWER_CLKCTRL_SHIFT)
-#define SDRC_SELF_REFRESH_ON_AUTOCOUNT (0x2 << SDRC_POWER_CLKCTRL_SHIFT)
-
 /* Scratchpad offsets */
 #define OMAP343X_TABLE_ADDRESS_OFFSET     0x31
 #define OMAP343X_TABLE_VALUE_OFFSET       0x30
 #define OMAP343X_CONTROL_REG_VALUE_OFFSET  0x32
 
+u32 enable_off_mode;
+u32 sleep_while_idle;
+u32 wakeup_timer_seconds;
+
 struct power_state {
        struct powerdomain *pwrdm;
        u32 next_state;
@@ -74,8 +76,7 @@ static int (*_omap_save_secure_sram)(u32 *addr);
 
 static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
 static struct powerdomain *core_pwrdm, *per_pwrdm;
-
-static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
+static struct powerdomain *cam_pwrdm;
 
 static inline void omap3_per_save_context(void)
 {
@@ -87,6 +88,35 @@ static inline void omap3_per_restore_context(void)
        omap_gpio_restore_context();
 }
 
+static void omap3_enable_io_chain(void)
+{
+       int timeout = 0;
+
+       if (omap_rev() >= OMAP3430_REV_ES3_1) {
+               prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN);
+               /* Do a readback to assure write has been done */
+               prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+
+               while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+                        OMAP3430_ST_IO_CHAIN)) {
+                       timeout++;
+                       if (timeout > 1000) {
+                               printk(KERN_ERR "Wake up daisy chain "
+                                      "activation failed.\n");
+                               return;
+                       }
+                       prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN,
+                                            WKUP_MOD, PM_WKST);
+               }
+       }
+}
+
+static void omap3_disable_io_chain(void)
+{
+       if (omap_rev() >= OMAP3430_REV_ES3_1)
+               prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN);
+}
+
 static void omap3_core_save_context(void)
 {
        u32 control_padconf_off;
@@ -96,9 +126,17 @@ static void omap3_core_save_context(void)
        control_padconf_off |= START_PADCONF_SAVE;
        omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF);
        /* wait for the save to complete */
-       while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
-                       & PADCONF_SAVE_DONE)
-               ;
+       while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
+                       & PADCONF_SAVE_DONE))
+               udelay(1);
+
+       /*
+        * Force write last pad into memory, as this can fail in some
+        * cases according to erratas 1.157, 1.185
+        */
+       omap_ctrl_writel(omap_ctrl_readl(OMAP343X_PADCONF_ETK_D14),
+               OMAP343X_CONTROL_MEM_WKUP + 0x2a0);
+
        /* Save the Interrupt controller context */
        omap_intc_save_context();
        /* Save the GPMC context */
@@ -130,9 +168,6 @@ static void omap3_save_secure_ram_context(u32 target_mpu_state)
        u32 ret;
 
        if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
-               /* Disable dma irq before calling secure rom code API */
-               omap_dma_disable_irq(0);
-               omap_dma_disable_irq(1);
                /*
                 * MPU next state must be set to POWER_ON temporarily,
                 * otherwise the WFI executed inside the ROM code
@@ -291,7 +326,7 @@ static void restore_table_entry(void)
        restore_control_register(control_reg_value);
 }
 
-static void omap_sram_idle(void)
+void omap_sram_idle(void)
 {
        /* Variable to tell what needs to be saved and restored
         * in omap_sram_idle*/
@@ -305,6 +340,7 @@ static void omap_sram_idle(void)
        int core_next_state = PWRDM_POWER_ON;
        int core_prev_state, per_prev_state;
        u32 sdrc_pwr = 0;
+       int per_state_modified = 0;
 
        if (!_omap_sram_idle)
                return;
@@ -333,43 +369,51 @@ static void omap_sram_idle(void)
 
        /* NEON control */
        if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
-               set_pwrdm_state(neon_pwrdm, mpu_next_state);
+               pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
 
-       /* CORE & PER */
+       /* PER */
+       per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
        core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
-       if (core_next_state < PWRDM_POWER_ON) {
+       if (per_next_state < PWRDM_POWER_ON) {
+               omap_uart_prepare_idle(2);
                omap2_gpio_prepare_for_retention();
-               omap_uart_prepare_idle(0);
-               omap_uart_prepare_idle(1);
-               /* PER changes only with core */
-               per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
-               if (per_next_state < PWRDM_POWER_ON) {
-                       omap_uart_prepare_idle(2);
-                       if (per_next_state == PWRDM_POWER_OFF)
+               if (per_next_state == PWRDM_POWER_OFF) {
+                       if (core_next_state == PWRDM_POWER_ON) {
+                               per_next_state = PWRDM_POWER_RET;
+                               pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
+                               per_state_modified = 1;
+                       } else
                                omap3_per_save_context();
                }
+       }
+
+       if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
+               omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
+
+       /* CORE */
+       if (core_next_state < PWRDM_POWER_ON) {
+               omap_uart_prepare_idle(0);
+               omap_uart_prepare_idle(1);
                if (core_next_state == PWRDM_POWER_OFF) {
                        omap3_core_save_context();
                        omap3_prcm_save_context();
                }
-               /* Enable IO-PAD wakeup */
+               /* Enable IO-PAD and IO-CHAIN wakeups */
                prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
+               omap3_enable_io_chain();
        }
+       omap3_intc_prepare_idle();
 
        /*
-        * Force SDRAM controller to self-refresh mode after timeout on
-        * autocount. This is needed on ES3.0 to avoid SDRAM controller
-        * hang-ups.
-        */
+       * On EMU/HS devices ROM code restores a SRDC value
+       * from scratchpad which has automatic self refresh on timeout
+       * of AUTO_CNT = 1 enabled. This takes care of errata 1.142.
+       * Hence store/restore the SDRC_POWER register here.
+       */
        if (omap_rev() >= OMAP3430_REV_ES3_0 &&
            omap_type() != OMAP2_DEVICE_TYPE_GP &&
-           core_next_state == PWRDM_POWER_OFF) {
+           core_next_state == PWRDM_POWER_OFF)
                sdrc_pwr = sdrc_read_reg(SDRC_POWER);
-               sdrc_write_reg((sdrc_pwr &
-                       ~(SDRC_POWER_AUTOCOUNT_MASK|SDRC_POWER_CLKCTRL_MASK)) |
-                       (1 << SDRC_POWER_AUTOCOUNT_SHIFT) |
-                       SDRC_SELF_REFRESH_ON_AUTOCOUNT, SDRC_POWER);
-       }
 
        /*
         * omap3_arm_context is the location where ARM registers
@@ -379,7 +423,7 @@ static void omap_sram_idle(void)
        _omap_sram_idle(omap3_arm_context, save_state);
        cpu_init();
 
-       /* Restore normal SDRAM settings */
+       /* Restore normal SDRC POWER settings */
        if (omap_rev() >= OMAP3430_REV_ES3_0 &&
            omap_type() != OMAP2_DEVICE_TYPE_GP &&
            core_next_state == PWRDM_POWER_OFF)
@@ -389,78 +433,51 @@ static void omap_sram_idle(void)
        if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF)
                restore_table_entry();
 
+       /* CORE */
        if (core_next_state < PWRDM_POWER_ON) {
-               if (per_next_state < PWRDM_POWER_ON)
-                       omap_uart_resume_idle(2);
-               omap_uart_resume_idle(1);
-               omap_uart_resume_idle(0);
-
-               /* Disable IO-PAD wakeup */
-               prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
                core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
                if (core_prev_state == PWRDM_POWER_OFF) {
                        omap3_core_restore_context();
                        omap3_prcm_restore_context();
                        omap3_sram_restore_context();
+                       omap2_sms_restore_context();
                }
-               if (per_next_state < PWRDM_POWER_ON) {
-                       per_prev_state =
-                               pwrdm_read_prev_pwrst(per_pwrdm);
-                       if (per_prev_state == PWRDM_POWER_OFF)
-                               omap3_per_restore_context();
-               }
-               omap2_gpio_resume_after_retention();
+               omap_uart_resume_idle(0);
+               omap_uart_resume_idle(1);
+               if (core_next_state == PWRDM_POWER_OFF)
+                       prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF,
+                                              OMAP3430_GR_MOD,
+                                              OMAP3_PRM_VOLTCTRL_OFFSET);
        }
+       omap3_intc_resume_idle();
 
-       pwrdm_post_transition();
+       /* PER */
+       if (per_next_state < PWRDM_POWER_ON) {
+               per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
+               if (per_prev_state == PWRDM_POWER_OFF)
+                       omap3_per_restore_context();
+               omap2_gpio_resume_after_retention();
+               omap_uart_resume_idle(2);
+               if (per_state_modified)
+                       pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
+       }
 
-}
+       /* Disable IO-PAD and IO-CHAIN wakeup */
+       if (core_next_state < PWRDM_POWER_ON) {
+               prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
+               omap3_disable_io_chain();
+       }
 
-/*
- * Check if functional clocks are enabled before entering
- * sleep. This function could be behind CONFIG_PM_DEBUG
- * when all drivers are configuring their sysconfig registers
- * properly and using their clocks properly.
- */
-static int omap3_fclks_active(void)
-{
-       u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
-               fck_cam = 0, fck_per = 0, fck_usbhost = 0;
+       pwrdm_post_transition();
 
-       fck_core1 = cm_read_mod_reg(CORE_MOD,
-                                   CM_FCLKEN1);
-       if (omap_rev() > OMAP3430_REV_ES1_0) {
-               fck_core3 = cm_read_mod_reg(CORE_MOD,
-                                           OMAP3430ES2_CM_FCLKEN3);
-               fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
-                                         CM_FCLKEN);
-               fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
-                                             CM_FCLKEN);
-       } else
-               fck_sgx = cm_read_mod_reg(GFX_MOD,
-                                         OMAP3430ES2_CM_FCLKEN3);
-       fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
-                                 CM_FCLKEN);
-       fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
-                                 CM_FCLKEN);
-       fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
-                                 CM_FCLKEN);
-
-       /* Ignore UART clocks.  These are handled by UART core (serial.c) */
-       fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
-       fck_per &= ~OMAP3430_EN_UART3;
-
-       if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
-           fck_cam | fck_per | fck_usbhost)
-               return 1;
-       return 0;
+       omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
 }
 
-static int omap3_can_sleep(void)
+int omap3_can_sleep(void)
 {
-       if (!omap_uart_can_sleep())
+       if (!sleep_while_idle)
                return 0;
-       if (omap3_fclks_active())
+       if (!omap_uart_can_sleep())
                return 0;
        return 1;
 }
@@ -468,7 +485,7 @@ static int omap3_can_sleep(void)
 /* This sets pwrdm state (other than mpu & core. Currently only ON &
  * RET are supported. Function is assuming that clkdm doesn't have
  * hw_sup mode enabled. */
-static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
 {
        u32 cur_state;
        int sleep_switch = 0;
@@ -518,7 +535,7 @@ static void omap3_pm_idle(void)
        if (!omap3_can_sleep())
                goto out;
 
-       if (omap_irq_pending())
+       if (omap_irq_pending() || need_resched())
                goto out;
 
        omap_sram_idle();
@@ -531,6 +548,22 @@ out:
 #ifdef CONFIG_SUSPEND
 static suspend_state_t suspend_state;
 
+static void omap2_pm_wakeup_on_timer(u32 seconds)
+{
+       u32 tick_rate, cycles;
+
+       if (!seconds)
+               return;
+
+       tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
+       cycles = tick_rate * seconds;
+       omap_dm_timer_stop(gptimer_wakeup);
+       omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
+
+       pr_info("PM: Resume timer in %d secs (%d ticks at %d ticks/sec.)\n",
+               seconds, cycles, tick_rate);
+}
+
 static int omap3_pm_prepare(void)
 {
        disable_hlt();
@@ -542,6 +575,9 @@ static int omap3_pm_suspend(void)
        struct power_state *pwrst;
        int state, ret = 0;
 
+       if (wakeup_timer_seconds)
+               omap2_pm_wakeup_on_timer(wakeup_timer_seconds);
+
        /* Read current next_pwrsts */
        list_for_each_entry(pwrst, &pwrst_list, node)
                pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
@@ -554,6 +590,8 @@ static int omap3_pm_suspend(void)
        }
 
        omap_uart_prepare_suspend();
+       omap3_intc_suspend();
+
        omap_sram_idle();
 
 restore:
@@ -648,10 +686,10 @@ static void __init omap3_iva_idle(void)
        prm_write_mod_reg(OMAP3430_RST1_IVA2 |
                          OMAP3430_RST2_IVA2 |
                          OMAP3430_RST3_IVA2,
-                         OMAP3430_IVA2_MOD, RM_RSTCTRL);
+                         OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
 
        /* Enable IVA2 clock */
-       cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
+       cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK,
                         OMAP3430_IVA2_MOD, CM_FCLKEN);
 
        /* Set IVA2 boot mode to 'idle' */
@@ -659,7 +697,7 @@ static void __init omap3_iva_idle(void)
                         OMAP343X_CONTROL_IVA2_BOOTMOD);
 
        /* Un-reset IVA2 */
-       prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
+       prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
 
        /* Disable IVA2 clock */
        cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
@@ -668,7 +706,7 @@ static void __init omap3_iva_idle(void)
        prm_write_mod_reg(OMAP3430_RST1_IVA2 |
                          OMAP3430_RST2_IVA2 |
                          OMAP3430_RST3_IVA2,
-                         OMAP3430_IVA2_MOD, RM_RSTCTRL);
+                         OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
 }
 
 static void __init omap3_d2d_idle(void)
@@ -691,8 +729,8 @@ static void __init omap3_d2d_idle(void)
        /* reset modem */
        prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
                          OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
-                         CORE_MOD, RM_RSTCTRL);
-       prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
+                         CORE_MOD, OMAP2_RM_RSTCTRL);
+       prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL);
 }
 
 static void __init prcm_setup_regs(void)
@@ -811,6 +849,8 @@ static void __init prcm_setup_regs(void)
                        CM_AUTOIDLE);
        }
 
+       omap_ctrl_writel(OMAP3430_AUTOIDLE, OMAP2_CONTROL_SYSCONFIG);
+
        /*
         * Set all plls to autoidle. This is needed until autoidle is
         * enabled by clockfw
@@ -851,15 +891,23 @@ static void __init prcm_setup_regs(void)
        prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
                          OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 
+       /* Enable PM_WKEN to support DSS LPR */
+       prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS,
+                               OMAP3430_DSS_MOD, PM_WKEN);
+
        /* Enable wakeups in PER */
        prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 |
                          OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 |
-                         OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3,
+                         OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3 |
+                         OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 |
+                         OMAP3430_EN_MCBSP4,
                          OMAP3430_PER_MOD, PM_WKEN);
        /* and allow them to wake up MPU */
        prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 |
                          OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 |
-                         OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3,
+                         OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3 |
+                         OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 |
+                         OMAP3430_EN_MCBSP4,
                          OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
 
        /* Don't attach IVA interrupts */
@@ -869,37 +917,39 @@ static void __init prcm_setup_regs(void)
        prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
 
        /* Clear any pending 'reset' flags */
-       prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
+       prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST);
+       prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, OMAP2_RM_RSTST);
 
        /* Clear any pending PRCM interrupts */
        prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
 
-       /* Don't attach IVA interrupts */
-       prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
-       prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
-       prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
-       prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
+       omap3_iva_idle();
+       omap3_d2d_idle();
+}
 
-       /* Clear any pending 'reset' flags */
-       prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
-       prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
+void omap3_pm_off_mode_enable(int enable)
+{
+       struct power_state *pwrst;
+       u32 state;
 
-       /* Clear any pending PRCM interrupts */
-       prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+       if (enable)
+               state = PWRDM_POWER_OFF;
+       else
+               state = PWRDM_POWER_RET;
 
-       omap3_iva_idle();
-       omap3_d2d_idle();
+#ifdef CONFIG_CPU_IDLE
+       omap3_cpuidle_update_states();
+#endif
+
+       list_for_each_entry(pwrst, &pwrst_list, node) {
+               pwrst->next_state = state;
+               set_pwrdm_state(pwrst->pwrdm, state);
+       }
 }
 
 int omap3_pm_get_suspend_state(struct powerdomain *pwrdm)
@@ -953,6 +1003,9 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
  */
 static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
 {
+       clkdm_clear_all_wkdeps(clkdm);
+       clkdm_clear_all_sleepdeps(clkdm);
+
        if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
                omap2_clkdm_allow_idle(clkdm);
        else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
@@ -973,6 +1026,7 @@ void omap_push_sram_idle(void)
 static int __init omap3_pm_init(void)
 {
        struct power_state *pwrst, *tmp;
+       struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm;
        int ret;
 
        if (!cpu_is_omap34xx())
@@ -1010,6 +1064,12 @@ static int __init omap3_pm_init(void)
        neon_pwrdm = pwrdm_lookup("neon_pwrdm");
        per_pwrdm = pwrdm_lookup("per_pwrdm");
        core_pwrdm = pwrdm_lookup("core_pwrdm");
+       cam_pwrdm = pwrdm_lookup("cam_pwrdm");
+
+       neon_clkdm = clkdm_lookup("neon_clkdm");
+       mpu_clkdm = clkdm_lookup("mpu_clkdm");
+       per_clkdm = clkdm_lookup("per_clkdm");
+       core_clkdm = clkdm_lookup("core_clkdm");
 
        omap_push_sram_idle();
 #ifdef CONFIG_SUSPEND
@@ -1017,15 +1077,16 @@ static int __init omap3_pm_init(void)
 #endif /* CONFIG_SUSPEND */
 
        pm_idle = omap3_pm_idle;
+       omap3_idle_init();
 
-       pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm);
+       clkdm_add_wkdep(neon_clkdm, mpu_clkdm);
        /*
         * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for
         * IO-pad wakeup.  Otherwise it will unnecessarily waste power
         * waking up PER with every CORE wakeup - see
         * http://marc.info/?l=linux-omap&m=121852150710062&w=2
        */
-       pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
+       clkdm_add_wkdep(per_clkdm, core_clkdm);
 
        if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
                omap3_secure_ram_storage =