Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / gpio / timbgpio.c
index ddd0531..4529366 100644 (file)
@@ -47,6 +47,7 @@ struct timbgpio {
        spinlock_t              lock; /* mutual exclusion */
        struct gpio_chip        gpio;
        int                     irq_base;
+       unsigned long           last_ier;
 };
 
 static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
@@ -112,16 +113,24 @@ static void timbgpio_irq_disable(unsigned irq)
 {
        struct timbgpio *tgpio = get_irq_chip_data(irq);
        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)
 {
        struct timbgpio *tgpio = get_irq_chip_data(irq);
        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)
@@ -194,8 +203,16 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
        ipr = ioread32(tgpio->membase + TGPIO_IPR);
        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)
                generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));
+
+       iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
 }
 
 static struct irq_chip timbgpio_irqchip = {