diff options
author | Colin Cross <ccross@android.com> | 2011-11-01 18:47:18 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-11-03 14:13:45 -0700 |
commit | 8ab5eec38348bf7521c09bc33b05aec5eea66c62 (patch) | |
tree | 8350e9c93b2ab91d5782f670dd7734a0d62f1f34 /drivers/gpio/gpio-omap.c | |
parent | 203f3a9979dfa0983c5462086e17dc5c30a5625e (diff) | |
download | kernel_samsung_tuna-8ab5eec38348bf7521c09bc33b05aec5eea66c62.zip kernel_samsung_tuna-8ab5eec38348bf7521c09bc33b05aec5eea66c62.tar.gz kernel_samsung_tuna-8ab5eec38348bf7521c09bc33b05aec5eea66c62.tar.bz2 |
ARM: omap: gpio: set wakeupenable bits when entering idle modes
THe pad wakeupenable bits are required to wake through a gpio when
in OFF or OSWR. If the wakeupenable bits are set when the controller
is not in idle, a PRCM and a GPIO interrupt will occur for every
interrupt. Set the wakeupenable bits for every active gpio
interrupt when entering any gpio idle mode.
Also sets the irq chip flag IRQCHIP_MASK_ON_SUSPEND to cause the
irq pm code to mask all non-wake gpios in suspend, which will
ensure the wakeupenable bit is not set on non-wake gpios.
Change-Id: I03b8d954a65f8cc47388319e983decf03308448f
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
-rw-r--r-- | drivers/gpio/gpio-omap.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 8fff8e1..5b45bc1 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/bitops.h> #include <mach/hardware.h> #include <asm/irq.h> @@ -29,6 +30,8 @@ #include <asm/mach/irq.h> #include <plat/omap-pm.h> +#include "../mux.h" + static LIST_HEAD(omap_gpio_list); struct gpio_regs { @@ -46,6 +49,7 @@ struct gpio_regs { u32 debounce_en; u32 edge_falling; u32 edge_rising; + u32 pad_set_wakeupenable; }; struct gpio_bank { @@ -81,6 +85,8 @@ struct gpio_bank { void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); struct omap_gpio_reg_offs *regs; + + struct omap_mux *mux[32]; }; static void omap_gpio_mod_init(struct gpio_bank *bank); @@ -761,6 +767,7 @@ static struct irq_chip gpio_irq_chip = { .irq_unmask = gpio_unmask_irq, .irq_set_type = gpio_irq_type, .irq_set_wake = gpio_wake_enable, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; /*---------------------------------------------------------------------*/ @@ -941,6 +948,8 @@ static struct lock_class_key gpio_lock_class; static void omap_gpio_mod_init(struct gpio_bank *bank) { + int i; + if (bank->width == 32) { u32 clr_all = 0; /* clear all the bits */ u32 set_all = 0xFFFFFFFF; /* set all the bits */ @@ -1036,6 +1045,11 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) ULPD_CAM_CLK_CTRL); } } + + for (i = 0; i < bank->width; i++) { + int gpio = irq_to_gpio(bank->virtual_irq_start + i); + bank->mux[i] = omap_mux_get_gpio(gpio); + } } static __init void @@ -1271,6 +1285,35 @@ static int omap_gpio_resume(struct device *dev) #ifdef CONFIG_ARCH_OMAP2PLUS static void omap_gpio_save_context(struct gpio_bank *bank); static void omap_gpio_restore_context(struct gpio_bank *bank); + +static void omap2_gpio_set_wakeupenables(struct gpio_bank *bank) +{ + unsigned long pad_wakeup; + int i; + + bank->context.pad_set_wakeupenable = 0; + + pad_wakeup = __raw_readl(bank->base + bank->regs->irqenable); + + for_each_set_bit(i, &pad_wakeup, bank->width) { + if (!omap_mux_get_wakeupenable(bank->mux[i])) { + bank->context.pad_set_wakeupenable |= BIT(i); + omap_mux_set_wakeupenable(bank->mux[i]); + } + } +} + +static void omap2_gpio_clear_wakeupenables(struct gpio_bank *bank) +{ + unsigned long pad_wakeup; + int i; + + pad_wakeup = bank->context.pad_set_wakeupenable; + + for_each_set_bit(i, &pad_wakeup, bank->width) + omap_mux_clear_wakeupenable(bank->mux[i]); +} + #endif static int omap_gpio_pm_runtime_suspend(struct device *dev) @@ -1473,6 +1516,8 @@ int omap2_gpio_prepare_for_idle(int off_mode) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { + omap2_gpio_set_wakeupenables(bank); + if (!bank->mod_usage || !bank->loses_context || !off_mode) { if (omap2_gpio_set_edge_wakeup(bank)) ret = -EBUSY; @@ -1496,6 +1541,8 @@ void omap2_gpio_resume_after_idle(int off_mode) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { + omap2_gpio_clear_wakeupenables(bank); + if (!bank->mod_usage || !bank->loses_context || !off_mode) { omap2_gpio_restore_edge_wakeup(bank); continue; |