aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBastian Hecht <hechtb@gmail.com>2013-03-27 09:54:03 -0400
committerSimon Horman <horms+renesas@verge.net.au>2013-03-28 03:39:46 -0400
commit427cc720277c140e6a63a03237f9bf37d8076ac3 (patch)
tree4da738eed066ad302789aac37b7e7caa5a681d72
parent3b8dfa7c2f8af7613dae28ac0f3419bf75ead5d0 (diff)
irqchip: intc-irqpin: Add support for shared interrupt lines
On some hardware we don't have a 1-1 mapping from the external interrupts coming from INTC to the GIC SPI pins. We can however share lines to demux incoming IRQs on these SoCs. This patch enables the intc_irqpin driver to detect requests for shared interrupt lines and demuxes them properly by querying the INTC INTREQx0A registers. If you need multiple shared intc_irqpin device instances, be sure to mask out all interrupts on the INTC that share the one line before you start to register them. Else you run into IRQ floods that would be caused by interrupts for which no handler has been set up yet when the first intc_irqpin device is registered. Signed-off-by: Bastian Hecht <hechtb+renesas@gmail.com> Acked-by: Magnus Damm <damm@opensource.se> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c90
1 files changed, 83 insertions, 7 deletions
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index fd5dabc2235d..5a68e5accec1 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -74,6 +74,8 @@ struct intc_irqpin_priv {
74 struct platform_device *pdev; 74 struct platform_device *pdev;
75 struct irq_chip irq_chip; 75 struct irq_chip irq_chip;
76 struct irq_domain *irq_domain; 76 struct irq_domain *irq_domain;
77 bool shared_irqs;
78 u8 shared_irq_mask;
77}; 79};
78 80
79static unsigned long intc_irqpin_read32(void __iomem *iomem) 81static unsigned long intc_irqpin_read32(void __iomem *iomem)
@@ -193,6 +195,28 @@ static void intc_irqpin_irq_disable(struct irq_data *d)
193 intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq); 195 intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq);
194} 196}
195 197
198static void intc_irqpin_shared_irq_enable(struct irq_data *d)
199{
200 struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
201 int hw_irq = irqd_to_hwirq(d);
202
203 intc_irqpin_dbg(&p->irq[hw_irq], "shared enable");
204 intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq);
205
206 p->shared_irq_mask &= ~BIT(hw_irq);
207}
208
209static void intc_irqpin_shared_irq_disable(struct irq_data *d)
210{
211 struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
212 int hw_irq = irqd_to_hwirq(d);
213
214 intc_irqpin_dbg(&p->irq[hw_irq], "shared disable");
215 intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq);
216
217 p->shared_irq_mask |= BIT(hw_irq);
218}
219
196static void intc_irqpin_irq_enable_force(struct irq_data *d) 220static void intc_irqpin_irq_enable_force(struct irq_data *d)
197{ 221{
198 struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 222 struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
@@ -261,6 +285,25 @@ static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id)
261 return IRQ_NONE; 285 return IRQ_NONE;
262} 286}
263 287
288static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id)
289{
290 struct intc_irqpin_priv *p = dev_id;
291 unsigned int reg_source = intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE);
292 irqreturn_t status = IRQ_NONE;
293 int k;
294
295 for (k = 0; k < 8; k++) {
296 if (reg_source & BIT(7 - k)) {
297 if (BIT(k) & p->shared_irq_mask)
298 continue;
299
300 status |= intc_irqpin_irq_handler(irq, &p->irq[k]);
301 }
302 }
303
304 return status;
305}
306
264static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq, 307static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq,
265 irq_hw_number_t hw) 308 irq_hw_number_t hw)
266{ 309{
@@ -292,6 +335,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
292 void (*enable_fn)(struct irq_data *d); 335 void (*enable_fn)(struct irq_data *d);
293 void (*disable_fn)(struct irq_data *d); 336 void (*disable_fn)(struct irq_data *d);
294 const char *name = dev_name(&pdev->dev); 337 const char *name = dev_name(&pdev->dev);
338 int ref_irq;
295 int ret; 339 int ret;
296 int k; 340 int k;
297 341
@@ -372,13 +416,29 @@ static int intc_irqpin_probe(struct platform_device *pdev)
372 for (k = 0; k < p->number_of_irqs; k++) 416 for (k = 0; k < p->number_of_irqs; k++)
373 intc_irqpin_mask_unmask_prio(p, k, 1); 417 intc_irqpin_mask_unmask_prio(p, k, 1);
374 418
419 /* clear all pending interrupts */
420 intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, 0x0);
421
422 /* scan for shared interrupt lines */
423 ref_irq = p->irq[0].requested_irq;
424 p->shared_irqs = true;
425 for (k = 1; k < p->number_of_irqs; k++) {
426 if (ref_irq != p->irq[k].requested_irq) {
427 p->shared_irqs = false;
428 break;
429 }
430 }
431
375 /* use more severe masking method if requested */ 432 /* use more severe masking method if requested */
376 if (p->config.control_parent) { 433 if (p->config.control_parent) {
377 enable_fn = intc_irqpin_irq_enable_force; 434 enable_fn = intc_irqpin_irq_enable_force;
378 disable_fn = intc_irqpin_irq_disable_force; 435 disable_fn = intc_irqpin_irq_disable_force;
379 } else { 436 } else if (!p->shared_irqs) {
380 enable_fn = intc_irqpin_irq_enable; 437 enable_fn = intc_irqpin_irq_enable;
381 disable_fn = intc_irqpin_irq_disable; 438 disable_fn = intc_irqpin_irq_disable;
439 } else {
440 enable_fn = intc_irqpin_shared_irq_enable;
441 disable_fn = intc_irqpin_shared_irq_disable;
382 } 442 }
383 443
384 irq_chip = &p->irq_chip; 444 irq_chip = &p->irq_chip;
@@ -400,18 +460,34 @@ static int intc_irqpin_probe(struct platform_device *pdev)
400 goto err0; 460 goto err0;
401 } 461 }
402 462
403 /* request and set priority on interrupts one by one */ 463 if (p->shared_irqs) {
404 for (k = 0; k < p->number_of_irqs; k++) { 464 /* request one shared interrupt */
405 if (devm_request_irq(&pdev->dev, p->irq[k].requested_irq, 465 if (devm_request_irq(&pdev->dev, p->irq[0].requested_irq,
406 intc_irqpin_irq_handler, 466 intc_irqpin_shared_irq_handler,
407 0, name, &p->irq[k])) { 467 IRQF_SHARED, name, p)) {
408 dev_err(&pdev->dev, "failed to request low IRQ\n"); 468 dev_err(&pdev->dev, "failed to request low IRQ\n");
409 ret = -ENOENT; 469 ret = -ENOENT;
410 goto err1; 470 goto err1;
411 } 471 }
412 intc_irqpin_mask_unmask_prio(p, k, 0); 472 } else {
473 /* request interrupts one by one */
474 for (k = 0; k < p->number_of_irqs; k++) {
475 if (devm_request_irq(&pdev->dev,
476 p->irq[k].requested_irq,
477 intc_irqpin_irq_handler,
478 0, name, &p->irq[k])) {
479 dev_err(&pdev->dev,
480 "failed to request low IRQ\n");
481 ret = -ENOENT;
482 goto err1;
483 }
484 }
413 } 485 }
414 486
487 /* unmask all interrupts on prio level */
488 for (k = 0; k < p->number_of_irqs; k++)
489 intc_irqpin_mask_unmask_prio(p, k, 0);
490
415 dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); 491 dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs);
416 492
417 /* warn in case of mismatch if irq base is specified */ 493 /* warn in case of mismatch if irq base is specified */