diff options
author | Baruch Siach <baruch@tkos.co.il> | 2009-06-30 14:41:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-30 21:56:01 -0400 |
commit | 50efacf6711e6c75595afd9b92aa15c1e4f7c79d (patch) | |
tree | 6b23a034d4a798572f8ef62d18a2531df7a6239d /drivers | |
parent | 79d7f4ee23d41571d9e4663521b5e6604c55729a (diff) |
gpio: pl061: fix IRQ handling for GPIOs >= PL061_GPIO_NR
IRQ handling is wrong for any GPIO >= PL061_GPIO_NR.
Fix this by implementing and using a proper .to_irq method.
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/pl061.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index 80e483986699..4ee4c8367a3f 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c | |||
@@ -109,6 +109,16 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) | |||
109 | writeb(!!value << offset, chip->base + (1 << (offset + 2))); | 109 | writeb(!!value << offset, chip->base + (1 << (offset + 2))); |
110 | } | 110 | } |
111 | 111 | ||
112 | static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) | ||
113 | { | ||
114 | struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); | ||
115 | |||
116 | if (chip->irq_base == (unsigned) -1) | ||
117 | return -EINVAL; | ||
118 | |||
119 | return chip->irq_base + offset; | ||
120 | } | ||
121 | |||
112 | /* | 122 | /* |
113 | * PL061 GPIO IRQ | 123 | * PL061 GPIO IRQ |
114 | */ | 124 | */ |
@@ -200,7 +210,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) | |||
200 | desc->chip->ack(irq); | 210 | desc->chip->ack(irq); |
201 | list_for_each(ptr, chip_list) { | 211 | list_for_each(ptr, chip_list) { |
202 | unsigned long pending; | 212 | unsigned long pending; |
203 | int gpio; | 213 | int offset; |
204 | 214 | ||
205 | chip = list_entry(ptr, struct pl061_gpio, list); | 215 | chip = list_entry(ptr, struct pl061_gpio, list); |
206 | pending = readb(chip->base + GPIOMIS); | 216 | pending = readb(chip->base + GPIOMIS); |
@@ -209,8 +219,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) | |||
209 | if (pending == 0) | 219 | if (pending == 0) |
210 | continue; | 220 | continue; |
211 | 221 | ||
212 | for_each_bit(gpio, &pending, PL061_GPIO_NR) | 222 | for_each_bit(offset, &pending, PL061_GPIO_NR) |
213 | generic_handle_irq(gpio_to_irq(gpio)); | 223 | generic_handle_irq(pl061_to_irq(&chip->gc, offset)); |
214 | } | 224 | } |
215 | desc->chip->unmask(irq); | 225 | desc->chip->unmask(irq); |
216 | } | 226 | } |
@@ -251,6 +261,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) | |||
251 | chip->gc.direction_output = pl061_direction_output; | 261 | chip->gc.direction_output = pl061_direction_output; |
252 | chip->gc.get = pl061_get_value; | 262 | chip->gc.get = pl061_get_value; |
253 | chip->gc.set = pl061_set_value; | 263 | chip->gc.set = pl061_set_value; |
264 | chip->gc.to_irq = pl061_to_irq; | ||
254 | chip->gc.base = pdata->gpio_base; | 265 | chip->gc.base = pdata->gpio_base; |
255 | chip->gc.ngpio = PL061_GPIO_NR; | 266 | chip->gc.ngpio = PL061_GPIO_NR; |
256 | chip->gc.label = dev_name(&dev->dev); | 267 | chip->gc.label = dev_name(&dev->dev); |