Skip to content

Commit

Permalink
ARM: OMAP: Clear level-triggered GPIO interrupts in unmask hook
Browse files Browse the repository at this point in the history
The clearing was moved to the unmask hook because it is known to run
after the interrupt handler has actually run.  Before this patch, if
interrupts are threaded, the clearing/unmasking of level triggered
interrupts would be done before the threaded handler actually ran.

Signed-off-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
  • Loading branch information
Kevin Hilman authored and Tony Lindgren committed Apr 14, 2008
1 parent d94577d commit b144ff6
Showing 1 changed file with 13 additions and 14 deletions.
27 changes: 13 additions & 14 deletions arch/arm/plat-omap/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ struct gpio_bank {
u32 saved_fallingdetect;
u32 saved_risingdetect;
#endif
u32 level_mask;
spinlock_t lock;
struct gpio_chip chip;
};
Expand Down Expand Up @@ -538,6 +539,9 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
bank->enabled_non_wakeup_gpios &= ~gpio_bit;
}

bank->level_mask =
__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) |
__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
/*
* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only
* level triggering requested.
Expand Down Expand Up @@ -1021,12 +1025,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
isr &= 0x0000ffff;

if (cpu_class_is_omap2()) {
level_mask =
__raw_readl(bank->base +
OMAP24XX_GPIO_LEVELDETECT0) |
__raw_readl(bank->base +
OMAP24XX_GPIO_LEVELDETECT1);
level_mask &= enabled;
level_mask = bank->level_mask & enabled;
}

/* clear edge sensitive interrupts before handler(s) are
Expand Down Expand Up @@ -1088,14 +1087,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
retrigger |= irq_mask;
}
}

if (cpu_class_is_omap2()) {
/* clear level sensitive interrupts after handler(s) */
_enable_gpio_irqbank(bank, isr_saved & level_mask, 0);
_clear_gpio_irqbank(bank, isr_saved & level_mask);
_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
Expand Down Expand Up @@ -1134,6 +1125,14 @@ static void gpio_unmask_irq(unsigned int irq)
{
unsigned int gpio = irq - IH_GPIO_BASE;
struct gpio_bank *bank = get_irq_chip_data(irq);
unsigned int irq_mask = 1 << get_gpio_index(gpio);

/* For level-triggered GPIOs, the clearing must be done after
* the HW source is cleared, thus after the handler has run */
if (bank->level_mask & irq_mask) {
_set_gpio_irqenable(bank, gpio, 0);
_clear_gpio_irqstatus(bank, gpio);
}

_set_gpio_irqenable(bank, gpio, 1);
}
Expand Down

0 comments on commit b144ff6

Please sign in to comment.