diff options
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cpuidle44xx.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap-wakeupgen.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap2plus-cpufreq.c | 49 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm-debug.c | 74 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.h | 8 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm44xx.c | 29 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.c | 12 | ||||
-rw-r--r-- | arch/arm/mach-omap2/smartreflex.c | 89 | ||||
-rw-r--r-- | drivers/mfd/twl6030-irq.c | 9 |
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); } |