ARM: tegra: allow 1-to-many irq to wake mapping
Bitan Biswas [Sat, 18 May 2013 21:44:41 +0000 (02:44 +0530)]
Problem:
Current Tegra wake table does not allow same USB irq to be used
for multiple wake sources.

Fix:
Changed tegra_irq_to_wake API to return multiple wake table indices

bug 1286802

Change-Id: I72e6d83cb71de76e23ea9623b6fcae34091171bb
Signed-off-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-on: http://git-master/r/231921
(cherry picked from commit b96d7c7db56bb49cd4f81190e25cf55b58794ab7)
Reviewed-on: http://git-master/r/241037
(cherry picked from commit 0e715b8054e22764e76c4f746287ba1c7c166501)
Reviewed-on: http://git-master/r/247134
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/irq.c
arch/arm/mach-tegra/pm-irq.h
arch/arm/mach-tegra/wakeups-t11x.c
arch/arm/mach-tegra/wakeups-t14x.c
arch/arm/mach-tegra/wakeups-t2.c
arch/arm/mach-tegra/wakeups-t3.c

index 5027a6e..e74952a 100644 (file)
@@ -4,17 +4,19 @@
  * Author:
  *     Colin Cross <ccross@android.com>
  *
- * Copyright (C) 2010-2012, NVIDIA Corporation
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
  *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
  *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/kernel.h>
@@ -156,9 +158,24 @@ static int tegra_retrigger(struct irq_data *d)
 
 static int tegra_set_type(struct irq_data *d, unsigned int flow_type)
 {
-       int wake = tegra_irq_to_wake(d->irq);
+       int wake_size;
+       int wake_list[PMC_MAX_WAKE_COUNT];
+       int i;
+       int err = 0;
+       int ret;
+
+       tegra_irq_to_wake(d->irq, wake_list, &wake_size);
 
-       return tegra_pm_irq_set_wake_type(wake, flow_type);
+       for (i = 0; i < wake_size; i++) {
+               ret = tegra_pm_irq_set_wake_type(wake_list[i], flow_type);
+               if (ret < 0) {
+                       pr_err("Set lp0 wake type=%d fail for irq=%d, wake%d ret=%d\n",
+                               flow_type, d->irq, wake_list[i], ret);
+                       if (!err)
+                               err = ret;
+               }
+       }
+       return err;
 }
 
 
@@ -169,14 +186,25 @@ static int tegra_set_type(struct irq_data *d, unsigned int flow_type)
  */
 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);
+       int wake_size;
+       int wake_list[PMC_MAX_WAKE_COUNT];
+       int i;
+       int err = 0;
+
+       tegra_irq_to_wake(d->irq, wake_list, &wake_size);
+
+       for (i = 0; i < wake_size; i++) {
+               /* pmc lp0 wake enable for non-gpio wake sources */
+               ret = tegra_pm_irq_set_wake(wake_list[i], enable);
+               if (ret < 0) {
+                       pr_err("Failed lp0 wake %s for irq=%d, wake%d ret=%d\n",
+                               (enable ? "enable" : "disable"), d->irq,
+                               wake_list[i], ret);
+                       if (!err)
+                               err = ret;
+               }
+       }
 
        /* lp1 wake enable for wake sources */
        ret = tegra_update_lp1_irq_wake(d->irq, enable);
index cbb7450..61af6d7 100644 (file)
 #ifndef _MACH_TERA_PM_IRQ_H_
 #define _MACH_TERA_PM_IRQ_H_
 
+#define PMC_MAX_WAKE_COUNT 64
+
 #ifdef CONFIG_PM_SLEEP
 u64 tegra_read_pmc_wake_status(void);
 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);
+void tegra_irq_to_wake(int irq, int *wak_list, int *wak_size);
 int tegra_wake_to_irq(int wake);
 int tegra_disable_wake_source(int wake);
 #else
@@ -40,9 +42,11 @@ static inline int tegra_gpio_to_wake(int gpio)
 {
        return 0;
 }
-static inline int tegra_irq_to_wake(int irq)
+static inline
+void tegra_irq_to_wake(int irq, int *wak_list, int *wak_size)
 {
-       return 0;
+       *wak_size = 0;
+       return;
 }
 static inline int tegra_disable_wake_source(int wake)
 {
index 0aa1204..5dc42fd 100644 (file)
@@ -235,18 +235,20 @@ void tegra_set_usb_wake_source(void)
        }
 }
 
