twl4030-irq.c (10ce3cc919f50c2043b41ca968b43c26a3672600) twl4030-irq.c (78518ffa08fceee42d61359303c58bdd0a82033f)
1/*
2 * twl4030-irq.c - TWL4030/TPS659x0 irq support
3 *
4 * Copyright (C) 2005-2006 Texas Instruments, Inc.
5 *
6 * Modifications to defer interrupt handling to a kernel thread:
7 * Copyright (C) 2006 MontaVista Software, Inc.
8 *

--- 14 unchanged lines hidden (view full) ---

23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29
30#include <linux/init.h>
1/*
2 * twl4030-irq.c - TWL4030/TPS659x0 irq support
3 *
4 * Copyright (C) 2005-2006 Texas Instruments, Inc.
5 *
6 * Modifications to defer interrupt handling to a kernel thread:
7 * Copyright (C) 2006 MontaVista Software, Inc.
8 *

--- 14 unchanged lines hidden (view full) ---

23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29
30#include <linux/init.h>
31#include <linux/export.h>
31#include <linux/interrupt.h>
32#include <linux/irq.h>
33#include <linux/slab.h>
34
32#include <linux/interrupt.h>
33#include <linux/irq.h>
34#include <linux/slab.h>
35
36#include <linux/of.h>
37#include <linux/irqdomain.h>
35#include <linux/i2c/twl.h>
36
37#include "twl-core.h"
38
39/*
40 * TWL4030 IRQ handling has two stages in hardware, and thus in software.
41 * The Primary Interrupt Handler (PIH) stage exposes status bits saying
42 * which Secondary Interrupt Handler (SIH) stage is raising an interrupt.

--- 5 unchanged lines hidden (view full) ---

48 * and mask registers in the PIH and SIH modules.
49 *
50 * We set up IRQs starting at a platform-specified base, always starting
51 * with PIH and the SIH for PWR_INT and then usually adding GPIO:
52 * base + 0 .. base + 7 PIH
53 * base + 8 .. base + 15 SIH for PWR_INT
54 * base + 16 .. base + 33 SIH for GPIO
55 */
38#include <linux/i2c/twl.h>
39
40#include "twl-core.h"
41
42/*
43 * TWL4030 IRQ handling has two stages in hardware, and thus in software.
44 * The Primary Interrupt Handler (PIH) stage exposes status bits saying
45 * which Secondary Interrupt Handler (SIH) stage is raising an interrupt.

--- 5 unchanged lines hidden (view full) ---

51 * and mask registers in the PIH and SIH modules.
52 *
53 * We set up IRQs starting at a platform-specified base, always starting
54 * with PIH and the SIH for PWR_INT and then usually adding GPIO:
55 * base + 0 .. base + 7 PIH
56 * base + 8 .. base + 15 SIH for PWR_INT
57 * base + 16 .. base + 33 SIH for GPIO
58 */
59#define TWL4030_CORE_NR_IRQS 8
60#define TWL4030_PWR_NR_IRQS 8
56
57/* PIH register offsets */
58#define REG_PIH_ISR_P1 0x01
59#define REG_PIH_ISR_P2 0x02
60#define REG_PIH_SIR 0x03 /* for testing */
61
61
62/* PIH register offsets */
63#define REG_PIH_ISR_P1 0x01
64#define REG_PIH_ISR_P2 0x02
65#define REG_PIH_SIR 0x03 /* for testing */
66
62
63/* Linux could (eventually) use either IRQ line */
64static int irq_line;
65
66struct sih {
67 char name[8];
68 u8 module; /* module id */
69 u8 control_offset; /* for SIH_CTRL */
70 bool set_cor;

--- 35 unchanged lines hidden (view full) ---

106 }, },
107
108/* register naming policies are inconsistent ... */
109#define TWL4030_INT_PWR_EDR TWL4030_INT_PWR_EDR1
110#define TWL4030_MODULE_KEYPAD_KEYP TWL4030_MODULE_KEYPAD
111#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT
112
113
67/* Linux could (eventually) use either IRQ line */
68static int irq_line;
69
70struct sih {
71 char name[8];
72 u8 module; /* module id */
73 u8 control_offset; /* for SIH_CTRL */
74 bool set_cor;

--- 35 unchanged lines hidden (view full) ---

110 }, },
111
112/* register naming policies are inconsistent ... */
113#define TWL4030_INT_PWR_EDR TWL4030_INT_PWR_EDR1
114#define TWL4030_MODULE_KEYPAD_KEYP TWL4030_MODULE_KEYPAD
115#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT
116
117
114/* Order in this table matches order in PIH_ISR. That is,
118/*
119 * Order in this table matches order in PIH_ISR. That is,
115 * BIT(n) in PIH_ISR is sih_modules[n].
116 */
117/* sih_modules_twl4030 is used both in twl4030 and twl5030 */
118static const struct sih sih_modules_twl4030[6] = {
119 [0] = {
120 .name = "gpio",
121 .module = TWL4030_MODULE_GPIO,
122 .control_offset = REG_GPIO_SIH_CTRL,

--- 181 unchanged lines hidden (view full) ---

304 pih_isr;
305 pih_isr >>= 1, module_irq++) {
306 if (pih_isr & 0x1)
307 handle_nested_irq(module_irq);
308 }
309
310 return IRQ_HANDLED;
311}
120 * BIT(n) in PIH_ISR is sih_modules[n].
121 */
122/* sih_modules_twl4030 is used both in twl4030 and twl5030 */
123static const struct sih sih_modules_twl4030[6] = {
124 [0] = {
125 .name = "gpio",
126 .module = TWL4030_MODULE_GPIO,
127 .control_offset = REG_GPIO_SIH_CTRL,

--- 181 unchanged lines hidden (view full) ---

309 pih_isr;
310 pih_isr >>= 1, module_irq++) {
311 if (pih_isr & 0x1)
312 handle_nested_irq(module_irq);
313 }
314
315 return IRQ_HANDLED;
316}
317
312/*----------------------------------------------------------------------*/
313
314/*
315 * twl4030_init_sih_modules() ... start from a known state where no
316 * IRQs will be coming in, and where we can quickly enable them then
317 * handle them as they arrive. Mask all IRQs: maybe init SIH_CTRL.
318 *
319 * NOTE: we don't touch EDR registers here; they stay with hardware

--- 12 unchanged lines hidden (view full) ---

332 return -EINVAL;
333
334 irq_line = line;
335
336 /* disable all interrupts on our line */
337 memset(buf, 0xff, sizeof buf);
338 sih = sih_modules;
339 for (i = 0; i < nr_sih_modules; i++, sih++) {
318/*----------------------------------------------------------------------*/
319
320/*
321 * twl4030_init_sih_modules() ... start from a known state where no
322 * IRQs will be coming in, and where we can quickly enable them then
323 * handle them as they arrive. Mask all IRQs: maybe init SIH_CTRL.
324 *
325 * NOTE: we don't touch EDR registers here; they stay with hardware

--- 12 unchanged lines hidden (view full) ---

338 return -EINVAL;
339
340 irq_line = line;
341
342 /* disable all interrupts on our line */
343 memset(buf, 0xff, sizeof buf);
344 sih = sih_modules;
345 for (i = 0; i < nr_sih_modules; i++, sih++) {
340
341 /* skip USB -- it's funky */
342 if (!sih->bytes_ixr)
343 continue;
344
345 /* Not all the SIH modules support multiple interrupt lines */
346 if (sih->irq_lines <= line)
347 continue;
348
349 status = twl_i2c_write(sih->module, buf,
350 sih->mask[line].imr_offset, sih->bytes_ixr);
351 if (status < 0)
352 pr_err("twl4030: err %d initializing %s %s\n",
353 status, sih->name, "IMR");
354
346 /* skip USB -- it's funky */
347 if (!sih->bytes_ixr)
348 continue;
349
350 /* Not all the SIH modules support multiple interrupt lines */
351 if (sih->irq_lines <= line)
352 continue;
353
354 status = twl_i2c_write(sih->module, buf,
355 sih->mask[line].imr_offset, sih->bytes_ixr);
356 if (status < 0)
357 pr_err("twl4030: err %d initializing %s %s\n",
358 status, sih->name, "IMR");
359
355 /* Maybe disable "exclusive" mode; buffer second pending irq;
360 /*
361 * Maybe disable "exclusive" mode; buffer second pending irq;
356 * set Clear-On-Read (COR) bit.
357 *
358 * NOTE that sometimes COR polarity is documented as being
359 * inverted: for MADC, COR=1 means "clear on write".
360 * And for PWR_INT it's not documented...
361 */
362 if (sih->set_cor) {
363 status = twl_i2c_write_u8(sih->module,

--- 13 unchanged lines hidden (view full) ---

377 /* skip USB */
378 if (!sih->bytes_ixr)
379 continue;
380
381 /* Not all the SIH modules support multiple interrupt lines */
382 if (sih->irq_lines <= line)
383 continue;
384
362 * set Clear-On-Read (COR) bit.
363 *
364 * NOTE that sometimes COR polarity is documented as being
365 * inverted: for MADC, COR=1 means "clear on write".
366 * And for PWR_INT it's not documented...
367 */
368 if (sih->set_cor) {
369 status = twl_i2c_write_u8(sih->module,

--- 13 unchanged lines hidden (view full) ---

383 /* skip USB */
384 if (!sih->bytes_ixr)
385 continue;
386
387 /* Not all the SIH modules support multiple interrupt lines */
388 if (sih->irq_lines <= line)
389 continue;
390
385 /* Clear pending interrupt status. Either the read was
391 /*
392 * Clear pending interrupt status. Either the read was
386 * enough, or we need to write those bits. Repeat, in
387 * case an IRQ is pending (PENDDIS=0) ... that's not
388 * uncommon with PWR_INT.PWRON.
389 */
390 for (j = 0; j < 2; j++) {
391 status = twl_i2c_read(sih->module, rxbuf,
392 sih->mask[line].isr_offset, sih->bytes_ixr);
393 if (status < 0)
394 pr_err("twl4030: err %d initializing %s %s\n",
395 status, sih->name, "ISR");
396
397 if (!sih->set_cor)
398 status = twl_i2c_write(sih->module, buf,
399 sih->mask[line].isr_offset,
400 sih->bytes_ixr);
393 * enough, or we need to write those bits. Repeat, in
394 * case an IRQ is pending (PENDDIS=0) ... that's not
395 * uncommon with PWR_INT.PWRON.
396 */
397 for (j = 0; j < 2; j++) {
398 status = twl_i2c_read(sih->module, rxbuf,
399 sih->mask[line].isr_offset, sih->bytes_ixr);
400 if (status < 0)
401 pr_err("twl4030: err %d initializing %s %s\n",
402 status, sih->name, "ISR");
403
404 if (!sih->set_cor)
405 status = twl_i2c_write(sih->module, buf,
406 sih->mask[line].isr_offset,
407 sih->bytes_ixr);
401 /* else COR=1 means read sufficed.
408 /*
409 * else COR=1 means read sufficed.
402 * (for most SIH modules...)
403 */
404 }
405 }
406
407 return 0;
408}
409
410static inline void activate_irq(int irq)
411{
412#ifdef CONFIG_ARM
410 * (for most SIH modules...)
411 */
412 }
413 }
414
415 return 0;
416}
417
418static inline void activate_irq(int irq)
419{
420#ifdef CONFIG_ARM
413 /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
421 /*
422 * ARM requires an extra step to clear IRQ_NOREQUEST, which it
414 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
415 */
416 set_irq_flags(irq, IRQF_VALID);
417#else
418 /* same effect on other architectures */
419 irq_set_noprobe(irq);
420#endif
421}

--- 195 unchanged lines hidden (view full) ---

617 pr_err("twl4030: %s SIH, invalid ISR bit %d\n",
618 sih->name, irq);
619 }
620 return IRQ_HANDLED;
621}
622
623static unsigned twl4030_irq_next;
624
423 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
424 */
425 set_irq_flags(irq, IRQF_VALID);
426#else
427 /* same effect on other architectures */
428 irq_set_noprobe(irq);
429#endif
430}

