summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorBitan Biswas <bbiswas@nvidia.com>2011-11-15 14:39:02 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:50:16 -0800
commitd42e1fd52adbed786f13bd22dce41fee58146465 (patch)
treefb09283a2f4f41a2dd5f96a7267adcd22d6cf483 /arch/arm/mach-tegra
parentc40df1b08359db110ef153d470e3e3da7a5ba575 (diff)
arm: tegra: power: lp0 wake enable modified
GPIO based lp0 wakeup needed to support search for its irq as well as GPIO bank irq in table. This is implemented in this change. lp0 wakeup irq enable using enable_irq_wake needs to be called in specific drivers. Additionally, in some cases wake irq needs to be updated in tegra wakeup table. bug 890309 bug 902114 Change-Id: I983318172ffb020f565763cfe2bb29018223dcd0 Reviewed-on: http://git-master/r/64395 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: Rffcadeee341a73f2ea6d62e31d507e9a8dce5a0e
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/include/mach/gpio.h1
-rw-r--r--arch/arm/mach-tegra/pm-irq.c46
-rw-r--r--arch/arm/mach-tegra/wakeups-t2.c61
-rw-r--r--arch/arm/mach-tegra/wakeups-t3.c46
4 files changed, 111 insertions, 43 deletions
diff --git a/arch/arm/mach-tegra/include/mach/gpio.h b/arch/arm/mach-tegra/include/mach/gpio.h
index dd1a249eafa9..b7357ab0c4dd 100644
--- a/arch/arm/mach-tegra/include/mach/gpio.h
+++ b/arch/arm/mach-tegra/include/mach/gpio.h
@@ -76,4 +76,5 @@ void tegra_gpio_disable(int gpio);
int tegra_gpio_resume_init(void);
void tegra_gpio_init_configure(unsigned gpio, bool is_input, int value);
void tegra_gpio_set_tristate(int gpio, enum tegra_tristate ts);
+int tegra_gpio_get_bank_int_nr(int gpio);
#endif
diff --git a/arch/arm/mach-tegra/pm-irq.c b/arch/arm/mach-tegra/pm-irq.c
index eda278ccd89c..d66e2cba8546 100644
--- a/arch/arm/mach-tegra/pm-irq.c
+++ b/arch/arm/mach-tegra/pm-irq.c
@@ -43,6 +43,8 @@
#define PMC_SW_WAKE2_STATUS 0x16C
#endif
+#define PMC_MAX_WAKE_COUNT 64
+
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
static u64 tegra_lp0_wake_enb;
@@ -50,7 +52,7 @@ static u64 tegra_lp0_wake_level;
static u64 tegra_lp0_wake_level_any;
static int tegra_prevent_lp0;
-static unsigned int tegra_wake_irq_count[64];
+static unsigned int tegra_wake_irq_count[PMC_MAX_WAKE_COUNT];
static bool debug_lp0;
module_param(debug_lp0, bool, S_IRUGO | S_IWUSR);
@@ -73,8 +75,11 @@ static void pmc_32kwritel(u32 val, unsigned long offs)
static inline void write_pmc_wake_mask(u64 value)
{
+ pr_info("Wake[31-0] enable=0x%x\n", (u32)(value & 0xFFFFFFFF));
writel((u32)value, pmc + PMC_WAKE_MASK);
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ pr_info("Tegra3 wake[63-32] enable=0x%x\n", (u32)((value >> 32) &
+ 0xFFFFFFFF));
__raw_writel((u32)(value >> 32), pmc + PMC_WAKE2_MASK);
#endif
}
@@ -153,10 +158,13 @@ int tegra_pm_irq_set_wake(int irq, int enable)
return -EINVAL;
}
- if (enable)
+ if (enable) {
tegra_lp0_wake_enb |= 1ull << wake;
- else
+ pr_info("Enabling wake%d\n", wake);
+ } else {
tegra_lp0_wake_enb &= ~(1ull << wake);
+ pr_info("Disabling wake%d\n", wake);
+ }
return 0;
}
@@ -191,29 +199,33 @@ int tegra_pm_irq_set_wake_type(int irq, int flow_type)
}
/* translate lp0 wake sources back into irqs to catch edge triggered wakeups */
-static void tegra_pm_irq_syscore_resume_helper(unsigned long wake_status)
+static void tegra_pm_irq_syscore_resume_helper(
+ unsigned long wake_status,
+ unsigned int index)
{
int wake;
int irq;
struct irq_desc *desc;
for_each_set_bit(wake, &wake_status, sizeof(wake_status) * 8) {
- irq = tegra_wake_to_irq(wake);
+ irq = tegra_wake_to_irq(wake + 32 * index);
if (!irq) {
- pr_info("Resume caused by WAKE%d\n", wake);
+ pr_info("Resume caused by WAKE%d\n",
+ (wake + 32 * index));
continue;
}
desc = irq_to_desc(irq);
if (!desc || !desc->action || !desc->action->name) {
- pr_info("Resume caused by WAKE%d, irq %d\n", wake, irq);
+ pr_info("Resume caused by WAKE%d, irq %d\n",
+ (wake + 32 * index), irq);
continue;
}
- pr_info("Resume caused by WAKE%d, %s\n", wake,
+ pr_info("Resume caused by WAKE%d, %s\n", (wake + 32 * index),
desc->action->name);
- tegra_wake_irq_count[wake]++;
+ tegra_wake_irq_count[wake + 32 * index]++;
generic_handle_irq(irq);
}
@@ -223,9 +235,12 @@ static void tegra_pm_irq_syscore_resume(void)
{
unsigned long long wake_status = read_pmc_wake_status();
- tegra_pm_irq_syscore_resume_helper((unsigned long)wake_status);
+ pr_info(" legacy wake status=0x%x\n", (u32)wake_status);
+ tegra_pm_irq_syscore_resume_helper((unsigned long)wake_status, 0);
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- tegra_pm_irq_syscore_resume_helper((unsigned long)(wake_status >> 32));
+ pr_info(" tegra3 wake status=0x%x\n", (u32)(wake_status >> 32));
+ tegra_pm_irq_syscore_resume_helper(
+ (unsigned long)(wake_status >> 32), 1);
#endif
}
@@ -237,6 +252,7 @@ static int tegra_pm_irq_syscore_suspend(void)
u64 lvl;
u64 wake_level;
u64 wake_enb;
+ static bool is_first = true;
clear_pmc_sw_wake_status();
@@ -253,7 +269,11 @@ static int tegra_pm_irq_syscore_suspend(void)
/* flip the wakeup trigger for any-edge triggered pads
* which are currently asserting as wakeups */
- lvl ^= status;
+ if (is_first)
+ is_first = false;
+ else
+ lvl ^= status;
+
lvl &= tegra_lp0_wake_level_any;
wake_level = lvl | tegra_lp0_wake_level;
@@ -294,7 +314,7 @@ static int tegra_pm_irq_debug_show(struct seq_file *s, void *data)
seq_printf(s, "wake irq count name\n");
seq_printf(s, "----------------------\n");
- for (wake = 0; wake < 32; wake++) {
+ for (wake = 0; wake < PMC_MAX_WAKE_COUNT; wake++) {
irq = tegra_wake_to_irq(wake);
if (irq < 0)
continue;
diff --git a/arch/arm/mach-tegra/wakeups-t2.c b/arch/arm/mach-tegra/wakeups-t2.c
index 667fea714fe7..7c5d12ac60d4 100644
--- a/arch/arm/mach-tegra/wakeups-t2.c
+++ b/arch/arm/mach-tegra/wakeups-t2.c
@@ -19,11 +19,10 @@
#include <mach/iomap.h>
#include <mach/irqs.h>
+#include <mach/gpio.h>
#include "gpio-names.h"
-#define NUM_WAKE_EVENTS 31
-
static int tegra_wake_event_irq[] = {
[0] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5),
[1] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3),
@@ -44,7 +43,7 @@ static int tegra_wake_event_irq[] = {
[16] = INT_RTC,
[17] = INT_KBC,
[18] = INT_EXTERNAL_PMU,
- [19] = -EINVAL, /* TEGRA_USB1_VBUS, */
+ [19] = -EINVAL, /* TEGRA_USB1_VBUS, */
[20] = -EINVAL, /* TEGRA_USB3_VBUS, */
[21] = -EINVAL, /* TEGRA_USB1_ID, */
[22] = -EINVAL, /* TEGRA_USB3_ID, */
@@ -56,34 +55,48 @@ static int tegra_wake_event_irq[] = {
[28] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6),
[29] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7),
[30] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2),
- [31] = -EINVAL,
- /*
- * The gpio bank irqs aren't actually wake sources, but they don't
- * prevent lp0 because the gpio chained irq is requested directly
- */
- [32] = INT_GPIO1,
- [33] = INT_GPIO2,
- [34] = INT_GPIO3,
- [35] = INT_GPIO4,
- [36] = INT_GPIO5,
- [37] = INT_GPIO6,
- [38] = INT_GPIO7,
};
int tegra_irq_to_wake(int irq)
{
int i;
- for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++)
- if (tegra_wake_event_irq[i] == irq)
- break;
+ int wake_irq;
+ int search_gpio;
+ static int last_wake = -1;
- if (i == ARRAY_SIZE(tegra_wake_event_irq))
- return -ENOTSUPP;
+ /* 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
+ */
+ 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;
+ }
- if (i > NUM_WAKE_EVENTS)
- return -EALREADY;
+ /* 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)
+ continue;
+ if ((last_wake == i) &&
+ (wake_irq == irq)) {
+ pr_info("gpio bank wake found: wake%d for irq=%d\n",
+ i, irq);
+ return i;
+ }
+ }
- return i;
+ return -EINVAL;
}
int tegra_wake_to_irq(int wake)
@@ -91,7 +104,7 @@ int tegra_wake_to_irq(int wake)
if (wake < 0)
return -EINVAL;
- if (wake >= NUM_WAKE_EVENTS)
+ if (wake >= ARRAY_SIZE(tegra_wake_event_irq))
return -EINVAL;
return tegra_wake_event_irq[wake];
diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c
index da9ecbfd00d7..823736204362 100644
--- a/arch/arm/mach-tegra/wakeups-t3.c
+++ b/arch/arm/mach-tegra/wakeups-t3.c
@@ -19,12 +19,11 @@
#include <mach/iomap.h>
#include <mach/irqs.h>
+#include <mach/gpio.h>
#include "gpio-names.h"
-#define NUM_WAKE_EVENTS 39
-
-static int tegra_wake_event_irq[NUM_WAKE_EVENTS] = {
+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 */
@@ -64,14 +63,49 @@ static int tegra_wake_event_irq[NUM_WAKE_EVENTS] = {
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 */
};
int tegra_irq_to_wake(int irq)
{
int i;
- for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++)
- if (tegra_wake_event_irq[i] == irq)
+ 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
+ */
+ 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;
+ }
+
+ /* 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)
+ continue;
+ if ((last_wake == i) &&
+ (wake_irq == irq)) {
+ pr_info("gpio bank wake found: wake%d for irq=%d\n",
+ i, irq);
return i;
+ }
+ }
return -EINVAL;
}
@@ -81,7 +115,7 @@ int tegra_wake_to_irq(int wake)
if (wake < 0)
return -EINVAL;
- if (wake >= NUM_WAKE_EVENTS)
+ if (wake >= ARRAY_SIZE(tegra_wake_event_irq))
return -EINVAL;
return tegra_wake_event_irq[wake];