diff options
author | Colin Cross <ccross@android.com> | 2011-04-03 00:02:37 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2012-03-21 22:10:25 -0700 |
commit | f567fce84aef7053a1d62fb06d19043239f30aee (patch) | |
tree | a0eefbd0dfd267b125a9e2b5c0f567be1e409082 /arch/arm/mach-tegra/irq.c | |
parent | 51c1e3c1d2e83d160eaca1fdb186abd3adb7bdfa (diff) |
ARM: tegra: irq: Add wake irq handling
Add LP0 wake irq handling in pm-irq.c, called from irq.c and
gpio.c.
Use IRQCHIP_MASK_ON_SUSPEND for LP1 wake irq handling, when
the legacy irq controller stays powered.
Determine valid suspend modes based on requested wake sources.
Signed-off-by: Colin Cross <ccross@android.com>
Change-Id: I547bd8290c0921163054d49f43141379e8f9f493
Rebase-Id: R41bb96d898e06614c65c1cff7aa483f4caf7e93f
Diffstat (limited to 'arch/arm/mach-tegra/irq.c')
-rw-r--r-- | arch/arm/mach-tegra/irq.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 4e1afcd54fae..9ae0fefb5ba1 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -22,12 +22,14 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/syscore_ops.h> #include <asm/hardware/gic.h> #include <mach/iomap.h> #include "board.h" +#include "pm-irq.h" #define ICTLR_CPU_IEP_VFIQ 0x08 #define ICTLR_CPU_IEP_FIR 0x14 @@ -54,6 +56,12 @@ static void __iomem *ictlr_reg_base[] = { IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE), }; +#ifdef CONFIG_PM +static u32 cop_ier[NUM_ICTLRS]; +static u32 cpu_ier[NUM_ICTLRS]; +static u32 cpu_iep[NUM_ICTLRS]; +#endif + static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) { void __iomem *base; @@ -110,6 +118,70 @@ static int tegra_retrigger(struct irq_data *d) return 1; } +static int tegra_set_type(struct irq_data *d, unsigned int flow_type) +{ + return tegra_pm_irq_set_wake_type(d->irq, flow_type); +} + + +#ifdef CONFIG_PM +static int tegra_set_wake(struct irq_data *d, unsigned int enable) +{ + return tegra_pm_irq_set_wake(d->irq, enable); +} + +static int tegra_legacy_irq_suspend(void) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < NUM_ICTLRS; i++) { + void __iomem *ictlr = ictlr_reg_base[i]; + 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); + writel(~0, ictlr + ICTLR_COP_IER_CLR); + } + local_irq_restore(flags); + + return 0; +} + +static void tegra_legacy_irq_resume(void) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < NUM_ICTLRS; i++) { + void __iomem *ictlr = ictlr_reg_base[i]; + 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(~0ul, ictlr + ICTLR_COP_IER_CLR); + writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET); + } + local_irq_restore(flags); +} + +static struct syscore_ops tegra_legacy_irq_syscore_ops = { + .suspend = tegra_legacy_irq_suspend, + .resume = tegra_legacy_irq_resume, +}; + +static int tegra_legacy_irq_syscore_init(void) +{ + register_syscore_ops(&tegra_legacy_irq_syscore_ops); + + return 0; +} +subsys_initcall(tegra_legacy_irq_syscore_init); +#else +#define tegra_set_wake NULL +#endif + void __init tegra_init_irq(void) { int i; @@ -125,6 +197,9 @@ void __init tegra_init_irq(void) gic_arch_extn.irq_mask = tegra_mask; gic_arch_extn.irq_unmask = tegra_unmask; gic_arch_extn.irq_retrigger = tegra_retrigger; + gic_arch_extn.irq_set_type = tegra_set_type; + gic_arch_extn.irq_set_wake = tegra_set_wake; + gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND; /* * Check if there is a devicetree present, since the GIC will be |