summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/irq.c
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2012-07-31 16:27:34 +0530
committerVarun Colbert <vcolbert@nvidia.com>2012-08-01 19:10:44 -0700
commit02569866aeb63d3404351f90d6ba2d88b3087282 (patch)
tree8b040b9fe9c262df8e858e910fd53217db683a7a /arch/arm/mach-tegra/irq.c
parentb34dc18e7d9fb67f11980fe4737ba1abcc3a34be (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.c49
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);
}