summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@nvidia.com>2012-05-30 00:36:39 -0700
committerVarun Wadekar <vwadekar@nvidia.com>2012-06-06 05:48:06 -0700
commitb175e51c671cf9418fdef87077bc876228320dbd (patch)
tree305d4a93849c41f015742a704779fc69b56b216d
parent7d3dd900a13552a85d7f9bfef15d0a04aac7db6a (diff)
ARM: tegra: wakeups: Refactor
TODO: Share code between T2 & T3. Move irq->wake translation to the driver layer, this lets us split out the tegra_irq_to_wake gpio searching to a tegra_gpio_to_wake function. tegra_pm_irq_set_wake: the tegra_*_to_wake() functions can never return -EALREADY or -ENOTSUPP (even before this change) This has a side effect of removing usage of TEGRA_GPIO_TO_IRQ, which is deprecated. Change-Id: I07c00952997db9f1597fd0a1caadbf4dfe1b5045 Signed-off-by: Dan Willemsen <dwillemsen@nvidia.com> Reviewed-on: http://git-master/r/106365 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Varun Wadekar <vwadekar@nvidia.com> Tested-by: Varun Wadekar <vwadekar@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/irq.c8
-rw-r--r--arch/arm/mach-tegra/pm-irq.c21
-rw-r--r--arch/arm/mach-tegra/pm-irq.h15
-rw-r--r--arch/arm/mach-tegra/wakeups-t2.c165
-rw-r--r--arch/arm/mach-tegra/wakeups-t3.c181
-rw-r--r--drivers/gpio/gpio-tegra.c8
6 files changed, 257 insertions, 141 deletions
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 4bd1f45e1f95..12e42fe704e2 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -132,14 +132,18 @@ static int tegra_retrigger(struct irq_data *d)
static int tegra_set_type(struct irq_data *d, unsigned int flow_type)
{
- return tegra_pm_irq_set_wake_type(d->irq, flow_type);
+ int wake = tegra_irq_to_wake(d->irq);
+
+ return tegra_pm_irq_set_wake_type(wake, flow_type);
}
#ifdef CONFIG_PM_SLEEP
static int tegra_set_wake(struct irq_data *d, unsigned int enable)
{
- return tegra_pm_irq_set_wake(d->irq, enable);
+ int wake = tegra_irq_to_wake(d->irq);
+
+ return tegra_pm_irq_set_wake(wake, enable);
}
static int tegra_legacy_irq_suspend(void)
diff --git a/arch/arm/mach-tegra/pm-irq.c b/arch/arm/mach-tegra/pm-irq.c
index 57d21361ca14..a09f060897f1 100644
--- a/arch/arm/mach-tegra/pm-irq.c
+++ b/arch/arm/mach-tegra/pm-irq.c
@@ -142,22 +142,9 @@ static inline void clear_pmc_sw_wake_status(void)
#endif
}
-int tegra_pm_irq_set_wake(int irq, int enable)
+int tegra_pm_irq_set_wake(int wake, int enable)
{
- int wake = tegra_irq_to_wake(irq);
-
- if (wake == -EALREADY) {
- /* EALREADY means wakeup event already accounted for */
- return 0;
- } else if (wake == -ENOTSUPP) {
- /* ENOTSUPP means LP0 not supported with this wake source */
- WARN(enable && warn_prevent_lp0, "irq %d prevents lp0\n", irq);
- if (enable)
- tegra_prevent_lp0++;
- else if (!WARN_ON(tegra_prevent_lp0 == 0))
- tegra_prevent_lp0--;
- return 0;
- } else if (wake < 0) {
+ if (wake < 0) {
return -EINVAL;
}
@@ -172,10 +159,8 @@ int tegra_pm_irq_set_wake(int irq, int enable)
return 0;
}
-int tegra_pm_irq_set_wake_type(int irq, int flow_type)
+int tegra_pm_irq_set_wake_type(int wake, int flow_type)
{
- int wake = tegra_irq_to_wake(irq);
-
if (wake < 0)
return 0;
diff --git a/arch/arm/mach-tegra/pm-irq.h b/arch/arm/mach-tegra/pm-irq.h
index 8e87b4bba246..de049eb0a54e 100644
--- a/arch/arm/mach-tegra/pm-irq.h
+++ b/arch/arm/mach-tegra/pm-irq.h
@@ -19,13 +19,22 @@
#define _MACH_TERA_PM_IRQ_H_
#ifdef CONFIG_PM_SLEEP
-int tegra_pm_irq_set_wake(int irq, int enable);
-int tegra_pm_irq_set_wake_type(int irq, int flow_type);
+int tegra_pm_irq_set_wake(int wake, int enable);
+int tegra_pm_irq_set_wake_type(int wake, int flow_type);
bool tegra_pm_irq_lp0_allowed(void);
+int tegra_gpio_to_wake(int gpio);
int tegra_irq_to_wake(int irq);
int tegra_wake_to_irq(int wake);
#else
-static inline int tegra_pm_irq_set_wake_type(int irq, int flow_type)
+static inline int tegra_pm_irq_set_wake_type(int wake, int flow_type)
+{
+ return 0;
+}
+static inline int tegra_gpio_to_wake(int gpio)
+{
+ return 0;
+}
+static inline int tegra_irq_to_wake(int irq)
{
return 0;
}
diff --git a/arch/arm/mach-tegra/wakeups-t2.c b/arch/arm/mach-tegra/wakeups-t2.c
index bba9e5baf13d..e5267b64053a 100644
--- a/arch/arm/mach-tegra/wakeups-t2.c
+++ b/arch/arm/mach-tegra/wakeups-t2.c
@@ -20,27 +20,62 @@
#include <mach/gpio-tegra.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
-#include <mach/gpio.h>
#include "gpio-names.h"
+/* TODO: We could populate the other table from this one at runtime
+ * instead of always searching twice */
+static int tegra_gpio_wakes[] = {
+ [0] = TEGRA_GPIO_PO5,
+ [1] = TEGRA_GPIO_PV3,
+ [2] = TEGRA_GPIO_PL1,
+ [3] = TEGRA_GPIO_PB6,
+ [4] = TEGRA_GPIO_PN7,
+ [5] = TEGRA_GPIO_PA0,
+ [6] = TEGRA_GPIO_PU5,
+ [7] = TEGRA_GPIO_PU6,
+ [8] = TEGRA_GPIO_PC7,
+ [9] = TEGRA_GPIO_PS2,
+ [10] = TEGRA_GPIO_PAA1,
+ [11] = TEGRA_GPIO_PW3,
+ [12] = TEGRA_GPIO_PW2,
+ [13] = TEGRA_GPIO_PY6,
+ [14] = TEGRA_GPIO_PV6,
+ [15] = TEGRA_GPIO_PJ7,
+ [16] = -EINVAL,
+ [17] = -EINVAL,
+ [18] = -EINVAL,
+ [19] = -EINVAL, /* TEGRA_USB1_VBUS, */
+ [20] = -EINVAL, /* TEGRA_USB3_VBUS, */
+ [21] = -EINVAL, /* TEGRA_USB1_ID, */
+ [22] = -EINVAL, /* TEGRA_USB3_ID, */
+ [23] = TEGRA_GPIO_PI5,
+ [24] = TEGRA_GPIO_PV2,
+ [25] = TEGRA_GPIO_PS4,
+ [26] = TEGRA_GPIO_PS5,
+ [27] = TEGRA_GPIO_PS0,
+ [28] = TEGRA_GPIO_PQ6,
+ [29] = TEGRA_GPIO_PQ7,
+ [30] = TEGRA_GPIO_PN2,
+};
+
static int tegra_wake_event_irq[] = {
- [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),
+ [0] = -EAGAIN, /* Search the GPIO table */
+ [1] = -EAGAIN,
+ [2] = -EAGAIN,
+ [3] = -EAGAIN,
+ [4] = -EAGAIN,
+ [5] = -EAGAIN,
+ [6] = -EAGAIN,
+ [7] = -EAGAIN,
+ [8] = -EAGAIN,
+ [9] = -EAGAIN,
+ [10] = -EAGAIN,
+ [11] = -EAGAIN,
+ [12] = -EAGAIN,
+ [13] = -EAGAIN,
+ [14] = -EAGAIN,
+ [15] = -EAGAIN,
[16] = INT_RTC,
[17] = INT_KBC,
[18] = INT_EXTERNAL_PMU,
@@ -48,64 +83,82 @@ static int tegra_wake_event_irq[] = {
[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),
+ [23] = -EAGAIN,
+ [24] = -EAGAIN,
+ [25] = -EAGAIN,
+ [26] = -EAGAIN,
+ [27] = -EAGAIN,
+ [28] = -EAGAIN,
+ [29] = -EAGAIN,
+ [30] = -EAGAIN,
};
+static int last_gpio = -1;
+
+int tegra_gpio_to_wake(int gpio)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_gpio_wakes); i++) {
+ if (tegra_gpio_wakes[i] == gpio) {
+ pr_info("gpio wake%d for gpio=%d\n", i, gpio);
+ last_gpio = i;
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
int tegra_irq_to_wake(int irq)
{
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==358 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 ret = -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); 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;
+ pr_info("Wake %d for irq=%d\n", i, irq);
+ ret = i;
+ goto out;
}
+ }
- /* step 2 below uses saved last_wake from step 1
- * in previous call */
- search_gpio = tegra_wake_event_irq[i] - INT_GPIO_BASE;
- if (search_gpio < 0)
- continue;
- wake_irq = tegra_gpio_get_bank_int_nr(search_gpio);
- if (wake_irq < 0)
- continue;
- if ((last_wake == i) &&
- (wake_irq == irq)) {
- pr_info("gpio bank wake found: wake%d for irq=%d\n",
- i, irq);
- return i;
- }
+ /* The gpio set_wake code bubbles the set_wake call up to the irq
+ * set_wake code. This insures that the nested irq set_wake call
+ * succeeds, even though it doesn't have to do any pm setup for the
+ * bank.
+ *
+ * This is very fragile - there's no locking, so two callers could
+ * cause issues with this.
+ */
+ if (last_gpio < 0)
+ goto out;
+
+ if (tegra_gpio_get_bank_int_nr(tegra_gpio_wakes[last_gpio]) == irq) {
+ pr_info("gpio bank wake found: wake %d for irq=%d\n", i, irq);
+ ret = last_gpio;
}
- return -EINVAL;
+out:
+ return ret;
}
int tegra_wake_to_irq(int wake)
{
+ int ret;
+
if (wake < 0)
return -EINVAL;
if (wake >= ARRAY_SIZE(tegra_wake_event_irq))
return -EINVAL;
- return tegra_wake_event_irq[wake];
+ ret = tegra_wake_event_irq[wake];
+ if (ret == -EAGAIN) {
+ ret = tegra_gpio_wakes[wake];
+ if (ret != -EINVAL)
+ ret = gpio_to_irq(ret);
+ }
+
+ return ret;
}
diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c
index 94de2e49c5f8..997de2389e77 100644
--- a/arch/arm/mach-tegra/wakeups-t3.c
+++ b/arch/arm/mach-tegra/wakeups-t3.c
@@ -23,23 +23,68 @@
#include "gpio-names.h"
+static int tegra_gpio_wakes[] = {
+ TEGRA_GPIO_PO5, /* wake0 */
+ TEGRA_GPIO_PV1, /* wake1 */
+ TEGRA_GPIO_PL1, /* wake2 */
+ TEGRA_GPIO_PB6, /* wake3 */
+ TEGRA_GPIO_PN7, /* wake4 */
+ TEGRA_GPIO_PBB6, /* wake5 */
+ TEGRA_GPIO_PU5, /* wake6 */
+ TEGRA_GPIO_PU6, /* wake7 */
+ TEGRA_GPIO_PC7, /* wake8 */
+ TEGRA_GPIO_PS2, /* wake9 */
+ TEGRA_GPIO_PAA1, /* wake10 */
+ TEGRA_GPIO_PW3, /* wake11 */
+ TEGRA_GPIO_PW2, /* wake12 */
+ TEGRA_GPIO_PY6, /* wake13 */
+ TEGRA_GPIO_PDD3, /* wake14 */
+ TEGRA_GPIO_PJ2, /* wake15 */
+ -EINVAL, /* wake16 */
+ -EINVAL, /* wake17 */
+ -EINVAL, /* wake18 */
+ -EINVAL, /* TEGRA_USB1_VBUS, */ /* wake19 */
+ -EINVAL, /* TEGRA_USB2_VBUS, */ /* wake20 */
+ -EINVAL, /* TEGRA_USB1_ID, */ /* wake21 */
+ -EINVAL, /* TEGRA_USB2_ID, */ /* wake22 */
+ TEGRA_GPIO_PI5, /* wake23 */
+ TEGRA_GPIO_PV0, /* wake24 */
+ TEGRA_GPIO_PS4, /* wake25 */
+ TEGRA_GPIO_PS5, /* wake26 */
+ TEGRA_GPIO_PS0, /* wake27 */
+ TEGRA_GPIO_PS6, /* wake28 */
+ TEGRA_GPIO_PS7, /* wake29 */
+ TEGRA_GPIO_PN2, /* wake30 */
+ -EINVAL, /* not used */ /* wake31 */
+ TEGRA_GPIO_PO4, /* wake32 */
+ TEGRA_GPIO_PJ0, /* wake33 */
+ TEGRA_GPIO_PK2, /* wake34 */
+ TEGRA_GPIO_PI6, /* wake35 */
+ TEGRA_GPIO_PBB1, /* wake36 */
+ -EINVAL, /* TEGRA_USB3_VBUS, */ /* wake37 */
+ -EINVAL, /* TEGRA_USB3_ID, */ /* wake38 */
+ -EINVAL, /* TEGRA_USB1_UTMIP, */ /* wake39 */
+ -EINVAL, /* TEGRA_USB2_UTMIP, */ /* wake40 */
+ -EINVAL, /* TEGRA_USB3_UTMIP, */ /* wake41 */
+};
+
static int tegra_wake_event_irq[] = {
- 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 */
+ -EAGAIN, /* wake0 */
+ -EAGAIN, /* wake1 */
+ -EAGAIN, /* wake2 */
+ -EAGAIN, /* wake3 */
+ -EAGAIN, /* wake4 */
+ -EAGAIN, /* wake5 */
+ -EAGAIN, /* wake6 */
+ -EAGAIN, /* wake7 */
+ -EAGAIN, /* wake8 */
+ -EAGAIN, /* wake9 */
+ -EAGAIN, /* wake10 */
+ -EAGAIN, /* wake11 */
+ -EAGAIN, /* wake12 */
+ -EAGAIN, /* wake13 */
+ -EAGAIN, /* wake14 */
+ -EAGAIN, /* wake15 */
INT_RTC, /* wake16 */
INT_KBC, /* wake17 */
INT_EXTERNAL_PMU, /* wake18 */
@@ -47,20 +92,20 @@ static int tegra_wake_event_irq[] = {
-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 */
+ -EAGAIN, /* wake23 */
+ -EAGAIN, /* wake24 */
+ -EAGAIN, /* wake25 */
+ -EAGAIN, /* wake26 */
+ -EAGAIN, /* wake27 */
+ -EAGAIN, /* wake28 */
+ -EAGAIN, /* wake29 */
+ -EAGAIN, /* 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 */
+ -EAGAIN, /* wake32 */
+ -EAGAIN, /* wake33 */
+ -EAGAIN, /* wake34 */
+ -EAGAIN, /* wake35 */
+ -EAGAIN, /* wake36 */
-EINVAL, /* TEGRA_USB3_VBUS, */ /* wake37 */
-EINVAL, /* TEGRA_USB3_ID, */ /* wake38 */
INT_USB, /* TEGRA_USB1_UTMIP, */ /* wake39 */
@@ -68,54 +113,72 @@ static int tegra_wake_event_irq[] = {
INT_USB3, /* TEGRA_USB3_UTMIP, */ /* wake41 */
};
+static int last_gpio = -1;
+
+int tegra_gpio_to_wake(int gpio)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_gpio_wakes); i++) {
+ if (tegra_gpio_wakes[i] == gpio) {
+ pr_info("gpio wake%d for gpio=%d\n", i, gpio);
+ last_gpio = i;
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
int tegra_irq_to_wake(int irq)
{
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 ret = -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); 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;
+ ret = i;
+ goto out;
}
+ }
- /* step 2 below uses saved last_wake from step 1
- * in previous call */
- search_gpio = tegra_wake_event_irq[i] - INT_GPIO_BASE;
- if (search_gpio < 0)
- continue;
- wake_irq = tegra_gpio_get_bank_int_nr(search_gpio);
- if (wake_irq < 0)
- continue;
- if ((last_wake == i) &&
- (wake_irq == irq)) {
- pr_info("gpio bank wake found: wake%d for irq=%d\n",
- i, irq);
- return i;
- }
+ /* The gpio set_wake code bubbles the set_wake call up to the irq
+ * set_wake code. This insures that the nested irq set_wake call
+ * succeeds, even though it doesn't have to do any pm setup for the
+ * bank.
+ *
+ * This is very fragile - there's no locking, so two callers could
+ * cause issues with this.
+ */
+ if (last_gpio < 0)
+ goto out;
+
+ if (tegra_gpio_get_bank_int_nr(tegra_gpio_wakes[last_gpio]) == irq) {
+ pr_info("gpio bank wake found: wake%d for irq=%d\n", i, irq);
+ ret = last_gpio;
}
- return -EINVAL;
+out:
+ return ret;
}
int tegra_wake_to_irq(int wake)
{
+ int ret;
+
if (wake < 0)
return -EINVAL;
if (wake >= ARRAY_SIZE(tegra_wake_event_irq))
return -EINVAL;
- return tegra_wake_event_irq[wake];
+ ret = tegra_wake_event_irq[wake];
+ if (ret == -EAGAIN) {
+ ret = tegra_gpio_wakes[wake];
+ if (ret != -EINVAL)
+ ret = gpio_to_irq(ret);
+ }
+
+ return ret;
}
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 8253665eafcc..e55c93d0674d 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -271,6 +271,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
int lvl_type;
int val;
unsigned long flags;
+ int wake = tegra_gpio_to_wake(d->hwirq);
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING:
@@ -311,7 +312,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
__irq_set_handler_locked(d->irq, handle_edge_irq);
- tegra_pm_irq_set_wake_type(d->irq, type);
+ tegra_pm_irq_set_wake_type(wake, type);
return 0;
}
@@ -393,8 +394,9 @@ 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;
+ int wake = tegra_gpio_to_wake(d->hwirq);
- ret = tegra_pm_irq_set_wake(d->irq, enable);
+ ret = tegra_pm_irq_set_wake(wake, enable);
if (ret)
return ret;
@@ -402,7 +404,7 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
ret = irq_set_irq_wake(bank->irq, enable);
if (ret)
- tegra_pm_irq_set_wake(d->irq, !enable);
+ tegra_pm_irq_set_wake(wake, !enable);
return ret;
}