diff options
Diffstat (limited to 'drivers/gpio/pl061.c')
| -rw-r--r-- | drivers/gpio/pl061.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index aa8e7cb020d9..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 | } |
| @@ -221,7 +231,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) | |||
| 221 | struct pl061_gpio *chip; | 231 | struct pl061_gpio *chip; |
| 222 | struct list_head *chip_list; | 232 | struct list_head *chip_list; |
| 223 | int ret, irq, i; | 233 | int ret, irq, i; |
| 224 | static unsigned long init_irq[BITS_TO_LONGS(NR_IRQS)]; | 234 | static DECLARE_BITMAP(init_irq, NR_IRQS); |
| 225 | 235 | ||
| 226 | pdata = dev->dev.platform_data; | 236 | pdata = dev->dev.platform_data; |
| 227 | if (pdata == NULL) | 237 | if (pdata == NULL) |
| @@ -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); |
| @@ -280,6 +291,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) | |||
| 280 | if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ | 291 | if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ |
| 281 | chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); | 292 | chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); |
| 282 | if (chip_list == NULL) { | 293 | if (chip_list == NULL) { |
| 294 | clear_bit(irq, init_irq); | ||
| 283 | ret = -ENOMEM; | 295 | ret = -ENOMEM; |
| 284 | goto iounmap; | 296 | goto iounmap; |
| 285 | } | 297 | } |
