arm: tegra: power: lp0 wake enable modified
Bitan Biswas [Tue, 15 Nov 2011 09:09:02 +0000 (14:09 +0530)]
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

arch/arm/mach-tegra/include/mach/gpio-tegra.h
arch/arm/mach-tegra/pm-irq.c
arch/arm/mach-tegra/wakeups-t2.c
arch/arm/mach-tegra/wakeups-t3.c
drivers/gpio/gpio-tegra.c

index b8847cd..4ff659e 100644 (file)
@@ -34,5 +34,6 @@ struct gpio_init_pin_info {
 };
 
 void tegra_gpio_init_configure(unsigned gpio, bool is_input, int value);
+void tegra_gpio_set_tristate(int gpio, enum tegra_tristate ts);
 
 #endif
index 74dcb11..6fcbb74 100644 (file)
@@ -42,6 +42,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;
@@ -49,7 +51,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);
@@ -72,8 +74,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
 }
@@ -152,10 +157,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;
 }
@@ -190,29 +198,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);
        }
@@ -222,9 +234,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
 }
 
@@ -236,6 +251,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();
 
@@ -252,7 +268,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;
@@ -293,7 +313,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;
index 4d5c63f..5ffb1c7 100644 (file)
@@ -23,8 +23,6 @@
 #include "gpio-names.h"
 #include "iomap.h"
 
-#define NUM_WAKE_EVENTS 31
-
 /* TODO: We could populate the other table from this one at runtime
  * instead of always searching twice */
 static int tegra_gpio_wakes[] = {
@@ -59,14 +57,6 @@ static int tegra_gpio_wakes[] = {
        [28] = TEGRA_GPIO_PQ6,
        [29] = TEGRA_GPIO_PQ7,
        [30] = TEGRA_GPIO_PN2,
-       [31] = -EINVAL,
-       [32] = -EINVAL,
-       [33] = -EINVAL,
-       [34] = -EINVAL,
-       [35] = -EINVAL,
-       [36] = -EINVAL,
-       [37] = -EINVAL,
-       [38] = -EINVAL,
 };
 
 static int tegra_wake_event_irq[] = {
@@ -89,7 +79,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, */
@@ -101,39 +91,38 @@ static int tegra_wake_event_irq[] = {
        [28] = -EAGAIN,
        [29] = -EAGAIN,
        [30] = -EAGAIN,
-       [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;
+       static int last_wake = -1;
+
        for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++)
                if (tegra_wake_event_irq[i] == irq)
-                       break;
-
-       if (i == ARRAY_SIZE(tegra_wake_event_irq)) {
-               for (i = 0; i < ARRAY_SIZE(tegra_gpio_wakes); i++)
-                       if (gpio_to_irq(tegra_gpio_wakes[i]) == irq)
-                               break;
+                       goto out;
+
+       for (i = 0; i < ARRAY_SIZE(tegra_gpio_wakes); i++)
+               if (gpio_to_irq(tegra_gpio_wakes[i]) == irq)
+                       goto out;
+
+       /* 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
+        */
+       if (last_wake < 0 || last_wake >= ARRAY_SIZE(tegra_gpio_wakes))
+               return -EINVAL;
 
-               if (i == ARRAY_SIZE(tegra_gpio_wakes))
-                       return -ENOTSUPP;
-       }
+       if (tegra_gpio_get_bank_int_nr(tegra_gpio_wakes[last_wake]) == irq)
+               return last_wake;
 
-       if (i > NUM_WAKE_EVENTS)
-               return -EALREADY;
+       return -EINVAL;
 
+out:
+       last_wake = i;
        return i;
 }
 
@@ -144,7 +133,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;
 
        ret = tegra_wake_event_irq[wake];
index e0175b4..26757e9 100644 (file)
 #include <linux/io.h>
 
 #include <mach/irqs.h>
+#include <mach/gpio-tegra.h>
 
 #include "gpio-names.h"
 #include "iomap.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,48 @@ 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 = 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;
+               }
+       }
 
        return -EINVAL;
 }
@@ -81,7 +114,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];
index 0243723..1d432f1 100644 (file)
@@ -109,6 +109,19 @@ static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
        tegra_gpio_writel(val, reg);
 }
 
+int tegra_gpio_get_bank_int_nr(int gpio)
+{
+       int bank;
+       int irq;
+       if (gpio >= TEGRA_NR_GPIOS) {
+               pr_warn("%s : Invalid gpio ID - %d\n", __func__, gpio);
+               return -EINVAL;
+       }
+       bank = gpio >> 5;
+       irq = tegra_gpio_banks[bank].irq;
+       return irq;
+}
+
 static void tegra_gpio_enable(int gpio)
 {
        if (gpio >= TEGRA_NR_GPIOS) {