aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/twl4030-irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/twl4030-irq.c')
-rw-r--r--drivers/mfd/twl4030-irq.c107
1 files changed, 60 insertions, 47 deletions
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index b69bb517b102..5d656e814358 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -28,10 +28,12 @@
28 */ 28 */
29 29
30#include <linux/init.h> 30#include <linux/init.h>
31#include <linux/export.h>
31#include <linux/interrupt.h> 32#include <linux/interrupt.h>
32#include <linux/irq.h> 33#include <linux/irq.h>
33#include <linux/slab.h> 34#include <linux/slab.h>
34 35#include <linux/of.h>
36#include <linux/irqdomain.h>
35#include <linux/i2c/twl.h> 37#include <linux/i2c/twl.h>
36 38
37#include "twl-core.h" 39#include "twl-core.h"
@@ -53,13 +55,14 @@
53 * base + 8 .. base + 15 SIH for PWR_INT 55 * base + 8 .. base + 15 SIH for PWR_INT
54 * base + 16 .. base + 33 SIH for GPIO 56 * base + 16 .. base + 33 SIH for GPIO
55 */ 57 */
58#define TWL4030_CORE_NR_IRQS 8
59#define TWL4030_PWR_NR_IRQS 8
56 60
57/* PIH register offsets */ 61/* PIH register offsets */
58#define REG_PIH_ISR_P1 0x01 62#define REG_PIH_ISR_P1 0x01
59#define REG_PIH_ISR_P2 0x02 63#define REG_PIH_ISR_P2 0x02
60#define REG_PIH_SIR 0x03 /* for testing */ 64#define REG_PIH_SIR 0x03 /* for testing */
61 65
62
63/* Linux could (eventually) use either IRQ line */ 66/* Linux could (eventually) use either IRQ line */
64static int irq_line; 67static int irq_line;
65 68
@@ -111,7 +114,8 @@ static int nr_sih_modules;
111#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT 114#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT
112 115
113 116
114/* Order in this table matches order in PIH_ISR. That is, 117/*
118 * Order in this table matches order in PIH_ISR. That is,
115 * BIT(n) in PIH_ISR is sih_modules[n]. 119 * BIT(n) in PIH_ISR is sih_modules[n].
116 */ 120 */
117/* sih_modules_twl4030 is used both in twl4030 and twl5030 */ 121/* sih_modules_twl4030 is used both in twl4030 and twl5030 */
@@ -288,7 +292,6 @@ static unsigned twl4030_irq_base;
288 */ 292 */
289static irqreturn_t handle_twl4030_pih(int irq, void *devid) 293static irqreturn_t handle_twl4030_pih(int irq, void *devid)
290{ 294{
291 int module_irq;
292 irqreturn_t ret; 295 irqreturn_t ret;
293 u8 pih_isr; 296 u8 pih_isr;
294 297
@@ -299,16 +302,18 @@ static irqreturn_t handle_twl4030_pih(int irq, void *devid)
299 return IRQ_NONE; 302 return IRQ_NONE;
300 } 303 }
301 304
302 /* these handlers deal with the relevant SIH irq status */ 305 while (pih_isr) {
303 for (module_irq = twl4030_irq_base; 306 unsigned long pending = __ffs(pih_isr);
304 pih_isr; 307 unsigned int irq;
305 pih_isr >>= 1, module_irq++) { 308
306 if (pih_isr & 0x1) 309 pih_isr &= ~BIT(pending);
307 handle_nested_irq(module_irq); 310 irq = pending + twl4030_irq_base;
311 handle_nested_irq(irq);
308 } 312 }
309 313
310 return IRQ_HANDLED; 314 return IRQ_HANDLED;
311} 315}
316
312/*----------------------------------------------------------------------*/ 317/*----------------------------------------------------------------------*/
313 318
314/* 319/*
@@ -337,7 +342,6 @@ static int twl4030_init_sih_modules(unsigned line)
337 memset(buf, 0xff, sizeof buf); 342 memset(buf, 0xff, sizeof buf);
338 sih = sih_modules; 343 sih = sih_modules;
339 for (i = 0; i < nr_sih_modules; i++, sih++) { 344 for (i = 0; i < nr_sih_modules; i++, sih++) {
340
341 /* skip USB -- it's funky */ 345 /* skip USB -- it's funky */
342 if (!sih->bytes_ixr) 346 if (!sih->bytes_ixr)
343 continue; 347 continue;
@@ -352,7 +356,8 @@ static int twl4030_init_sih_modules(unsigned line)
352 pr_err("twl4030: err %d initializing %s %s\n", 356 pr_err("twl4030: err %d initializing %s %s\n",
353 status, sih->name, "IMR"); 357 status, sih->name, "IMR");
354 358
355 /* Maybe disable "exclusive" mode; buffer second pending irq; 359 /*
360 * Maybe disable "exclusive" mode; buffer second pending irq;
356 * set Clear-On-Read (COR) bit. 361 * set Clear-On-Read (COR) bit.
357 * 362 *
358 * NOTE that sometimes COR polarity is documented as being 363 * NOTE that sometimes COR polarity is documented as being
@@ -382,7 +387,8 @@ static int twl4030_init_sih_modules(unsigned line)
382 if (sih->irq_lines <= line) 387 if (sih->irq_lines <= line)
383 continue; 388 continue;
384 389
385 /* Clear pending interrupt status. Either the read was 390 /*
391 * Clear pending interrupt status. Either the read was
386 * enough, or we need to write those bits. Repeat, in 392 * enough, or we need to write those bits. Repeat, in
387 * case an IRQ is pending (PENDDIS=0) ... that's not 393 * case an IRQ is pending (PENDDIS=0) ... that's not
388 * uncommon with PWR_INT.PWRON. 394 * uncommon with PWR_INT.PWRON.
@@ -398,7 +404,8 @@ static int twl4030_init_sih_modules(unsigned line)
398 status = twl_i2c_write(sih->module, buf, 404 status = twl_i2c_write(sih->module, buf,
399 sih->mask[line].isr_offset, 405 sih->mask[line].isr_offset,
400 sih->bytes_ixr); 406 sih->bytes_ixr);
401 /* else COR=1 means read sufficed. 407 /*
408 * else COR=1 means read sufficed.
402 * (for most SIH modules...) 409 * (for most SIH modules...)
403 */ 410 */
404 } 411 }
@@ -410,7 +417,8 @@ static int twl4030_init_sih_modules(unsigned line)
410static inline void activate_irq(int irq) 417static inline void activate_irq(int irq)
411{ 418{
412#ifdef CONFIG_ARM 419#ifdef CONFIG_ARM
413 /* ARM requires an extra step to clear IRQ_NOREQUEST, which it 420 /*
421 * ARM requires an extra step to clear IRQ_NOREQUEST, which it
414 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. 422 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
415 */ 423 */
416 set_irq_flags(irq, IRQF_VALID); 424 set_irq_flags(irq, IRQF_VALID);
@@ -620,33 +628,24 @@ static irqreturn_t handle_twl4030_sih(int irq, void *data)
620 return IRQ_HANDLED; 628 return IRQ_HANDLED;
621} 629}
622 630
623static unsigned twl4030_irq_next; 631/* returns the first IRQ used by this SIH bank, or negative errno */
624 632int twl4030_sih_setup(struct device *dev, int module, int irq_base)
625/* returns the first IRQ used by this SIH bank,
626 * or negative errno
627 */
628int twl4030_sih_setup(int module)
629{ 633{
630 int sih_mod; 634 int sih_mod;
631 const struct sih *sih = NULL; 635 const struct sih *sih = NULL;
632 struct sih_agent *agent; 636 struct sih_agent *agent;
633 int i, irq; 637 int i, irq;
634 int status = -EINVAL; 638 int status = -EINVAL;
635 unsigned irq_base = twl4030_irq_next;
636 639
637 /* only support modules with standard clear-on-read for now */ 640 /* only support modules with standard clear-on-read for now */
638 for (sih_mod = 0, sih = sih_modules; 641 for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;
639 sih_mod < nr_sih_modules;
640 sih_mod++, sih++) { 642 sih_mod++, sih++) {
641 if (sih->module == module && sih->set_cor) { 643 if (sih->module == module && sih->set_cor) {
642 if (!WARN((irq_base + sih->bits) > NR_IRQS, 644 status = 0;
643 "irq %d for %s too big\n",
644 irq_base + sih->bits,
645 sih->name))
646 status = 0;
647 break; 645 break;
648 } 646 }
649 } 647 }
648
650 if (status < 0) 649 if (status < 0)
651 return status; 650 return status;
652 651
@@ -654,8 +653,6 @@ int twl4030_sih_setup(int module)
654 if (!agent) 653 if (!agent)
655 return -ENOMEM; 654 return -ENOMEM;
656 655
657 status = 0;
658
659 agent->irq_base = irq_base; 656 agent->irq_base = irq_base;
660 agent->sih = sih; 657 agent->sih = sih;
661 agent->imr = ~0; 658 agent->imr = ~0;
@@ -671,8 +668,6 @@ int twl4030_sih_setup(int module)
671 activate_irq(irq); 668 activate_irq(irq);
672 } 669 }
673 670
674 twl4030_irq_next += i;
675
676 /* replace generic PIH handler (handle_simple_irq) */ 671 /* replace generic PIH handler (handle_simple_irq) */
677 irq = sih_mod + twl4030_irq_base; 672 irq = sih_mod + twl4030_irq_base;
678 irq_set_handler_data(irq, agent); 673 irq_set_handler_data(irq, agent);
@@ -680,26 +675,43 @@ int twl4030_sih_setup(int module)
680 status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0, 675 status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
681 agent->irq_name ?: sih->name, NULL); 676 agent->irq_name ?: sih->name, NULL);
682 677
683 pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, 678 dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
684 irq, irq_base, twl4030_irq_next - 1); 679 irq, irq_base, irq_base + i - 1);
685 680
686 return status < 0 ? status : irq_base; 681 return status < 0 ? status : irq_base;
687} 682}
688 683
689/* FIXME need a call to reverse twl4030_sih_setup() ... */ 684/* FIXME need a call to reverse twl4030_sih_setup() ... */
690 685
691
692/*----------------------------------------------------------------------*/ 686/*----------------------------------------------------------------------*/
693 687
694/* FIXME pass in which interrupt line we'll use ... */ 688/* FIXME pass in which interrupt line we'll use ... */
695#define twl_irq_line 0 689#define twl_irq_line 0
696 690
697int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) 691int twl4030_init_irq(struct device *dev, int irq_num)
698{ 692{
699 static struct irq_chip twl4030_irq_chip; 693 static struct irq_chip twl4030_irq_chip;
694 int status, i;
695 int irq_base, irq_end, nr_irqs;
696 struct device_node *node = dev->of_node;
700 697
701 int status; 698 /*
702 int i; 699 * TWL core and pwr interrupts must be contiguous because
700 * the hwirqs numbers are defined contiguously from 1 to 15.
701 * Create only one domain for both.
702 */
703 nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
704
705 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
706 if (IS_ERR_VALUE(irq_base)) {
707 dev_err(dev, "Fail to allocate IRQ descs\n");
708 return irq_base;
709 }
710
711 irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
712 &irq_domain_simple_ops, NULL);
713
714 irq_end = irq_base + TWL4030_CORE_NR_IRQS;
703 715
704 /* 716 /*
705 * Mask and clear all TWL4030 interrupts since initially we do 717 * Mask and clear all TWL4030 interrupts since initially we do
@@ -711,7 +723,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
711 723
712 twl4030_irq_base = irq_base; 724 twl4030_irq_base = irq_base;
713 725
714 /* install an irq handler for each of the SIH modules; 726 /*
727 * Install an irq handler for each of the SIH modules;
715 * clone dummy irq_chip since PIH can't *do* anything 728 * clone dummy irq_chip since PIH can't *do* anything
716 */ 729 */
717 twl4030_irq_chip = dummy_irq_chip; 730 twl4030_irq_chip = dummy_irq_chip;
@@ -725,14 +738,14 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
725 irq_set_nested_thread(i, 1); 738 irq_set_nested_thread(i, 1);
726 activate_irq(i); 739 activate_irq(i);
727 } 740 }
728 twl4030_irq_next = i; 741
729 pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", 742 dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",
730 irq_num, irq_base, twl4030_irq_next - 1); 743 irq_num, irq_base, irq_end);
731 744
732 /* ... and the PWR_INT module ... */ 745 /* ... and the PWR_INT module ... */
733 status = twl4030_sih_setup(TWL4030_MODULE_INT); 746 status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);
734 if (status < 0) { 747 if (status < 0) {
735 pr_err("twl4030: sih_setup PWR INT --> %d\n", status); 748 dev_err(dev, "sih_setup PWR INT --> %d\n", status);
736 goto fail; 749 goto fail;
737 } 750 }
738 751
@@ -741,11 +754,11 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
741 IRQF_ONESHOT, 754 IRQF_ONESHOT,
742 "TWL4030-PIH", NULL); 755 "TWL4030-PIH", NULL);
743 if (status < 0) { 756 if (status < 0) {
744 pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status); 757 dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);
745 goto fail_rqirq; 758 goto fail_rqirq;
746 } 759 }
747 760
748 return status; 761 return irq_base;
749fail_rqirq: 762fail_rqirq:
750 /* clean up twl4030_sih_setup */ 763 /* clean up twl4030_sih_setup */
751fail: 764fail: