aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-pl061.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2015-09-24 20:52:52 -0400
committerLinus Walleij <linus.walleij@linaro.org>2015-10-15 12:03:07 -0400
commit26ba9cd48fc0c2ff741de913270e9469506f3666 (patch)
treefcb9834464590ba51d36bdabd973424005374577 /drivers/gpio/gpio-pl061.c
parent21d4de1469a1da20a14a745c5f49488bba417ea7 (diff)
gpio: pl061: assign the apropriate handler for irqs
The PL061 can handle level IRQs and edge IRQs, however it is just utilizing handle_simple_irq() for all IRQs. Inspired by Stefan Agners patch to vf610, this assigns the right handler depending on what type is set up, and after this handle_bad_irq() is only used as default and if the type is not specified, as is done in the OMAP driver: defining the IRQ type is really not optional for this driver. The interrupt handler was just writing the interrupt clearing register for all lines that were high when entering the handling loop, this is wrong: that register is only supposed to be written (on a per-line basis) for edge IRQs, so this ACK was moved to the .irq_ack() callback as is proper. Tested with PL061 on the ARM RealView PB11MPCore and the MMC/SC card detect GPIO. Cc: Jonas Gorski <jogo@openwrt.org> Cc: Stefan Agner <stefan@agner.ch> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-pl061.c')
-rw-r--r--drivers/gpio/gpio-pl061.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 179339739d60..e15499936c18 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -181,7 +181,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
181 gpioiev |= bit; 181 gpioiev |= bit;
182 else 182 else
183 gpioiev &= ~bit; 183 gpioiev &= ~bit;
184 184 irq_set_handler_locked(d, handle_level_irq);
185 dev_dbg(gc->dev, "line %d: IRQ on %s level\n", 185 dev_dbg(gc->dev, "line %d: IRQ on %s level\n",
186 offset, 186 offset,
187 polarity ? "HIGH" : "LOW"); 187 polarity ? "HIGH" : "LOW");
@@ -190,7 +190,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
190 gpiois &= ~bit; 190 gpiois &= ~bit;
191 /* Select both edges, setting this makes GPIOEV be ignored */ 191 /* Select both edges, setting this makes GPIOEV be ignored */
192 gpioibe |= bit; 192 gpioibe |= bit;
193 193 irq_set_handler_locked(d, handle_edge_irq);
194 dev_dbg(gc->dev, "line %d: IRQ on both edges\n", offset); 194 dev_dbg(gc->dev, "line %d: IRQ on both edges\n", offset);
195 } else if ((trigger & IRQ_TYPE_EDGE_RISING) || 195 } else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
196 (trigger & IRQ_TYPE_EDGE_FALLING)) { 196 (trigger & IRQ_TYPE_EDGE_FALLING)) {
@@ -205,7 +205,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
205 gpioiev |= bit; 205 gpioiev |= bit;
206 else 206 else
207 gpioiev &= ~bit; 207 gpioiev &= ~bit;
208 208 irq_set_handler_locked(d, handle_edge_irq);
209 dev_dbg(gc->dev, "line %d: IRQ on %s edge\n", 209 dev_dbg(gc->dev, "line %d: IRQ on %s edge\n",
210 offset, 210 offset,
211 rising ? "RISING" : "FALLING"); 211 rising ? "RISING" : "FALLING");
@@ -214,6 +214,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
214 gpiois &= ~bit; 214 gpiois &= ~bit;
215 gpioibe &= ~bit; 215 gpioibe &= ~bit;
216 gpioiev &= ~bit; 216 gpioiev &= ~bit;
217 irq_set_handler_locked(d, handle_bad_irq);
217 dev_warn(gc->dev, "no trigger selected for line %d\n", 218 dev_warn(gc->dev, "no trigger selected for line %d\n",
218 offset); 219 offset);
219 } 220 }
@@ -238,7 +239,6 @@ static void pl061_irq_handler(struct irq_desc *desc)
238 chained_irq_enter(irqchip, desc); 239 chained_irq_enter(irqchip, desc);
239 240
240 pending = readb(chip->base + GPIOMIS); 241 pending = readb(chip->base + GPIOMIS);
241 writeb(pending, chip->base + GPIOIC);
242 if (pending) { 242 if (pending) {
243 for_each_set_bit(offset, &pending, PL061_GPIO_NR) 243 for_each_set_bit(offset, &pending, PL061_GPIO_NR)
244 generic_handle_irq(irq_find_mapping(gc->irqdomain, 244 generic_handle_irq(irq_find_mapping(gc->irqdomain,
@@ -274,8 +274,28 @@ static void pl061_irq_unmask(struct irq_data *d)
274 spin_unlock(&chip->lock); 274 spin_unlock(&chip->lock);
275} 275}
276 276
277/**
278 * pl061_irq_ack() - ACK an edge IRQ
279 * @d: IRQ data for this IRQ
280 *
281 * This gets called from the edge IRQ handler to ACK the edge IRQ
282 * in the GPIOIC (interrupt-clear) register. For level IRQs this is
283 * not needed: these go away when the level signal goes away.
284 */
285static void pl061_irq_ack(struct irq_data *d)
286{
287 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
288 struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
289 u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
290
291 spin_lock(&chip->lock);
292 writeb(mask, chip->base + GPIOIC);
293 spin_unlock(&chip->lock);
294}
295
277static struct irq_chip pl061_irqchip = { 296static struct irq_chip pl061_irqchip = {
278 .name = "pl061", 297 .name = "pl061",
298 .irq_ack = pl061_irq_ack,
279 .irq_mask = pl061_irq_mask, 299 .irq_mask = pl061_irq_mask,
280 .irq_unmask = pl061_irq_unmask, 300 .irq_unmask = pl061_irq_unmask,
281 .irq_set_type = pl061_irq_type, 301 .irq_set_type = pl061_irq_type,
@@ -338,7 +358,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
338 } 358 }
339 359
340 ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, 360 ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip,
341 irq_base, handle_simple_irq, 361 irq_base, handle_bad_irq,
342 IRQ_TYPE_NONE); 362 IRQ_TYPE_NONE);
343 if (ret) { 363 if (ret) {
344 dev_info(&adev->dev, "could not add irqchip\n"); 364 dev_info(&adev->dev, "could not add irqchip\n");