summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/irq.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2011-04-03 00:02:37 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2012-03-21 22:10:25 -0700
commitf567fce84aef7053a1d62fb06d19043239f30aee (patch)
treea0eefbd0dfd267b125a9e2b5c0f567be1e409082 /arch/arm/mach-tegra/irq.c
parent51c1e3c1d2e83d160eaca1fdb186abd3adb7bdfa (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.c75
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