diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-02 15:04:12 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-02 15:04:12 -0700 |
commit | a8c4c20dfa8b28a3c99e33c639d9c2ea5657741e (patch) | |
tree | 887b64d29b5a46d9ab2ca1267d8a2f05b5845561 /arch/arm/plat-omap/gpio.c | |
parent | 168d04b3b4de7723eb73b3cffc9cb75224e0f393 (diff) | |
parent | 2dc7667b9d0674db6572723356fe3857031101a4 (diff) |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (44 commits)
[ARM] 3541/2: workaround for PXA27x erratum E7
[ARM] nommu: provide a way for correct control register value selection
[ARM] 3705/1: add supersection support to ioremap()
[ARM] 3707/1: iwmmxt: use the generic thread notifier infrastructure
[ARM] 3706/2: ep93xx: add cirrus logic edb9315a support
[ARM] 3704/1: format IOP Kconfig with tabs, create more consistency
[ARM] 3703/1: Add help description for ARCH_EP80219
[ARM] 3678/1: MMC: Make OMAP MMC work
[ARM] 3677/1: OMAP: Update H2 defconfig
[ARM] 3676/1: ARM: OMAP: Fix dmtimers and timer32k to compile on OMAP1
[ARM] Add section support to ioremap
[ARM] Fix sa11x0 SDRAM selection
[ARM] Set bit 4 on section mappings correctly depending on CPU
[ARM] 3666/1: TRIZEPS4 [1/5] core
ARM: OMAP: Multiplexing for 24xx GPMC wait pin monitoring
ARM: OMAP: Fix SRAM to use MT_MEMORY instead of MT_DEVICE
ARM: OMAP: Update dmtimers
ARM: OMAP: Make clock variables static
ARM: OMAP: Fix GPMC compilation when DEBUG is defined
ARM: OMAP: Mux updates for external DMA and GPIO
...
Diffstat (limited to 'arch/arm/plat-omap/gpio.c')
-rw-r--r-- | arch/arm/plat-omap/gpio.c | 103 |
1 files changed, 94 insertions, 9 deletions
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 418b88fbea8..ae08eeec7aa 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -536,6 +536,49 @@ static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); } +static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) +{ + void __iomem *reg = bank->base; + int inv = 0; + u32 l; + u32 mask; + + switch (bank->method) { + case METHOD_MPUIO: + reg += OMAP_MPUIO_GPIO_MASKIT; + mask = 0xffff; + inv = 1; + break; + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_INT_MASK; + mask = 0xffff; + inv = 1; + break; + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_IRQENABLE1; + mask = 0xffff; + break; + case METHOD_GPIO_730: + reg += OMAP730_GPIO_INT_MASK; + mask = 0xffffffff; + inv = 1; + break; + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_IRQENABLE1; + mask = 0xffffffff; + break; + default: + BUG(); + return 0; + } + + l = __raw_readl(reg); + if (inv) + l = ~l; + l &= mask; + return l; +} + static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) { void __iomem *reg = bank->base; @@ -735,6 +778,8 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, u32 isr; unsigned int gpio_irq; struct gpio_bank *bank; + u32 retrigger = 0; + int unmasked = 0; desc->chip->ack(irq); @@ -759,18 +804,22 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, #endif while(1) { u32 isr_saved, level_mask = 0; + u32 enabled; - isr_saved = isr = __raw_readl(isr_reg); + enabled = _get_gpio_irqbank_mask(bank); + isr_saved = isr = __raw_readl(isr_reg) & enabled; if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) isr &= 0x0000ffff; - if (cpu_is_omap24xx()) + if (cpu_is_omap24xx()) { level_mask = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) | __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + level_mask &= enabled; + } /* clear edge sensitive interrupts before handler(s) are called so that we don't miss any interrupt occurred while @@ -781,19 +830,54 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, /* if there is only edge sensitive GPIO pin interrupts configured, we could unmask GPIO bank interrupt immediately */ - if (!level_mask) + if (!level_mask && !unmasked) { + unmasked = 1; desc->chip->unmask(irq); + } + isr |= retrigger; + retrigger = 0; if (!isr) break; gpio_irq = bank->virtual_irq_start; for (; isr != 0; isr >>= 1, gpio_irq++) { struct irqdesc *d; + int irq_mask; if (!(isr & 1)) continue; d = irq_desc + gpio_irq; + /* Don't run the handler if it's already running + * or was disabled lazely. + */ + if (unlikely((d->disable_depth || d->running))) { + irq_mask = 1 << + (gpio_irq - bank->virtual_irq_start); + /* The unmasking will be done by + * enable_irq in case it is disabled or + * after returning from the handler if + * it's already running. + */ + _enable_gpio_irqbank(bank, irq_mask, 0); + if (!d->disable_depth) { + /* Level triggered interrupts + * won't ever be reentered + */ + BUG_ON(level_mask & irq_mask); + d->pending = 1; + } + continue; + } + d->running = 1; desc_handle_irq(gpio_irq, d, regs); + d->running = 0; + if (unlikely(d->pending && !d->disable_depth)) { + irq_mask = 1 << + (gpio_irq - bank->virtual_irq_start); + d->pending = 0; + _enable_gpio_irqbank(bank, irq_mask, 1); + retrigger |= irq_mask; + } } if (cpu_is_omap24xx()) { @@ -803,13 +887,14 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); } - /* if bank has any level sensitive GPIO pin interrupt - configured, we must unmask the bank interrupt only after - handler(s) are executed in order to avoid spurious bank - interrupt */ - if (level_mask) - desc->chip->unmask(irq); } + /* if bank has any level sensitive GPIO pin interrupt + configured, we must unmask the bank interrupt only after + handler(s) are executed in order to avoid spurious bank + interrupt */ + if (!unmasked) + desc->chip->unmask(irq); + } static void gpio_ack_irq(unsigned int irq) |