aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */