Commit 76d800a5 authored by Tomas Hallenberg's avatar Tomas Hallenberg Committed by Linus Torvalds

gpio: timbgpio: use a copy of the IER register to avoid it being trashed

Some versions of the hardware can trash the IER register if simultaneous
interrupts occur.  This patch works around it by using a local copy of the
register and restoring it after every interrupt.
Signed-off-by: default avatarTomas Hallenberg <tomas.hallenberg@pelagicore.com>
Acked-by: default avatarRichard Röjfors <richard.rojfors@pelagicore.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 09cd9527
...@@ -47,6 +47,7 @@ struct timbgpio { ...@@ -47,6 +47,7 @@ struct timbgpio {
spinlock_t lock; /* mutual exclusion */ spinlock_t lock; /* mutual exclusion */
struct gpio_chip gpio; struct gpio_chip gpio;
int irq_base; int irq_base;
unsigned long last_ier;
}; };
static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
...@@ -112,16 +113,24 @@ static void timbgpio_irq_disable(unsigned irq) ...@@ -112,16 +113,24 @@ static void timbgpio_irq_disable(unsigned irq)
{ {
struct timbgpio *tgpio = get_irq_chip_data(irq); struct timbgpio *tgpio = get_irq_chip_data(irq);
int offset = irq - tgpio->irq_base; int offset = irq - tgpio->irq_base;
unsigned long flags;
timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0); spin_lock_irqsave(&tgpio->lock, flags);
tgpio->last_ier &= ~(1 << offset);
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
spin_unlock_irqrestore(&tgpio->lock, flags);
} }
static void timbgpio_irq_enable(unsigned irq) static void timbgpio_irq_enable(unsigned irq)
{ {
struct timbgpio *tgpio = get_irq_chip_data(irq); struct timbgpio *tgpio = get_irq_chip_data(irq);
int offset = irq - tgpio->irq_base; int offset = irq - tgpio->irq_base;
unsigned long flags;
timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1); spin_lock_irqsave(&tgpio->lock, flags);
tgpio->last_ier |= 1 << offset;
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
spin_unlock_irqrestore(&tgpio->lock, flags);
} }
static int timbgpio_irq_type(unsigned irq, unsigned trigger) static int timbgpio_irq_type(unsigned irq, unsigned trigger)
...@@ -194,8 +203,16 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) ...@@ -194,8 +203,16 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
ipr = ioread32(tgpio->membase + TGPIO_IPR); ipr = ioread32(tgpio->membase + TGPIO_IPR);
iowrite32(ipr, tgpio->membase + TGPIO_ICR); iowrite32(ipr, tgpio->membase + TGPIO_ICR);
/*
* Some versions of the hardware trash the IER register if more than
* one interrupt is received simultaneously.
*/
iowrite32(0, tgpio->membase + TGPIO_IER);
for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio) for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio)
generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset)); generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
} }
static struct irq_chip timbgpio_irqchip = { static struct irq_chip timbgpio_irqchip = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment