summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2012-07-31 16:27:34 +0530
committerVarun Colbert <vcolbert@nvidia.com>2012-08-01 19:10:44 -0700
commit02569866aeb63d3404351f90d6ba2d88b3087282 (patch)
tree8b040b9fe9c262df8e858e910fd53217db683a7a /drivers/gpio
parentb34dc18e7d9fb67f11980fe4737ba1abcc3a34be (diff)
ARM: tegra: support multiple wake sources with same irq
Partial port of commit 48651d264bdb2ff90624e965b8a68b011077ca7c (http://git-master/r/103140). Earlier implementation only allowed single wake source for a particular irq in wake table. Changed implementation to support multiple wake sources ==> single irq mapping. Test: Cardhu boots up fine and can pass 100 suspend-resume cycles. Change-Id: I3345181d1e9a084e8b745234c4ffb11df5c68ff3 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/119641 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpio-tegra.c51
1 files changed, 46 insertions, 5 deletions
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 8db4ce1215cf..546a510b6ce8 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -35,6 +35,7 @@
#include <mach/gpio-tegra.h>
#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
#include <mach/pinmux.h>
#include "../../arch/arm/mach-tegra/pm-irq.h"
@@ -79,6 +80,7 @@ struct tegra_gpio_bank {
u32 oe[4];
u32 int_enb[4];
u32 int_lvl[4];
+ u32 wake_enb[4];
#endif
};
@@ -390,26 +392,65 @@ 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->hwirq;
+
+ 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;
int wake = tegra_gpio_to_wake(d->hwirq);
- ret = tegra_pm_irq_set_wake(wake, 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);
+ ret = tegra_pm_irq_set_wake(wake, enable);
if (ret)
- tegra_pm_irq_set_wake(wake, !enable);
+ pr_err("Failed gpio lp0 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), d->irq, ret);
+fail:
return ret;
}
#else
#define tegra_gpio_irq_set_wake NULL
+#define tegra_update_lp1_gpio_wake NULL
#define tegra_gpio_suspend NULL
#define tegra_gpio_resume NULL
#endif