diff options
Diffstat (limited to 'drivers/gpio/gpio-tegra.c')
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 65 |
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 |