summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpio-tegra.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpio-tegra.c')
-rw-r--r--drivers/gpio/gpio-tegra.c65
1 files changed, 60 insertions, 5 deletions
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 3a0893f9cdc3..49abdf016b26 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -32,6 +32,7 @@
#include <asm/mach/irq.h>
#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
#include <mach/pinmux.h>
#include "../../../arch/arm/mach-tegra/pm-irq.h"
@@ -90,6 +91,7 @@ struct tegra_gpio_bank {
u32 oe[4];
u32 int_enb[4];
u32 int_lvl[4];
+ u32 wake_enb[4];
#endif
};
@@ -191,6 +193,7 @@ static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -199,6 +202,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
{
tegra_gpio_set(chip, offset, value);
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -213,8 +217,20 @@ static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return TEGRA_GPIO_TO_IRQ(offset);
}
+static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return 0;
+}
+
+static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ tegra_gpio_disable(offset);
+}
+
static struct gpio_chip tegra_gpio_chip = {
.label = "tegra-gpio",
+ .request = tegra_gpio_request,
+ .free = tegra_gpio_free,
.direction_input = tegra_gpio_direction_input,
.get = tegra_gpio_get,
.direction_output = tegra_gpio_direction_output,
@@ -381,21 +397,60 @@ static 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->irq - INT_GPIO_BASE;
+
+ 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;
- ret = tegra_pm_irq_set_wake(d->irq, 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);
+ /* LP0 */
+ ret = tegra_pm_irq_set_wake(d->irq, enable);
if (ret)
- tegra_pm_irq_set_wake(d->irq, !enable);
+ pr_err("Failed gpio lp0 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), d->irq, ret);
+fail:
return ret;
}
#else