-int tegra_irq_to_wake(int irq)
+void tegra_irq_to_wake(int irq, int *wak_list, int *wak_size)
 {
        int i;
-       int ret = -EINVAL;
 
+       *wak_size = 0;
        for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) {
                if (tegra_wake_event_irq[i] == irq) {
                        pr_info("Wake%d for irq=%d\n", i, irq);
-                       ret = i;
-                       goto out;
+                       wak_list[*wak_size] = i;
+                       *wak_size = *wak_size + 1;
                }
        }
+       if (*wak_size)
+               goto out;
 
        /* 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
@@ -261,11 +263,12 @@ int tegra_irq_to_wake(int irq)
 
        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;
+               wak_list[*wak_size] = last_gpio;
+               *wak_size = 1;
        }
 
 out:
-       return ret;
+       return;
 }
 
 int tegra_wake_to_irq(int wake)
index bdce9f7..f9c772b 100644 (file)
@@ -177,18 +177,20 @@ int tegra_gpio_to_wake(int gpio)
        return -EINVAL;
 }
 
-int tegra_irq_to_wake(int irq)
+void tegra_irq_to_wake(int irq, int *wak_list, int *wak_size)
 {
        int i;
-       int ret = -EINVAL;
 
+       *wak_size = 0;
        for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) {
                if (tegra_wake_event_irq[i] == irq) {
                        pr_info("Wake%d for irq=%d\n", i, irq);
-                       ret = i;
-                       goto out;
+                       wak_list[*wak_size] = i;
+                       *wak_size = *wak_size + 1;
                }
        }
+       if (*wak_size)
+                       goto out;
 
        /* 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
@@ -203,11 +205,12 @@ int tegra_irq_to_wake(int irq)
 
        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;
+               wak_list[*wak_size] = last_gpio;
+               *wak_size = 1;
        }
 
 out:
-       return ret;
+       return;
 }
 
 int tegra_wake_to_irq(int wake)
index 308f511..329c8c7 100644 (file)
@@ -114,18 +114,20 @@ int tegra_gpio_to_wake(int gpio)
        return -EINVAL;
 }
 
-int tegra_irq_to_wake(int irq)
+void tegra_irq_to_wake(int irq, int *wak_list, int *wak_size)
 {
        int i;
-       int ret = -EINVAL;
 
+       *wak_size = 0;
        for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) {
                if (tegra_wake_event_irq[i] == irq) {
                        pr_info("Wake %d for irq=%d\n", i, irq);
-                       ret = i;
-                       goto out;
+                       wak_list[*wak_size] = i;
+                       *wak_size = *wak_size + 1;
                }
        }
+       if (*wak_size)
+               goto out;
 
        /* 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
@@ -140,11 +142,12 @@ int tegra_irq_to_wake(int irq)
 
        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;
+               wak_list[*wak_size] = last_gpio;
+               *wak_size = 1;
        }
 
 out:
-       return ret;
+       return;
 }
 
 int tegra_wake_to_irq(int wake)
index e26606a..15682e2 100644 (file)
@@ -133,18 +133,20 @@ int tegra_gpio_to_wake(int gpio)
        return -EINVAL;
 }
 
-int tegra_irq_to_wake(int irq)
+void tegra_irq_to_wake(int irq, int *wak_list, int *wak_size)
 {
        int i;
-       int ret = -EINVAL;
 
+       *wak_size = 0;
        for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) {
                if (tegra_wake_event_irq[i] == irq) {
                        pr_info("Wake%d for irq=%d\n", i, irq);
-                       ret = i;
-                       goto out;
+                       wak_list[*wak_size] = i;
+                       *wak_size = *wak_size + 1;
                }
        }
+       if (*wak_size)
+               goto out;
 
        /* 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
@@ -159,11 +161,12 @@ int tegra_irq_to_wake(int irq)
 
        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;
+               wak_list[*wak_size] = last_gpio;
+               *wak_size = 1;
        }
 
 out:
-       return ret;
+       return;
 }
 
 int tegra_wake_to_irq(int wake)