diff options
author | Varun Wadekar <vwadekar@nvidia.com> | 2012-07-31 16:27:34 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2012-08-01 19:10:44 -0700 |
commit | 02569866aeb63d3404351f90d6ba2d88b3087282 (patch) | |
tree | 8b040b9fe9c262df8e858e910fd53217db683a7a /arch/arm/mach-tegra/irq.c | |
parent | b34dc18e7d9fb67f11980fe4737ba1abcc3a34be (diff) |
ARM: tegra: support multiple wake sources with same irq
Partial port of commit 48651d264bdb2ff90624e965b8a68b011077ca7c
(http://git-master/r/103140).
Earlier implementation only allowed single wake source
for a particular irq in wake table. Changed implementation
to support multiple wake sources ==> single irq mapping.
Test: Cardhu boots up fine and can pass 100 suspend-resume
cycles.
Change-Id: I3345181d1e9a084e8b745234c4ffb11df5c68ff3
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Reviewed-on: http://git-master/r/119641
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/irq.c')
-rw-r--r-- | arch/arm/mach-tegra/irq.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index cadd2b5e9054..44dfdfed89fc 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -27,6 +27,7 @@ #include <asm/hardware/gic.h> #include <mach/iomap.h> +#include <mach/gpio.h> #include <mach/legacy_irq.h> #include "board.h" @@ -70,10 +71,33 @@ static void __iomem *ictlr_reg_base[] = { #ifdef CONFIG_PM_SLEEP static u32 cop_ier[NUM_ICTLRS]; +static u32 cop_iep[NUM_ICTLRS]; static u32 cpu_ier[NUM_ICTLRS]; static u32 cpu_iep[NUM_ICTLRS]; + +static u32 ictlr_wake_mask[NUM_ICTLRS]; +#endif + +int tegra_update_lp1_irq_wake(unsigned int irq, bool enable) +{ +#ifdef CONFIG_PM_SLEEP + u8 index; + u32 mask; + + BUG_ON(irq < FIRST_LEGACY_IRQ || + irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32); + + index = ((irq - FIRST_LEGACY_IRQ) / 32); + mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); + if (enable) + ictlr_wake_mask[index] |= mask; + else + ictlr_wake_mask[index] &= ~mask; #endif + return 0; +} + static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) { void __iomem *base; @@ -139,11 +163,28 @@ static int tegra_set_type(struct irq_data *d, unsigned int flow_type) #ifdef CONFIG_PM_SLEEP +/* + * Caller ensures that tegra_set_wake (irq_set_wake callback) + * is called for non-gpio wake sources only + */ static int tegra_set_wake(struct irq_data *d, unsigned int enable) { int wake = tegra_irq_to_wake(d->irq); + int ret; + + /* pmc lp0 wake enable for non-gpio wake sources */ + ret = tegra_pm_irq_set_wake(wake, enable); + if (ret) + pr_err("Failed lp0 wake %s for irq=%d\n", + (enable ? "enable" : "disable"), d->irq); + + /* lp1 wake enable for wake sources */ + ret = tegra_update_lp1_irq_wake(d->irq, enable); + if (ret) + pr_err("Failed lp1 wake %s for irq=%d\n", + (enable ? "enable" : "disable"), d->irq); - return tegra_pm_irq_set_wake(wake, enable); + return ret; } static int tegra_legacy_irq_suspend(void) @@ -154,9 +195,13 @@ static int tegra_legacy_irq_suspend(void) local_irq_save(flags); for (i = 0; i < NUM_ICTLRS; i++) { void __iomem *ictlr = ictlr_reg_base[i]; + /* save interrupt state */ cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER); cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS); cop_ier[i] = readl(ictlr + ICTLR_COP_IER); + cop_iep[i] = readl(ictlr + ICTLR_COP_IEP_CLASS); + + /* disable COP interrupts */ writel(~0, ictlr + ICTLR_COP_IER_CLR); } local_irq_restore(flags); @@ -175,7 +220,7 @@ static void tegra_legacy_irq_resume(void) writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); writel(~0ul, ictlr + ICTLR_CPU_IER_CLR); writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); - writel(0, ictlr + ICTLR_COP_IEP_CLASS); + writel(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS); writel(~0ul, ictlr + ICTLR_COP_IER_CLR); writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET); } |