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 --- |