diff options
Diffstat (limited to 'drivers/gpio/timbgpio.c')
-rw-r--r-- | drivers/gpio/timbgpio.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index ddd053108a13..45293662e950 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c | |||
@@ -47,6 +47,7 @@ struct timbgpio { | |||
47 | spinlock_t lock; /* mutual exclusion */ | 47 | spinlock_t lock; /* mutual exclusion */ |
48 | struct gpio_chip gpio; | 48 | struct gpio_chip gpio; |
49 | int irq_base; | 49 | int irq_base; |
50 | unsigned long last_ier; | ||
50 | }; | 51 | }; |
51 | 52 | ||
52 | static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, | 53 | static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, |
@@ -112,16 +113,24 @@ static void timbgpio_irq_disable(unsigned irq) | |||
112 | { | 113 | { |
113 | struct timbgpio *tgpio = get_irq_chip_data(irq); | 114 | struct timbgpio *tgpio = get_irq_chip_data(irq); |
114 | int offset = irq - tgpio->irq_base; | 115 | int offset = irq - tgpio->irq_base; |
116 | unsigned long flags; | ||
115 | 117 | ||
116 | timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0); | 118 | spin_lock_irqsave(&tgpio->lock, flags); |
119 | tgpio->last_ier &= ~(1 << offset); | ||
120 | iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); | ||
121 | spin_unlock_irqrestore(&tgpio->lock, flags); | ||
117 | } | 122 | } |
118 | 123 | ||
119 | static void timbgpio_irq_enable(unsigned irq) | 124 | static void timbgpio_irq_enable(unsigned irq) |
120 | { | 125 | { |
121 | struct timbgpio *tgpio = get_irq_chip_data(irq); | 126 | struct timbgpio *tgpio = get_irq_chip_data(irq); |
122 | int offset = irq - tgpio->irq_base; | 127 | int offset = irq - tgpio->irq_base; |
128 | unsigned long flags; | ||
123 | 129 | ||
124 | timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1); | 130 | spin_lock_irqsave(&tgpio->lock, flags); |
131 | tgpio->last_ier |= 1 << offset; | ||
132 | iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); | ||
133 | spin_unlock_irqrestore(&tgpio->lock, flags); | ||
125 | } | 134 | } |
126 | 135 | ||
127 | static int timbgpio_irq_type(unsigned irq, unsigned trigger) | 136 | 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 | ipr = ioread32(tgpio->membase + TGPIO_IPR); | 203 | ipr = ioread32(tgpio->membase + TGPIO_IPR); |
195 | iowrite32(ipr, tgpio->membase + TGPIO_ICR); | 204 | iowrite32(ipr, tgpio->membase + TGPIO_ICR); |
196 | 205 | ||
206 | /* | ||
207 | * Some versions of the hardware trash the IER register if more than | ||
208 | * one interrupt is received simultaneously. | ||
209 | */ | ||
210 | iowrite32(0, tgpio->membase + TGPIO_IER); | ||
211 | |||
197 | for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio) | 212 | for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio) |
198 | generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset)); | 213 | generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset)); |
214 | |||
215 | iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); | ||
199 | } | 216 | } |
200 | 217 | ||
201 | static struct irq_chip timbgpio_irqchip = { | 218 | static struct irq_chip timbgpio_irqchip = { |