summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/include/mach/legacy_irq.h2
-rw-r--r--arch/arm/mach-tegra/irq.c52
-rw-r--r--arch/arm/mach-tegra/pm-irq.c62
-rw-r--r--arch/arm/mach-tegra/wakeups-t2.c69
-rw-r--r--arch/arm/mach-tegra/wakeups-t3.c91
-rw-r--r--arch/arm/mach-tegra/wakeups.c115
-rw-r--r--arch/arm/mach-tegra/wakeups.h27
-rw-r--r--drivers/gpio/gpio-tegra.c51
8 files changed, 312 insertions, 157 deletions
diff --git a/arch/arm/mach-tegra/include/mach/legacy_irq.h b/arch/arm/mach-tegra/include/mach/legacy_irq.h
index 86f1ff7d06b0..3cd2d82c342f 100644
--- a/arch/arm/mach-tegra/include/mach/legacy_irq.h
+++ b/arch/arm/mach-tegra/include/mach/legacy_irq.h
@@ -19,5 +19,7 @@
#define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
void tegra_init_legacy_irq_cop(void);
+/* lp1 wake interrupts enabled or disabled using this API */
+int tegra_update_lp1_irq_wake(unsigned int irq, bool enable);
#endif
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 450295d901dd..278912486f40 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -26,6 +26,7 @@
#include <asm/hardware/gic.h>
#include <mach/iomap.h>
+#include <mach/gpio.h>
#include <mach/legacy_irq.h>
#include "board.h"
@@ -66,10 +67,34 @@ 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;
+
+ if (irq < FIRST_LEGACY_IRQ ||
+ irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32)
+ return -EINVAL;
+
+ index = ((irq - FIRST_LEGACY_IRQ) >> 5);
+ 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;
@@ -131,11 +156,28 @@ 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_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)
{
- return tegra_pm_irq_set_wake(d->irq, enable);
+ int ret;
+
+ /* pmc lp0 wake enable for non-gpio wake sources */
+ ret = tegra_pm_irq_set_wake(d->irq, 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 ret;
}
static int tegra_legacy_irq_suspend(void)
@@ -146,9 +188,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);
@@ -167,7 +213,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);
}
diff --git a/arch/arm/mach-tegra/pm-irq.c b/arch/arm/mach-tegra/pm-irq.c
index 9b205f86f8b9..4a3f3c31830c 100644
--- a/arch/arm/mach-tegra/pm-irq.c
+++ b/arch/arm/mach-tegra/pm-irq.c
@@ -145,12 +145,15 @@ static inline void clear_pmc_sw_wake_status(void)
int tegra_pm_irq_set_wake(int irq, int enable)
{
- int wake = tegra_irq_to_wake(irq);
+ struct wake_mask_types wake_msk;
+ int flow_type = -1;
+ int err;
- if (wake == -EALREADY) {
+ err = tegra_irq_to_wake(irq, flow_type, &wake_msk);
+ if (err == -EALREADY) {
/* EALREADY means wakeup event already accounted for */
return 0;
- } else if (wake == -ENOTSUPP) {
+ } else if (err == -ENOTSUPP) {
/* ENOTSUPP means LP0 not supported with this wake source */
WARN(enable && warn_prevent_lp0, "irq %d prevents lp0\n", irq);
if (enable)
@@ -158,46 +161,43 @@ int tegra_pm_irq_set_wake(int irq, int enable)
else if (!WARN_ON(tegra_prevent_lp0 == 0))
tegra_prevent_lp0--;
return 0;
- } else if (wake < 0) {
+ } else if (err < 0) {
return -EINVAL;
}
- if (enable) {
- tegra_lp0_wake_enb |= 1ull << wake;
- pr_info("Enabling wake%d\n", wake);
- } else {
- tegra_lp0_wake_enb &= ~(1ull << wake);
- pr_info("Disabling wake%d\n", wake);
- }
+ if (enable)
+ tegra_lp0_wake_enb |= (wake_msk.wake_mask_hi |
+ wake_msk.wake_mask_lo | wake_msk.wake_mask_any);
+ else
+ tegra_lp0_wake_enb &= ~(wake_msk.wake_mask_hi |
+ wake_msk.wake_mask_lo | wake_msk.wake_mask_any);
return 0;
}
int tegra_pm_irq_set_wake_type(int irq, int flow_type)
{
- int wake = tegra_irq_to_wake(irq);
+ struct wake_mask_types wake_msk;
+ int err;
+
+ err = tegra_irq_to_wake(irq, flow_type, &wake_msk);
- if (wake < 0)
+ if (err < 0)
return 0;
- switch (flow_type) {
- case IRQF_TRIGGER_FALLING:
- case IRQF_TRIGGER_LOW:
- tegra_lp0_wake_level &= ~(1ull << wake);
- tegra_lp0_wake_level_any &= ~(1ull << wake);
- break;
- case IRQF_TRIGGER_HIGH:
- case IRQF_TRIGGER_RISING:
- tegra_lp0_wake_level |= (1ull << wake);
- tegra_lp0_wake_level_any &= ~(1ull << wake);
- break;
-
- case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
- tegra_lp0_wake_level_any |= (1ull << wake);
- break;
- default:
- return -EINVAL;
- }
+ /* configure LOW/FALLING polarity wake sources for an irq */
+ tegra_lp0_wake_level &= ~wake_msk.wake_mask_lo;
+ tegra_lp0_wake_level_any &= ~wake_msk.wake_mask_lo;
+
+ /* configure HIGH/RISING polarity wake sources for an irq */
+ tegra_lp0_wake_level |= wake_msk.wake_mask_hi;
+ tegra_lp0_wake_level_any &= ~wake_msk.wake_mask_hi;
+
+ /*
+ * configure RISING and FALLING i.e. ANY polarity wake
+ * sources for an irq
+ */
+ tegra_lp0_wake_level_any |= wake_msk.wake_mask_any;
return 0;
}
diff --git a/arch/arm/mach-tegra/wakeups-t2.c b/arch/arm/mach-tegra/wakeups-t2.c
index 8079e6820145..adfe136c8118 100644
--- a/arch/arm/mach-tegra/wakeups-t2.c
+++ b/arch/arm/mach-tegra/wakeups-t2.c
@@ -24,39 +24,40 @@
#include "gpio-names.h"
#include "wakeups.h"
-static int tegra_wake_event_irq_t2[] = {
- [0] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5),
- [1] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3),
- [2] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1),
- [3] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6),
- [4] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7),
- [5] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PA0),
- [6] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5),
- [7] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6),
- [8] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7),
- [9] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2),
- [10] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1),
- [11] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3),
- [12] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2),
- [13] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6),
- [14] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6),
- [15] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ7),
- [16] = INT_RTC,
- [17] = INT_KBC,
- [18] = INT_EXTERNAL_PMU,
- [19] = -EINVAL, /* TEGRA_USB1_VBUS, */
- [20] = -EINVAL, /* TEGRA_USB3_VBUS, */
- [21] = -EINVAL, /* TEGRA_USB1_ID, */
- [22] = -EINVAL, /* TEGRA_USB3_ID, */
- [23] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5),
- [24] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV2),
- [25] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4),
- [26] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5),
- [27] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0),
- [28] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6),
- [29] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7),
- [30] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2),
+static struct tegra_wake_info tegra_wake_event_data_t2[] = {
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PA0), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ7), POLARITY_NONE},
+ {INT_RTC, POLARITY_NONE},
+ {INT_KBC, POLARITY_NONE},
+ {INT_EXTERNAL_PMU, POLARITY_NONE},
+ {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_VBUS, */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB3_VBUS, */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB1_ID, */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB3_ID, */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV2), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), POLARITY_NONE},
};
-int *tegra_wake_event_irq = tegra_wake_event_irq_t2;
-unsigned int tegra_wake_event_irq_size = ARRAY_SIZE(tegra_wake_event_irq_t2);
+struct tegra_wake_info *tegra_wake_event_data = tegra_wake_event_data_t2;
+unsigned int tegra_wake_event_data_size = ARRAY_SIZE(tegra_wake_event_data_t2);
+
diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c
index 33dfb12f7211..ef471cb035db 100644
--- a/arch/arm/mach-tegra/wakeups-t3.c
+++ b/arch/arm/mach-tegra/wakeups-t3.c
@@ -24,50 +24,51 @@
#include "gpio-names.h"
#include "wakeups.h"
-static int tegra_wake_event_irq_t3[] = {
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), /* wake0 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1), /* wake1 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), /* wake2 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), /* wake3 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), /* wake4 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB6), /* wake5 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), /* wake6 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), /* wake7 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), /* wake8 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), /* wake9 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), /* wake10 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), /* wake11 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), /* wake12 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), /* wake13 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PDD3), /* wake14 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ2), /* wake15 */
- INT_RTC, /* wake16 */
- INT_KBC, /* wake17 */
- INT_EXTERNAL_PMU, /* wake18 */
- -EINVAL, /* TEGRA_USB1_VBUS, */ /* wake19 */
- -EINVAL, /* TEGRA_USB2_VBUS, */ /* wake20 */
- -EINVAL, /* TEGRA_USB1_ID, */ /* wake21 */
- -EINVAL, /* TEGRA_USB2_ID, */ /* wake22 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), /* wake23 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV0), /* wake24 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), /* wake25 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), /* wake26 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), /* wake27 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS6), /* wake28 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS7), /* wake29 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), /* wake30 */
- -EINVAL, /* not used */ /* wake31 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO4), /* wake32 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ0), /* wake33 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PK2), /* wake34 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI6), /* wake35 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB1), /* wake36 */
- -EINVAL, /* TEGRA_USB3_VBUS, */ /* wake37 */
- -EINVAL, /* TEGRA_USB3_ID, */ /* wake38 */
- INT_USB, /* TEGRA_USB1_UTMIP, */ /* wake39 */
- INT_USB2, /* TEGRA_USB2_UTMIP, */ /* wake40 */
- INT_USB3, /* TEGRA_USB3_UTMIP, */ /* wake41 */
+static struct tegra_wake_info tegra_wake_event_data_t3[] = {
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), POLARITY_NONE}, /* wake0 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1), POLARITY_NONE}, /* wake1 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), POLARITY_NONE}, /* wake2 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), POLARITY_NONE}, /* wake3 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), POLARITY_NONE}, /* wake4 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB6), POLARITY_NONE}, /* wake5 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), POLARITY_NONE}, /* wake6 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), POLARITY_NONE}, /* wake7 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), POLARITY_NONE}, /* wake8 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), POLARITY_NONE}, /* wake9 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), POLARITY_NONE}, /* wake10 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), POLARITY_NONE}, /* wake11 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), POLARITY_NONE}, /* wake12 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), POLARITY_NONE}, /* wake13 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PDD3), POLARITY_NONE}, /* wake14 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ2), POLARITY_NONE}, /* wake15 */
+ {INT_RTC, POLARITY_NONE}, /* wake16 */
+ {INT_KBC, POLARITY_NONE}, /* wake17 */
+ {INT_EXTERNAL_PMU, POLARITY_NONE}, /* wake18 */
+ {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_VBUS, */ /* wake19 */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB2_VBUS, */ /* wake20 */
+ {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_ID, */ /* wake21 */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB2_ID, */ /* wake22 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), POLARITY_NONE}, /* wake23 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV0), POLARITY_NONE}, /* wake24 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), POLARITY_NONE}, /* wake25 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), POLARITY_NONE}, /* wake26 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), POLARITY_NONE}, /* wake27 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS6), POLARITY_NONE}, /* wake28 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS7), POLARITY_NONE}, /* wake29 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), POLARITY_NONE}, /* wake30 */
+ {-EINVAL, POLARITY_NONE}, /* not used */ /* wake31 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO4), POLARITY_NONE}, /* wake32 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ0), POLARITY_NONE}, /* wake33 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PK2), POLARITY_NONE}, /* wake34 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI6), POLARITY_NONE}, /* wake35 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB1), POLARITY_NONE}, /* wake36 */
+ {-EINVAL, POLARITY_NONE}, /* TEGRA_USB3_VBUS, */ /* wake37 */
+ {-EINVAL, POLARITY_NONE}, /* TEGRA_USB3_ID, */ /* wake38 */
+ {INT_USB, POLARITY_LEVEL_HI}, /* TEGRA_USB1_UTMIP, */ /* wake39 */
+ {INT_USB2, POLARITY_LEVEL_HI}, /* TEGRA_USB2_UTMIP, */ /* wake40 */
+ {INT_USB3, POLARITY_LEVEL_HI} /* TEGRA_USB3_UTMIP, */ /* wake41 */
};
-int *tegra_wake_event_irq = tegra_wake_event_irq_t3;
-unsigned int tegra_wake_event_irq_size = ARRAY_SIZE(tegra_wake_event_irq_t3);
+struct tegra_wake_info *tegra_wake_event_data = tegra_wake_event_data_t3;
+unsigned int tegra_wake_event_data_size = ARRAY_SIZE(tegra_wake_event_data_t3);
+
diff --git a/arch/arm/mach-tegra/wakeups.c b/arch/arm/mach-tegra/wakeups.c
index d53563cf22ba..a52a4d50c074 100644
--- a/arch/arm/mach-tegra/wakeups.c
+++ b/arch/arm/mach-tegra/wakeups.c
@@ -27,48 +27,83 @@
#include "gpio-names.h"
#include "wakeups.h"
-extern int *tegra_wake_event_irq;
-extern unsigned int tegra_wake_event_irq_size;
+extern struct tegra_wake_info *tegra_wake_event_data;
+extern unsigned int tegra_wake_event_data_size;
-int tegra_irq_to_wake(int irq)
+/*
+ * FIXME: unable to pass rising and falling
+ * flags from usb driver hence using polarity field
+ * from wake table to set wake_mask_any
+ * for selected usb wake sources - VBUS and ID
+ */
+static int update_wake_mask(unsigned int index, int flow_type,
+ struct wake_mask_types *wake_msk)
{
- int i;
- int wake_irq;
- int search_gpio;
- static int last_wake = -1;
-
- /* Two level wake irq search for gpio based wakeups -
- * 1. check for GPIO irq(based on tegra_wake_event_irq table)
- * e.g. for a board, wake7 based on GPIO PU6 and irq==390 done first
- * 2. check for gpio bank irq assuming search for GPIO irq
- * preceded this search.
- * e.g. in this step check for gpio bank irq GPIO6 irq==119
+ int trigger_val;
+ /*
+ * set wake function calls with flow_type as -1
+ * set wake type function calls update_wake_mask with
+ * the wake polarity
*/
- for (i = 0; i < tegra_wake_event_irq_size; i++) {
- /* return if step 1 matches */
- if (tegra_wake_event_irq[i] == irq) {
- pr_info("Wake%d for irq=%d\n", i, irq);
- last_wake = i;
- return i;
+ if (flow_type == -1) {
+ pr_debug("Wake%d flow_type=%d\n",
+ index, flow_type);
+ /* use argument wake_mask_hi to return mask */
+ wake_msk->wake_mask_hi |= (1ULL << index);
+ } else {
+ trigger_val = (flow_type & IRQF_TRIGGER_MASK);
+ if ((tegra_wake_event_data[index].polarity ==
+ POLARITY_EDGE_ANY) ||
+ (trigger_val ==
+ (IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING))) {
+ pr_debug("Wake%d flow_type=ANY\n", index);
+ wake_msk->wake_mask_any |= (1ULL << index);
+ } else if ((trigger_val == IRQF_TRIGGER_HIGH) ||
+ (trigger_val == IRQF_TRIGGER_RISING)) {
+ pr_debug("Wake%d flow_type=HI\n", index);
+ wake_msk->wake_mask_hi |= (1ULL << index);
+ } else if ((trigger_val == IRQF_TRIGGER_LOW) ||
+ (trigger_val == IRQF_TRIGGER_FALLING)) {
+ pr_debug("Wake%d flow_type=LO\n", index);
+ wake_msk->wake_mask_lo |= (1ULL << index);
+ } else {
+ pr_err("Error: Wake%d UNKNOWN flow_type=%d\n",
+ index, flow_type);
+ return -EINVAL;
}
+ }
+ return 0;
+}
- /* step 2 below uses saved last_wake from step 1
- * in previous call */
- search_gpio = irq_to_gpio(
- tegra_wake_event_irq[i]);
- if (search_gpio < 0)
- continue;
- wake_irq = tegra_gpio_get_bank_int_nr(search_gpio);
- if (wake_irq < 0)
+int tegra_irq_to_wake(unsigned int irq, int flow_type,
+ struct wake_mask_types *wake_msk)
+{
+ int i;
+ int err;
+
+ wake_msk->wake_mask_hi = 0ULL;
+ wake_msk->wake_mask_lo = 0ULL;
+ wake_msk->wake_mask_any = 0ULL;
+ /*
+ * check for irq based on tegra_wake_event_data table
+ */
+ for (i = 0; i < tegra_wake_event_data_size; i++) {
+ if (tegra_wake_event_data[i].irq == irq) {
+ err = update_wake_mask(i, flow_type, wake_msk);
+ if (err)
+ return err;
continue;
- if ((last_wake == i) &&
- (wake_irq == irq)) {
- pr_info("gpio bank wake found: wake%d for irq=%d\n",
- i, irq);
- return i;
}
}
+ if (wake_msk->wake_mask_hi || wake_msk->wake_mask_lo ||
+ wake_msk->wake_mask_any) {
+ pr_debug("Enabling wake sources for irq=%d, mask hi=%#llx, lo=%#llx, any=%#llx, flow_type=%d\n",
+ irq, wake_msk->wake_mask_hi, wake_msk->wake_mask_lo,
+ wake_msk->wake_mask_any, flow_type);
+ return 0;
+ }
return -EINVAL;
}
@@ -77,9 +112,19 @@ int tegra_wake_to_irq(int wake)
if (wake < 0)
return -EINVAL;
- if (wake >= tegra_wake_event_irq_size)
+ if (wake >= tegra_wake_event_data_size)
return -EINVAL;
- return tegra_wake_event_irq[wake];
+ return tegra_wake_event_data[wake].irq;
+}
+
+int tegra_disable_wake_source(int wake)
+{
+ if (wake >= tegra_wake_event_data_size)
+ return -EINVAL;
+
+ tegra_wake_event_data[wake].irq = -EINVAL;
+
+ return 0;
}
diff --git a/arch/arm/mach-tegra/wakeups.h b/arch/arm/mach-tegra/wakeups.h
index ab113649d534..6d2f5f077601 100644
--- a/arch/arm/mach-tegra/wakeups.h
+++ b/arch/arm/mach-tegra/wakeups.h
@@ -17,13 +17,32 @@
#ifndef __WAKEUPS_H_
#define __WAKEUPS_H_
-/*
- * given irq number returns wake source index or negative value for error
- */
-int tegra_irq_to_wake(int irq);
+struct wake_mask_types {
+ u64 wake_mask_hi;
+ u64 wake_mask_lo;
+ u64 wake_mask_any;
+};
+
+/* sets 64-bit wake mask argument bits for wake sources given an irq */
+int tegra_irq_to_wake(unsigned int irq, int flow_type,
+ struct wake_mask_types *wake_msk);
/*
* given wake source index, returns irq number or negative value for error
*/
int tegra_wake_to_irq(int wake);
+/* disable selected wake source setting for particular board */
+int tegra_disable_wake_source(int wake);
+
+enum wake_polarity {
+ POLARITY_NONE = 0,
+ POLARITY_LEVEL_HI,
+ POLARITY_LEVEL_LO,
+ POLARITY_EDGE_ANY
+};
+
+struct tegra_wake_info {
+ int irq;
+ enum wake_polarity polarity;
+};
#endif /* end __WAKEUPS_H_ */
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 17e9c1cfdf4e..49abdf016b26 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -32,6 +32,7 @@
#include <asm/mach/irq.h>
#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
#include <mach/pinmux.h>
#include "../../../arch/arm/mach-tegra/pm-irq.h"
@@ -90,6 +91,7 @@ struct tegra_gpio_bank {
u32 oe[4];
u32 int_enb[4];
u32 int_lvl[4];
+ u32 wake_enb[4];
#endif
};
@@ -395,21 +397,60 @@ static int tegra_gpio_suspend(void)
return 0;
}
+static int tegra_update_lp1_gpio_wake(struct irq_data *d, bool enable)
+{
+#ifdef CONFIG_PM_SLEEP
+ struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ u8 mask;
+ u8 port_index;
+ u8 pin_index_in_bank;
+ u8 pin_in_port;
+ int gpio = d->irq - INT_GPIO_BASE;
+
+ if (gpio < 0)
+ return -EIO;
+ pin_index_in_bank = (gpio & 0x1F);
+ port_index = pin_index_in_bank >> 3;
+ pin_in_port = (pin_index_in_bank & 0x7);
+ mask = BIT(pin_in_port);
+ if (enable)
+ bank->wake_enb[port_index] |= mask;
+ else
+ bank->wake_enb[port_index] &= ~mask;
+#endif
+
+ return 0;
+}
+
static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
{
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
int ret = 0;
- ret = tegra_pm_irq_set_wake(d->irq, enable);
+ /*
+ * update LP1 mask for gpio port/pin interrupt
+ * LP1 enable independent of LP0 wake support
+ */
+ ret = tegra_update_lp1_gpio_wake(d, enable);
+ if (ret) {
+ pr_err("Failed gpio lp1 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), d->irq, ret);
+ goto fail;
+ }
+ /* LP1 enable for bank interrupt */
+ ret = tegra_update_lp1_irq_wake(bank->irq, enable);
if (ret)
- return ret;
-
- ret = irq_set_irq_wake(bank->irq, enable);
+ pr_err("Failed gpio lp1 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), bank->irq, ret);
+ /* LP0 */
+ ret = tegra_pm_irq_set_wake(d->irq, enable);
if (ret)
- tegra_pm_irq_set_wake(d->irq, !enable);
+ pr_err("Failed gpio lp0 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), d->irq, ret);
+fail:
return ret;
}
#else