aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2011-07-25 14:53:04 -0700
committerColin Cross <ccross@android.com>2011-07-25 14:53:04 -0700
commitc06c360f1b34d5b386c8fcc145943126df084758 (patch)
tree584c2ce139170da9e25e48d7034e4015208a0875
parent799417abd7586301c597bd2fb963c62062b04fcb (diff)
parentcc7e5167f7461666fb7e1999d226e93ffe355b1c (diff)
downloadkernel_samsung_tuna-c06c360f1b34d5b386c8fcc145943126df084758.zip
kernel_samsung_tuna-c06c360f1b34d5b386c8fcc145943126df084758.tar.gz
kernel_samsung_tuna-c06c360f1b34d5b386c8fcc145943126df084758.tar.bz2
Merge branch 'linux-omap-pm-3.0' into linux-omap-3.0
-rw-r--r--arch/arm/mach-omap2/clockdomain.c7
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c2
-rw-r--r--arch/arm/mach-omap2/omap-wakeupgen.c15
-rw-r--r--arch/arm/mach-omap2/omap2plus-cpufreq.c49
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c3
-rw-r--r--arch/arm/mach-omap2/pm-debug.c74
-rw-r--r--arch/arm/mach-omap2/pm.h8
-rw-r--r--arch/arm/mach-omap2/pm44xx.c29
-rw-r--r--arch/arm/mach-omap2/powerdomain.c12
-rw-r--r--arch/arm/mach-omap2/smartreflex.c89
-rw-r--r--drivers/mfd/twl6030-irq.c9
11 files changed, 261 insertions, 36 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index b98a972..583cc3d 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -718,6 +718,8 @@ int clkdm_sleep(struct clockdomain *clkdm)
*/
int clkdm_wakeup(struct clockdomain *clkdm)
{
+ int ret;
+
if (!clkdm)
return -EINVAL;
@@ -732,7 +734,10 @@ int clkdm_wakeup(struct clockdomain *clkdm)
pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
- return arch_clkdm->clkdm_wakeup(clkdm);
+ ret = arch_clkdm->clkdm_wakeup(clkdm);
+ ret |= pwrdm_wait_transition(clkdm->pwrdm.ptr);
+
+ return ret;
}
/**
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index 81a4d0d..bb97206 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -150,7 +150,7 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
if (cx->type > OMAP4_STATE_C1)
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id);
- omap4_enter_sleep(dev->cpu, cx->cpu0_state);
+ omap4_enter_sleep(dev->cpu, cx->cpu0_state, false);
/* restore the MPU and CORE states to ON */
omap_set_pwrdm_state(mpu_pd, PWRDM_POWER_ON);
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index d97c36f..7567ee6 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -188,6 +188,20 @@ void omap_wakeupgen_irqmask_all(unsigned int cpu, unsigned int set)
spin_unlock(&wakeupgen_lock);
}
+#ifdef CONFIG_PM
+/*
+ * Masking wakeup irqs is handled by the IRQCHIP_MASK_ON_SUSPEND flag,
+ * so no action is necessary in set_wake, but implement an empty handler
+ * here to prevent enable_irq_wake() returning an error.
+ */
+static int wakeupgen_set_wake(struct irq_data *d, unsigned int on)
+{
+ return 0;
+}
+#else
+#define wakeupgen_set_wake NULL
+#endif
+
/*
* Initialse the wakeupgen module
*/
@@ -218,6 +232,7 @@ int __init omap_wakeupgen_init(void)
*/
gic_arch_extn.irq_mask = wakeupgen_mask;
gic_arch_extn.irq_unmask = wakeupgen_unmask;
+ gic_arch_extn.irq_set_wake = wakeupgen_set_wake;
gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
return 0;
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index 2523b11..883325f 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -40,6 +40,16 @@
#include "dvfs.h"
+#ifdef CONFIG_SMP
+struct lpj_info {
+ unsigned long ref;
+ unsigned int freq;
+};
+
+static DEFINE_PER_CPU(struct lpj_info, lpj_ref);
+static struct lpj_info global_lpj_ref;
+#endif
+
static struct cpufreq_frequency_table *freq_table;
static atomic_t freq_table_users = ATOMIC_INIT(0);
static struct clk *mpu_clk;
@@ -98,37 +108,19 @@ static int omap_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new && policy->cur == freqs.new)
return ret;
- if (!is_smp()) {
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- goto set_freq;
- }
-
/* notifiers */
for_each_cpu(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
-set_freq:
#ifdef CONFIG_CPU_FREQ_DEBUG
pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
#endif
ret = omap_device_scale(mpu_dev, mpu_dev, freqs.new * 1000);
- /*
- * Generic CPUFREQ driver jiffy update is under !SMP. So jiffies
- * won't get updated when UP machine cpufreq build with
- * CONFIG_SMP enabled. Below code is added only to manage that
- * scenario
- */
freqs.new = omap_getspeed(policy->cpu);
- if (!is_smp()) {
- loops_per_jiffy =
- cpufreq_scale(loops_per_jiffy, freqs.old, freqs.new);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- goto skip_lpj;
- }
#ifdef CONFIG_SMP
/*
@@ -136,10 +128,24 @@ set_freq:
* cpufreq driver. So, update the per-CPU loops_per_jiffy value
* on frequency transition. We need to update all dependent CPUs.
*/
- for_each_cpu(i, policy->cpus)
+ for_each_cpu(i, policy->cpus) {
+ struct lpj_info *lpj = &per_cpu(lpj_ref, i);
+ if (!lpj->freq) {
+ lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy;
+ lpj->freq = freqs.old;
+ }
+
per_cpu(cpu_data, i).loops_per_jiffy =
- cpufreq_scale(per_cpu(cpu_data, i).loops_per_jiffy,
- freqs.old, freqs.new);
+ cpufreq_scale(lpj->ref, lpj->freq, freqs.new);
+ }
+
+ /* And don't forget to adjust the global one */
+ if (!global_lpj_ref.freq) {
+ global_lpj_ref.ref = loops_per_jiffy;
+ global_lpj_ref.freq = freqs.old;
+ }
+ loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq,
+ freqs.new);
#endif
/* notifiers */
@@ -148,7 +154,6 @@ set_freq:
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
-skip_lpj:
return ret;
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index e1fc7a5..7697726 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -2642,7 +2642,8 @@ static struct omap_hwmod_class_sysconfig omap44xx_gpu_sysc = {
.sysc_offs = 0xfe10,
.sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
- MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART |
+ MSTANDBY_SMART_WKUP),
.sysc_fields = &omap_hwmod_sysc_type2,
};
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 4a07942..27ddf12 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -38,12 +38,27 @@
#include "prm2xxx_3xxx.h"
#include "pm.h"
+#define PM_DEBUG_MAX_SAVED_REGS 64
+#define PM_DEBUG_PRM_MIN 0x4A306000
+#define PM_DEBUG_PRM_MAX (0x4A307F00 + (PM_DEBUG_MAX_SAVED_REGS * 4) - 1)
+#define PM_DEBUG_CM1_MIN 0x4A004000
+#define PM_DEBUG_CM1_MAX (0x4A004F00 + (PM_DEBUG_MAX_SAVED_REGS * 4) - 1)
+#define PM_DEBUG_CM2_MIN 0x4A008000
+#define PM_DEBUG_CM2_MAX (0x4A009F00 + (PM_DEBUG_MAX_SAVED_REGS * 4) - 1)
+
int omap2_pm_debug;
u32 enable_off_mode;
u32 sleep_while_idle;
u32 wakeup_timer_seconds;
u32 wakeup_timer_milliseconds;
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+static u32 saved_reg_num;
+static u32 saved_reg_num_used;
+static u32 saved_reg_addr;
+static u32 saved_reg_buff[2][PM_DEBUG_MAX_SAVED_REGS];
+#endif
+
#define DUMP_PRM_MOD_REG(mod, reg) \
regs[reg_count].name = #mod "." #reg; \
regs[reg_count++].val = omap2_prm_read_mod_reg(mod, reg)
@@ -544,6 +559,47 @@ static int pwrdm_suspend_set(void *data, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
pwrdm_suspend_set, "%llu\n");
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+static bool is_addr_valid()
+{
+ int saved_reg_addr_max = 0;
+ /* Only for OMAP4 for the timebeing */
+ if (!cpu_is_omap44xx())
+ return false;
+
+ saved_reg_num = (saved_reg_num > PM_DEBUG_MAX_SAVED_REGS) ?
+ PM_DEBUG_MAX_SAVED_REGS : saved_reg_num;
+
+ saved_reg_addr_max = saved_reg_addr + (saved_reg_num * 4) - 1;
+
+ if (saved_reg_addr >= PM_DEBUG_PRM_MIN &&
+ saved_reg_addr_max <= PM_DEBUG_PRM_MAX)
+ return true;
+ if (saved_reg_addr >= PM_DEBUG_CM1_MIN &&
+ saved_reg_addr_max <= PM_DEBUG_CM1_MAX)
+ return true;
+ if (saved_reg_addr >= PM_DEBUG_CM2_MIN &&
+ saved_reg_addr_max <= PM_DEBUG_CM2_MAX)
+ return true;
+ return false;
+}
+
+void omap4_pm_suspend_save_regs()
+{
+ int i = 0;
+ if (!saved_reg_num || !is_addr_valid())
+ return;
+
+ saved_reg_num_used = saved_reg_num;
+
+ for (i = 0; i < saved_reg_num; i++) {
+ saved_reg_buff[1][i] = omap_readl(saved_reg_addr + (i*4));
+ saved_reg_buff[0][i] = saved_reg_addr + (i*4);
+ }
+ return;
+}
+#endif
+
static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
{
int i;
@@ -573,6 +629,14 @@ static int option_get(void *data, u64 *val)
u32 *option = data;
*val = *option;
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+ if (option == &saved_reg_addr) {
+ int i;
+ for (i = 0; i < saved_reg_num_used; i++)
+ pr_info(" %x = %x\n", saved_reg_buff[0][i],
+ saved_reg_buff[1][i]);
+ }
+#endif
return 0;
}
@@ -658,6 +722,16 @@ skip_reg_debufs:
(void) debugfs_create_file("wakeup_timer_milliseconds",
S_IRUGO | S_IWUSR, d, &wakeup_timer_milliseconds,
&pm_dbg_option_fops);
+
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+ (void) debugfs_create_file("saved_reg_show",
+ S_IRUGO | S_IWUSR, d, &saved_reg_addr,
+ &pm_dbg_option_fops);
+ debugfs_create_u32("saved_reg_addr", S_IRUGO | S_IWUGO, d,
+ &saved_reg_addr);
+ debugfs_create_u32("saved_reg_num", S_IRUGO | S_IWUGO, d,
+ &saved_reg_num);
+#endif
pm_dbg_init_done = 1;
return 0;
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index f191fdc..f7bd592 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -22,7 +22,8 @@ extern int omap3_can_sleep(void);
extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
extern int omap3_idle_init(void);
extern int omap4_idle_init(void);
-extern void omap4_enter_sleep(unsigned int cpu, unsigned int power_state);
+extern void omap4_enter_sleep(unsigned int cpu, unsigned int power_state,
+ bool suspend);
extern void omap4_trigger_ioctrl(void);
#if defined(CONFIG_PM_OPP)
@@ -80,6 +81,11 @@ extern u32 sleep_while_idle;
#define enable_off_mode 0
#define sleep_while_idle 0
#endif
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+extern void omap4_pm_suspend_save_regs(void);
+#else
+static inline void omap4_pm_suspend_save_regs(void) { }
+#endif
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev);
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 104ca5e..130bc6b 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -85,7 +85,8 @@ void omap4_trigger_ioctrl(void)
/* This is a common low power function called from suspend and
* cpuidle
*/
-void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
+
+void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend)
{
int cpu0_next_state = PWRDM_POWER_ON;
int per_next_state = PWRDM_POWER_ON;
@@ -107,7 +108,8 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
mpu_next_state = PWRDM_POWER_INACTIVE;
pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
} else {
- omap_sr_disable_reset_volt(mpu_voltdm);
+ if (!suspend)
+ omap_sr_disable_reset_volt(mpu_voltdm);
omap_vc_set_auto_trans(mpu_voltdm,
OMAP_VC_CHANNEL_AUTO_TRANSITION_RETENTION);
}
@@ -125,8 +127,10 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
core_next_state = PWRDM_POWER_ON;
pwrdm_set_next_pwrst(core_pwrdm, core_next_state);
} else {
- omap_sr_disable_reset_volt(iva_voltdm);
- omap_sr_disable_reset_volt(core_voltdm);
+ if (!suspend) {
+ omap_sr_disable_reset_volt(iva_voltdm);
+ omap_sr_disable_reset_volt(core_voltdm);
+ }
omap_vc_set_auto_trans(core_voltdm,
OMAP_VC_CHANNEL_AUTO_TRANSITION_RETENTION);
omap_vc_set_auto_trans(iva_voltdm,
@@ -137,6 +141,9 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
}
}
+ if (suspend && cpu_is_omap44xx())
+ omap4_pm_suspend_save_regs();
+
omap4_enter_lowpower(cpu, power_state);
if (core_next_state < PWRDM_POWER_ON) {
@@ -146,14 +153,17 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
omap_vc_set_auto_trans(iva_voltdm,
OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE);
omap2_gpio_resume_after_idle();
- omap_sr_enable(iva_voltdm);
- omap_sr_enable(core_voltdm);
+ if (!suspend) {
+ omap_sr_enable(iva_voltdm);
+ omap_sr_enable(core_voltdm);
+ }
}
if (mpu_next_state < PWRDM_POWER_INACTIVE) {
omap_vc_set_auto_trans(mpu_voltdm,
OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE);
- omap_sr_enable(mpu_voltdm);
+ if (!suspend)
+ omap_sr_enable(mpu_voltdm);
}
return;
@@ -240,7 +250,7 @@ static int omap4_pm_suspend(void)
* domain CSWR is not supported by hardware.
* More details can be found in OMAP4430 TRM section 4.3.4.2.
*/
- omap4_enter_sleep(0, PWRDM_POWER_OFF);
+ omap4_enter_sleep(0, PWRDM_POWER_OFF, true);
omap4_print_wakeirq();
/* Disable wake-up irq's */
@@ -532,6 +542,9 @@ static int __init omap4_pm_init(void)
core_pwrdm = pwrdm_lookup("core_pwrdm");
per_pwrdm = pwrdm_lookup("l4per_pwrdm");
+ /* Enable wakeup for PRCM IRQ for system wide suspend */
+ enable_irq_wake(OMAP44XX_IRQ_PRCM);
+
omap4_idle_init();
err2:
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index e0490bc..e61866c 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -109,6 +109,16 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
list_add(&pwrdm->node, &pwrdm_list);
+ /*
+ * Program all powerdomain target state as ON; This is to
+ * prevent domains from hitting low power states (if bootloader
+ * has target states set to something other than ON) and potentially
+ * even losing context while PM is not fully initilized.
+ * The PM late init code can then program the desired target
+ * state for all the power domains.
+ */
+ pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_ON);
+
/* Initialize the powerdomain's state counter */
for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
pwrdm->state_counter[i] = 0;
@@ -218,7 +228,7 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
/**
* pwrdm_init - set up the powerdomain layer
* @pwrdm_list: array of struct powerdomain pointers to register
- * @custom_funcs: func pointers for arch specific implementations
+ * @custom_funcs: func pointers for arch specfic implementations
*
* Loop through the array of powerdomains @pwrdm_list, registering all
* that are available on the current CPU. If pwrdm_list is supplied
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index bb606c9..f8705ca 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -23,6 +23,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <plat/common.h>
@@ -39,6 +40,7 @@ struct omap_sr {
int ip_type;
int nvalue_count;
bool autocomp_active;
+ bool is_suspended;
u32 clk_length;
u32 err_weight;
u32 err_minlimit;
@@ -684,6 +686,11 @@ void omap_sr_enable(struct voltagedomain *voltdm)
if (!sr->autocomp_active)
return;
+ if (sr->is_suspended) {
+ dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__);
+ return;
+ }
+
if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
"registered\n", __func__);
@@ -717,6 +724,11 @@ void omap_sr_disable(struct voltagedomain *voltdm)
if (!sr->autocomp_active)
return;
+ if (sr->is_suspended) {
+ dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__);
+ return;
+ }
+
if (!sr_class || !(sr_class->disable)) {
dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
"registered\n", __func__);
@@ -750,6 +762,11 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
if (!sr->autocomp_active)
return;
+ if (sr->is_suspended) {
+ dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__);
+ return;
+ }
+
if (!sr_class || !(sr_class->disable)) {
dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
"registered\n", __func__);
@@ -808,6 +825,11 @@ static int omap_sr_autocomp_store(void *data, u64 val)
return -EINVAL;
}
+ if (sr_info->is_suspended) {
+ pr_warning("%s: in suspended state\n", __func__);
+ return -EBUSY;
+ }
+
/* control enable/disable only if there is a delta in value */
if (sr_info->autocomp_active != val) {
if (!val)
@@ -896,7 +918,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
ret = sr_late_init(sr_info);
if (ret) {
pr_warning("%s: Error in SR late init\n", __func__);
- return ret;
+ goto err_iounmap;
}
}
@@ -1010,10 +1032,75 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
return 0;
}
+static int omap_sr_suspend(struct device *dev)
+{
+ struct omap_sr_data *pdata;
+ struct omap_sr *sr_info;
+
+ pdata = dev_get_platdata(dev);
+ if (!pdata) {
+ dev_err(dev, "%s: platform data missing\n", __func__);
+ return -EINVAL;
+ }
+
+ sr_info = _sr_lookup(pdata->voltdm);
+ if (IS_ERR(sr_info)) {
+ dev_warn(dev, "%s: omap_sr struct not found\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!sr_info->autocomp_active)
+ return 0;
+
+ if (sr_info->is_suspended)
+ return 0;
+
+ omap_sr_disable_reset_volt(pdata->voltdm);
+ sr_info->is_suspended = true;
+ /* Flag the same info to the other CPUs */
+ smp_wmb();
+
+ return 0;
+}
+
+static int omap_sr_resume(struct device *dev)
+{
+ struct omap_sr_data *pdata;
+ struct omap_sr *sr_info;
+
+ pdata = dev_get_platdata(dev);
+ if (!pdata) {
+ dev_err(dev, "%s: platform data missing\n", __func__);
+ return -EINVAL;
+ }
+
+ sr_info = _sr_lookup(pdata->voltdm);
+ if (IS_ERR(sr_info)) {
+ dev_warn(dev, "%s: omap_sr struct not found\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!sr_info->autocomp_active)
+ return 0;
+
+ if (!sr_info->is_suspended)
+ return 0;
+
+ sr_info->is_suspended = false;
+ /* Flag the same info to the other CPUs */
+ smp_wmb();
+ omap_sr_enable(pdata->voltdm);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(omap_sr_dev_pm_ops, omap_sr_suspend, omap_sr_resume);
+
static struct platform_driver smartreflex_driver = {
.remove = omap_sr_remove,
.driver = {
.name = "smartreflex",
+ .pm = &omap_sr_dev_pm_ops,
},
};
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index eb3b5f8..4477134 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -187,6 +187,13 @@ static inline void activate_irq(int irq)
#endif
}
+int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ int twl_irq = (int)irq_get_chip_data(d->irq);
+
+ return irq_set_irq_wake(twl_irq, on);
+}
+
/*----------------------------------------------------------------------*/
static unsigned twl6030_irq_next;
@@ -318,10 +325,12 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
twl6030_irq_chip = dummy_irq_chip;
twl6030_irq_chip.name = "twl6030";
twl6030_irq_chip.irq_set_type = NULL;
+ twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
for (i = irq_base; i < irq_end; i++) {
irq_set_chip_and_handler(i, &twl6030_irq_chip,
handle_simple_irq);
+ irq_set_chip_data(i, (void *)irq_num);
activate_irq(i);
}