summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/pm34xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/pm34xx.c')
-rw-r--r--arch/arm/mach-omap2/pm34xx.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 65f4a7f8185..ceedc07fea0 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -30,6 +30,7 @@
#include <linux/slab.h>
#include <linux/omap-dma.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/pm_runtime.h>
#include <trace/events/power.h>
@@ -53,6 +54,7 @@
#include "control.h"
#include "pm-debug-regs.h"
#include "iomap.h"
+#include "omap_device.h"
#include "pad_wkup.h"
@@ -77,6 +79,7 @@ void (*omap3_do_wfi_sram)(void);
static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
static struct powerdomain *core_pwrdm, *per_pwrdm;
static struct powerdomain *dss_pwrdm;
+static struct omap_hwmod *wd_hwmod;
static void omap3_core_save_context(void)
{
@@ -151,6 +154,7 @@ static void omap3_save_secure_ram_context(void)
*/
static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
{
+ static struct clk *per_dpll_clk;
u32 wkst, fclk, iclk, clken;
u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
@@ -163,6 +167,16 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
wkst &= ~ignore_bits;
if (wkst) {
+ if (module != WKUP_MOD) {
+ if (per_dpll_clk == NULL) {
+ per_dpll_clk = clk_get(NULL, "dpll4_ck");
+ if (per_dpll_clk == NULL) {
+ pr_emerg("Unable to get dpll4_ck\n");
+ BUG();
+ }
+ }
+ clk_enable(per_dpll_clk);
+ }
iclk = omap2_cm_read_mod_reg(module, iclk_off);
fclk = omap2_cm_read_mod_reg(module, fclk_off);
while (wkst) {
@@ -191,6 +205,8 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
}
omap2_cm_write_mod_reg(iclk, module, iclk_off);
omap2_cm_write_mod_reg(fclk, module, fclk_off);
+ if (module != WKUP_MOD)
+ clk_disable(per_dpll_clk);
}
return c;
@@ -200,6 +216,7 @@ static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
{
int c;
+ _reconfigure_io_chain();
c = prcm_clear_mod_irqs(WKUP_MOD, 1,
~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
@@ -309,6 +326,10 @@ void omap_sram_idle(bool in_suspend)
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
+ _reconfigure_io_chain();
+ if (!in_suspend && wd_hwmod != NULL)
+ platform_pm_suspend(&wd_hwmod->od->pdev->dev);
+
if (core_next_state == PWRDM_POWER_OFF) {
omap3_core_save_context();
omap3_cm_save_context();
@@ -360,6 +381,9 @@ void omap_sram_idle(bool in_suspend)
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
+ if (!in_suspend && wd_hwmod != NULL)
+ platform_pm_resume(&wd_hwmod->od->pdev->dev);
+
core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
if (core_prev_state == PWRDM_POWER_OFF) {
omap3_core_restore_context();
@@ -750,6 +774,7 @@ int __init omap3_pm_init(void)
ret = -EINVAL;
goto err3;
}
+ wd_hwmod = omap_hwmod_lookup("wd_timer2");
neon_pwrdm = pwrdm_lookup("neon_pwrdm");
per_pwrdm = pwrdm_lookup("per_pwrdm");