--- 195 unchanged lines hidden (view full) ---

626 pr_err("twl4030: %s SIH, invalid ISR bit %d\n",
627 sih->name, irq);
628 }
629 return IRQ_HANDLED;
630}
631
632static unsigned twl4030_irq_next;
633
625/* returns the first IRQ used by this SIH bank,
626 * or negative errno
627 */
634/* returns the first IRQ used by this SIH bank, or negative errno */
628int twl4030_sih_setup(int module)
629{
630 int sih_mod;
631 const struct sih *sih = NULL;
632 struct sih_agent *agent;
633 int i, irq;
634 int status = -EINVAL;
635 unsigned irq_base = twl4030_irq_next;

--- 47 unchanged lines hidden (view full) ---

683 pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
684 irq, irq_base, twl4030_irq_next - 1);
685
686 return status < 0 ? status : irq_base;
687}
688
689/* FIXME need a call to reverse twl4030_sih_setup() ... */
690
635int twl4030_sih_setup(int module)
636{
637 int sih_mod;
638 const struct sih *sih = NULL;
639 struct sih_agent *agent;
640 int i, irq;
641 int status = -EINVAL;
642 unsigned irq_base = twl4030_irq_next;

--- 47 unchanged lines hidden (view full) ---

690 pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
691 irq, irq_base, twl4030_irq_next - 1);
692
693 return status < 0 ? status : irq_base;
694}
695
696/* FIXME need a call to reverse twl4030_sih_setup() ... */
697
691
692/*----------------------------------------------------------------------*/
693
694/* FIXME pass in which interrupt line we'll use ... */
695#define twl_irq_line 0
696
698/*----------------------------------------------------------------------*/
699
700/* FIXME pass in which interrupt line we'll use ... */
701#define twl_irq_line 0
702
697int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
703int twl4030_init_irq(struct device *dev, int irq_num)
698{
699 static struct irq_chip twl4030_irq_chip;
704{
705 static struct irq_chip twl4030_irq_chip;
706 int irq_base, irq_end, nr_irqs;
707 struct device_node *node = dev->of_node;
700
701 int status;
702 int i;
703
704 /*
708
709 int status;
710 int i;
711
712 /*
713 * TWL core and pwr interrupts must be contiguous because
714 * the hwirqs numbers are defined contiguously from 1 to 15.
715 * Create only one domain for both.
716 */
717 nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
718
719 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
720 if (IS_ERR_VALUE(irq_base)) {
721 dev_err(dev, "Fail to allocate IRQ descs\n");
722 return irq_base;
723 }
724
725 irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
726 &irq_domain_simple_ops, NULL);
727
728 irq_end = irq_base + TWL4030_CORE_NR_IRQS;
729
730 /*
705 * Mask and clear all TWL4030 interrupts since initially we do
706 * not have any TWL4030 module interrupt handlers present
707 */
708 status = twl4030_init_sih_modules(twl_irq_line);
709 if (status < 0)
710 return status;
711
712 twl4030_irq_base = irq_base;
713
731 * Mask and clear all TWL4030 interrupts since initially we do
732 * not have any TWL4030 module interrupt handlers present
733 */
734 status = twl4030_init_sih_modules(twl_irq_line);
735 if (status < 0)
736 return status;
737
738 twl4030_irq_base = irq_base;
739
714 /* install an irq handler for each of the SIH modules;
740 /*
741 * install an irq handler for each of the SIH modules;
715 * clone dummy irq_chip since PIH can't *do* anything
716 */
717 twl4030_irq_chip = dummy_irq_chip;
718 twl4030_irq_chip.name = "twl4030";
719
720 twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack;
721
722 for (i = irq_base; i < irq_end; i++) {

--- 17 unchanged lines hidden (view full) ---

740 status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih,
741 IRQF_ONESHOT,
742 "TWL4030-PIH", NULL);
743 if (status < 0) {
744 pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
745 goto fail_rqirq;
746 }
747
742 * clone dummy irq_chip since PIH can't *do* anything
743 */
744 twl4030_irq_chip = dummy_irq_chip;
745 twl4030_irq_chip.name = "twl4030";
746
747 twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack;
748
749 for (i = irq_base; i < irq_end; i++) {

--- 17 unchanged lines hidden (view full) ---

767 status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih,
768 IRQF_ONESHOT,
769 "TWL4030-PIH", NULL);
770 if (status < 0) {
771 pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
772 goto fail_rqirq;
773 }
774
748 return status;
775 return irq_base;
749fail_rqirq:
750 /* clean up twl4030_sih_setup */
751fail:
752 for (i = irq_base; i < irq_end; i++) {
753 irq_set_nested_thread(i, 0);
754 irq_set_chip_and_handler(i, NULL, NULL);
755 }
756

--- 25 unchanged lines hidden ---
776fail_rqirq:
777 /* clean up twl4030_sih_setup */
778fail:
779 for (i = irq_base; i < irq_end; i++) {
780 irq_set_nested_thread(i, 0);
781 irq_set_chip_and_handler(i, NULL, NULL);
782 }
783

--- 25 unchanged lines hidden ---