776 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * twl4030-irq.c - TWL4030/TPS659x0 irq support4 *5 * Copyright (C) 2005-2006 Texas Instruments, Inc.6 *7 * Modifications to defer interrupt handling to a kernel thread:8 * Copyright (C) 2006 MontaVista Software, Inc.9 *10 * Based on tlv320aic23.c:11 * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>12 *13 * Code cleanup and modifications to IRQ handler.14 * by syed khasim <x0khasim@ti.com>15 */16 17#include <linux/device.h>18#include <linux/export.h>19#include <linux/interrupt.h>20#include <linux/irq.h>21#include <linux/slab.h>22#include <linux/of.h>23#include <linux/irqdomain.h>24#include <linux/mfd/twl.h>25 26#include "twl-core.h"27 28/*29 * TWL4030 IRQ handling has two stages in hardware, and thus in software.30 * The Primary Interrupt Handler (PIH) stage exposes status bits saying31 * which Secondary Interrupt Handler (SIH) stage is raising an interrupt.32 * SIH modules are more traditional IRQ components, which support per-IRQ33 * enable/disable and trigger controls; they do most of the work.34 *35 * These chips are designed to support IRQ handling from two different36 * I2C masters. Each has a dedicated IRQ line, and dedicated IRQ status37 * and mask registers in the PIH and SIH modules.38 *39 * We set up IRQs starting at a platform-specified base, always starting40 * with PIH and the SIH for PWR_INT and then usually adding GPIO:41 * base + 0 .. base + 7 PIH42 * base + 8 .. base + 15 SIH for PWR_INT43 * base + 16 .. base + 33 SIH for GPIO44 */45#define TWL4030_CORE_NR_IRQS 846#define TWL4030_PWR_NR_IRQS 847 48/* PIH register offsets */49#define REG_PIH_ISR_P1 0x0150#define REG_PIH_ISR_P2 0x0251#define REG_PIH_SIR 0x03 /* for testing */52 53/* Linux could (eventually) use either IRQ line */54static int irq_line;55 56struct sih {57 char name[8];58 u8 module; /* module id */59 u8 control_offset; /* for SIH_CTRL */60 bool set_cor;61 62 u8 bits; /* valid in isr/imr */63 u8 bytes_ixr; /* bytelen of ISR/IMR/SIR */64 65 u8 edr_offset;66 u8 bytes_edr; /* bytelen of EDR */67 68 u8 irq_lines; /* number of supported irq lines */69 70 /* SIR ignored -- set interrupt, for testing only */71 struct sih_irq_data {72 u8 isr_offset;73 u8 imr_offset;74 } mask[2];75 /* + 2 bytes padding */76};77 78static const struct sih *sih_modules;79static int nr_sih_modules;80 81#define SIH_INITIALIZER(modname, nbits) \82 .module = TWL4030_MODULE_ ## modname, \83 .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \84 .bits = nbits, \85 .bytes_ixr = DIV_ROUND_UP(nbits, 8), \86 .edr_offset = TWL4030_ ## modname ## _EDR, \87 .bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \88 .irq_lines = 2, \89 .mask = { { \90 .isr_offset = TWL4030_ ## modname ## _ISR1, \91 .imr_offset = TWL4030_ ## modname ## _IMR1, \92 }, \93 { \94 .isr_offset = TWL4030_ ## modname ## _ISR2, \95 .imr_offset = TWL4030_ ## modname ## _IMR2, \96 }, },97 98/* register naming policies are inconsistent ... */99#define TWL4030_INT_PWR_EDR TWL4030_INT_PWR_EDR1100#define TWL4030_MODULE_KEYPAD_KEYP TWL4030_MODULE_KEYPAD101#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT102 103 104/*105 * Order in this table matches order in PIH_ISR. That is,106 * BIT(n) in PIH_ISR is sih_modules[n].107 */108/* sih_modules_twl4030 is used both in twl4030 and twl5030 */109static const struct sih sih_modules_twl4030[6] = {110 [0] = {111 .name = "gpio",112 .module = TWL4030_MODULE_GPIO,113 .control_offset = REG_GPIO_SIH_CTRL,114 .set_cor = true,115 .bits = TWL4030_GPIO_MAX,116 .bytes_ixr = 3,117 /* Note: *all* of these IRQs default to no-trigger */118 .edr_offset = REG_GPIO_EDR1,119 .bytes_edr = 5,120 .irq_lines = 2,121 .mask = { {122 .isr_offset = REG_GPIO_ISR1A,123 .imr_offset = REG_GPIO_IMR1A,124 }, {125 .isr_offset = REG_GPIO_ISR1B,126 .imr_offset = REG_GPIO_IMR1B,127 }, },128 },129 [1] = {130 .name = "keypad",131 .set_cor = true,132 SIH_INITIALIZER(KEYPAD_KEYP, 4)133 },134 [2] = {135 .name = "bci",136 .module = TWL4030_MODULE_INTERRUPTS,137 .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL,138 .set_cor = true,139 .bits = 12,140 .bytes_ixr = 2,141 .edr_offset = TWL4030_INTERRUPTS_BCIEDR1,142 /* Note: most of these IRQs default to no-trigger */143 .bytes_edr = 3,144 .irq_lines = 2,145 .mask = { {146 .isr_offset = TWL4030_INTERRUPTS_BCIISR1A,147 .imr_offset = TWL4030_INTERRUPTS_BCIIMR1A,148 }, {149 .isr_offset = TWL4030_INTERRUPTS_BCIISR1B,150 .imr_offset = TWL4030_INTERRUPTS_BCIIMR1B,151 }, },152 },153 [3] = {154 .name = "madc",155 SIH_INITIALIZER(MADC, 4)156 },157 [4] = {158 /* USB doesn't use the same SIH organization */159 .name = "usb",160 },161 [5] = {162 .name = "power",163 .set_cor = true,164 SIH_INITIALIZER(INT_PWR, 8)165 },166 /* there are no SIH modules #6 or #7 ... */167};168 169static const struct sih sih_modules_twl5031[8] = {170 [0] = {171 .name = "gpio",172 .module = TWL4030_MODULE_GPIO,173 .control_offset = REG_GPIO_SIH_CTRL,174 .set_cor = true,175 .bits = TWL4030_GPIO_MAX,176 .bytes_ixr = 3,177 /* Note: *all* of these IRQs default to no-trigger */178 .edr_offset = REG_GPIO_EDR1,179 .bytes_edr = 5,180 .irq_lines = 2,181 .mask = { {182 .isr_offset = REG_GPIO_ISR1A,183 .imr_offset = REG_GPIO_IMR1A,184 }, {185 .isr_offset = REG_GPIO_ISR1B,186 .imr_offset = REG_GPIO_IMR1B,187 }, },188 },189 [1] = {190 .name = "keypad",191 .set_cor = true,192 SIH_INITIALIZER(KEYPAD_KEYP, 4)193 },194 [2] = {195 .name = "bci",196 .module = TWL5031_MODULE_INTERRUPTS,197 .control_offset = TWL5031_INTERRUPTS_BCISIHCTRL,198 .bits = 7,199 .bytes_ixr = 1,200 .edr_offset = TWL5031_INTERRUPTS_BCIEDR1,201 /* Note: most of these IRQs default to no-trigger */202 .bytes_edr = 2,203 .irq_lines = 2,204 .mask = { {205 .isr_offset = TWL5031_INTERRUPTS_BCIISR1,206 .imr_offset = TWL5031_INTERRUPTS_BCIIMR1,207 }, {208 .isr_offset = TWL5031_INTERRUPTS_BCIISR2,209 .imr_offset = TWL5031_INTERRUPTS_BCIIMR2,210 }, },211 },212 [3] = {213 .name = "madc",214 SIH_INITIALIZER(MADC, 4)215 },216 [4] = {217 /* USB doesn't use the same SIH organization */218 .name = "usb",219 },220 [5] = {221 .name = "power",222 .set_cor = true,223 SIH_INITIALIZER(INT_PWR, 8)224 },225 [6] = {226 /*227 * ECI/DBI doesn't use the same SIH organization.228 * For example, it supports only one interrupt output line.229 * That is, the interrupts are seen on both INT1 and INT2 lines.230 */231 .name = "eci_dbi",232 .module = TWL5031_MODULE_ACCESSORY,233 .bits = 9,234 .bytes_ixr = 2,235 .irq_lines = 1,236 .mask = { {237 .isr_offset = TWL5031_ACIIDR_LSB,238 .imr_offset = TWL5031_ACIIMR_LSB,239 }, },240 241 },242 [7] = {243 /* Audio accessory */244 .name = "audio",245 .module = TWL5031_MODULE_ACCESSORY,246 .control_offset = TWL5031_ACCSIHCTRL,247 .bits = 2,248 .bytes_ixr = 1,249 .edr_offset = TWL5031_ACCEDR1,250 /* Note: most of these IRQs default to no-trigger */251 .bytes_edr = 1,252 .irq_lines = 2,253 .mask = { {254 .isr_offset = TWL5031_ACCISR1,255 .imr_offset = TWL5031_ACCIMR1,256 }, {257 .isr_offset = TWL5031_ACCISR2,258 .imr_offset = TWL5031_ACCIMR2,259 }, },260 },261};262 263#undef TWL4030_MODULE_KEYPAD_KEYP264#undef TWL4030_MODULE_INT_PWR265#undef TWL4030_INT_PWR_EDR266 267/*----------------------------------------------------------------------*/268 269static unsigned twl4030_irq_base;270 271/*272 * handle_twl4030_pih() is the desc->handle method for the twl4030 interrupt.273 * This is a chained interrupt, so there is no desc->action method for it.274 * Now we need to query the interrupt controller in the twl4030 to determine275 * which module is generating the interrupt request. However, we can't do i2c276 * transactions in interrupt context, so we must defer that work to a kernel277 * thread. All we do here is acknowledge and mask the interrupt and wakeup278 * the kernel thread.279 */280static irqreturn_t handle_twl4030_pih(int irq, void *devid)281{282 irqreturn_t ret;283 u8 pih_isr;284 285 ret = twl_i2c_read_u8(TWL_MODULE_PIH, &pih_isr,286 REG_PIH_ISR_P1);287 if (ret) {288 pr_warn("twl4030: I2C error %d reading PIH ISR\n", ret);289 return IRQ_NONE;290 }291 292 while (pih_isr) {293 unsigned long pending = __ffs(pih_isr);294 unsigned int irq;295 296 pih_isr &= ~BIT(pending);297 irq = pending + twl4030_irq_base;298 handle_nested_irq(irq);299 }300 301 return IRQ_HANDLED;302}303 304/*----------------------------------------------------------------------*/305 306/*307 * twl4030_init_sih_modules() ... start from a known state where no308 * IRQs will be coming in, and where we can quickly enable them then309 * handle them as they arrive. Mask all IRQs: maybe init SIH_CTRL.310 *311 * NOTE: we don't touch EDR registers here; they stay with hardware312 * defaults or whatever the last value was. Note that when both EDR313 * bits for an IRQ are clear, that's as if its IMR bit is set...314 */315static int twl4030_init_sih_modules(unsigned line)316{317 const struct sih *sih;318 u8 buf[4];319 int i;320 int status;321 322 /* line 0 == int1_n signal; line 1 == int2_n signal */323 if (line > 1)324 return -EINVAL;325 326 irq_line = line;327 328 /* disable all interrupts on our line */329 memset(buf, 0xff, sizeof(buf));330 sih = sih_modules;331 for (i = 0; i < nr_sih_modules; i++, sih++) {332 /* skip USB -- it's funky */333 if (!sih->bytes_ixr)334 continue;335 336 /* Not all the SIH modules support multiple interrupt lines */337 if (sih->irq_lines <= line)338 continue;339 340 status = twl_i2c_write(sih->module, buf,341 sih->mask[line].imr_offset, sih->bytes_ixr);342 if (status < 0)343 pr_err("twl4030: err %d initializing %s %s\n",344 status, sih->name, "IMR");345 346 /*347 * Maybe disable "exclusive" mode; buffer second pending irq;348 * set Clear-On-Read (COR) bit.349 *350 * NOTE that sometimes COR polarity is documented as being351 * inverted: for MADC, COR=1 means "clear on write".352 * And for PWR_INT it's not documented...353 */354 if (sih->set_cor) {355 status = twl_i2c_write_u8(sih->module,356 TWL4030_SIH_CTRL_COR_MASK,357 sih->control_offset);358 if (status < 0)359 pr_err("twl4030: err %d initializing %s %s\n",360 status, sih->name, "SIH_CTRL");361 }362 }363 364 sih = sih_modules;365 for (i = 0; i < nr_sih_modules; i++, sih++) {366 u8 rxbuf[4];367 int j;368 369 /* skip USB */370 if (!sih->bytes_ixr)371 continue;372 373 /* Not all the SIH modules support multiple interrupt lines */374 if (sih->irq_lines <= line)375 continue;376 377 /*378 * Clear pending interrupt status. Either the read was379 * enough, or we need to write those bits. Repeat, in380 * case an IRQ is pending (PENDDIS=0) ... that's not381 * uncommon with PWR_INT.PWRON.382 */383 for (j = 0; j < 2; j++) {384 status = twl_i2c_read(sih->module, rxbuf,385 sih->mask[line].isr_offset, sih->bytes_ixr);386 if (status < 0)387 pr_warn("twl4030: err %d initializing %s %s\n",388 status, sih->name, "ISR");389 390 if (!sih->set_cor) {391 status = twl_i2c_write(sih->module, buf,392 sih->mask[line].isr_offset,393 sih->bytes_ixr);394 if (status < 0)395 pr_warn("twl4030: write failed: %d\n",396 status);397 }398 /*399 * else COR=1 means read sufficed.400 * (for most SIH modules...)401 */402 }403 }404 405 return 0;406}407 408static inline void activate_irq(int irq)409{410 irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);411}412 413/*----------------------------------------------------------------------*/414 415struct sih_agent {416 int irq_base;417 const struct sih *sih;418 419 u32 imr;420 bool imr_change_pending;421 422 u32 edge_change;423 424 struct mutex irq_lock;425 char *irq_name;426};427 428/*----------------------------------------------------------------------*/429 430/*431 * All irq_chip methods get issued from code holding irq_desc[irq].lock,432 * which can't perform the underlying I2C operations (because they sleep).433 * So we must hand them off to a thread (workqueue) and cope with asynch434 * completion, potentially including some re-ordering, of these requests.435 */436 437static void twl4030_sih_mask(struct irq_data *data)438{439 struct sih_agent *agent = irq_data_get_irq_chip_data(data);440 441 agent->imr |= BIT(data->irq - agent->irq_base);442 agent->imr_change_pending = true;443}444 445static void twl4030_sih_unmask(struct irq_data *data)446{447 struct sih_agent *agent = irq_data_get_irq_chip_data(data);448 449 agent->imr &= ~BIT(data->irq - agent->irq_base);450 agent->imr_change_pending = true;451}452 453static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)454{455 struct sih_agent *agent = irq_data_get_irq_chip_data(data);456 457 if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))458 return -EINVAL;459 460 if (irqd_get_trigger_type(data) != trigger)461 agent->edge_change |= BIT(data->irq - agent->irq_base);462 463 return 0;464}465 466static void twl4030_sih_bus_lock(struct irq_data *data)467{468 struct sih_agent *agent = irq_data_get_irq_chip_data(data);469 470 mutex_lock(&agent->irq_lock);471}472 473static void twl4030_sih_bus_sync_unlock(struct irq_data *data)474{475 struct sih_agent *agent = irq_data_get_irq_chip_data(data);476 const struct sih *sih = agent->sih;477 int status;478 479 if (agent->imr_change_pending) {480 union {481 __le32 word;482 u8 bytes[4];483 } imr;484 485 /* byte[0] gets overwritten as we write ... */486 imr.word = cpu_to_le32(agent->imr);487 agent->imr_change_pending = false;488 489 /* write the whole mask ... simpler than subsetting it */490 status = twl_i2c_write(sih->module, imr.bytes,491 sih->mask[irq_line].imr_offset,492 sih->bytes_ixr);493 if (status)494 pr_err("twl4030: %s, %s --> %d\n", __func__,495 "write", status);496 }497 498 if (agent->edge_change) {499 u32 edge_change;500 u8 bytes[6];501 502 edge_change = agent->edge_change;503 agent->edge_change = 0;504 505 /*506 * Read, reserving first byte for write scratch. Yes, this507 * could be cached for some speedup ... but be careful about508 * any processor on the other IRQ line, EDR registers are509 * shared.510 */511 status = twl_i2c_read(sih->module, bytes,512 sih->edr_offset, sih->bytes_edr);513 if (status) {514 pr_err("twl4030: %s, %s --> %d\n", __func__,515 "read", status);516 return;517 }518 519 /* Modify only the bits we know must change */520 while (edge_change) {521 int i = fls(edge_change) - 1;522 int byte = i >> 2;523 int off = (i & 0x3) * 2;524 unsigned int type;525 526 bytes[byte] &= ~(0x03 << off);527 528 type = irq_get_trigger_type(i + agent->irq_base);529 if (type & IRQ_TYPE_EDGE_RISING)530 bytes[byte] |= BIT(off + 1);531 if (type & IRQ_TYPE_EDGE_FALLING)532 bytes[byte] |= BIT(off + 0);533 534 edge_change &= ~BIT(i);535 }536 537 /* Write */538 status = twl_i2c_write(sih->module, bytes,539 sih->edr_offset, sih->bytes_edr);540 if (status)541 pr_err("twl4030: %s, %s --> %d\n", __func__,542 "write", status);543 }544 545 mutex_unlock(&agent->irq_lock);546}547 548static struct irq_chip twl4030_sih_irq_chip = {549 .name = "twl4030",550 .irq_mask = twl4030_sih_mask,551 .irq_unmask = twl4030_sih_unmask,552 .irq_set_type = twl4030_sih_set_type,553 .irq_bus_lock = twl4030_sih_bus_lock,554 .irq_bus_sync_unlock = twl4030_sih_bus_sync_unlock,555 .flags = IRQCHIP_SKIP_SET_WAKE,556};557 558/*----------------------------------------------------------------------*/559 560static inline int sih_read_isr(const struct sih *sih)561{562 int status;563 union {564 u8 bytes[4];565 __le32 word;566 } isr;567 568 /* FIXME need retry-on-error ... */569 570 isr.word = 0;571 status = twl_i2c_read(sih->module, isr.bytes,572 sih->mask[irq_line].isr_offset, sih->bytes_ixr);573 574 return (status < 0) ? status : le32_to_cpu(isr.word);575}576 577/*578 * Generic handler for SIH interrupts ... we "know" this is called579 * in task context, with IRQs enabled.580 */581static irqreturn_t handle_twl4030_sih(int irq, void *data)582{583 struct sih_agent *agent = irq_get_handler_data(irq);584 const struct sih *sih = agent->sih;585 int isr;586 587 /* reading ISR acks the IRQs, using clear-on-read mode */588 isr = sih_read_isr(sih);589 590 if (isr < 0) {591 pr_err("twl4030: %s SIH, read ISR error %d\n",592 sih->name, isr);593 /* REVISIT: recover; eventually mask it all, etc */594 return IRQ_HANDLED;595 }596 597 while (isr) {598 irq = fls(isr);599 irq--;600 isr &= ~BIT(irq);601 602 if (irq < sih->bits)603 handle_nested_irq(agent->irq_base + irq);604 else605 pr_err("twl4030: %s SIH, invalid ISR bit %d\n",606 sih->name, irq);607 }608 return IRQ_HANDLED;609}610 611/* returns the first IRQ used by this SIH bank, or negative errno */612int twl4030_sih_setup(struct device *dev, int module, int irq_base)613{614 int sih_mod;615 const struct sih *sih = NULL;616 struct sih_agent *agent;617 int i, irq;618 int status = -EINVAL;619 620 /* only support modules with standard clear-on-read for now */621 for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;622 sih_mod++, sih++) {623 if (sih->module == module && sih->set_cor) {624 status = 0;625 break;626 }627 }628 629 if (status < 0) {630 dev_err(dev, "module to setup SIH for not found\n");631 return status;632 }633 634 agent = kzalloc(sizeof(*agent), GFP_KERNEL);635 if (!agent)636 return -ENOMEM;637 638 agent->irq_base = irq_base;639 agent->sih = sih;640 agent->imr = ~0;641 mutex_init(&agent->irq_lock);642 643 for (i = 0; i < sih->bits; i++) {644 irq = irq_base + i;645 646 irq_set_chip_data(irq, agent);647 irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip,648 handle_edge_irq);649 irq_set_nested_thread(irq, 1);650 activate_irq(irq);651 }652 653 /* replace generic PIH handler (handle_simple_irq) */654 irq = sih_mod + twl4030_irq_base;655 irq_set_handler_data(irq, agent);656 agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name);657 status = request_threaded_irq(irq, NULL, handle_twl4030_sih,658 IRQF_EARLY_RESUME | IRQF_ONESHOT,659 agent->irq_name ?: sih->name, NULL);660 661 dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,662 irq, irq_base, irq_base + i - 1);663 664 return status < 0 ? status : irq_base;665}666 667/* FIXME need a call to reverse twl4030_sih_setup() ... */668 669/*----------------------------------------------------------------------*/670 671/* FIXME pass in which interrupt line we'll use ... */672#define twl_irq_line 0673 674int twl4030_init_irq(struct device *dev, int irq_num)675{676 static struct irq_chip twl4030_irq_chip;677 int status, i;678 int irq_base, irq_end, nr_irqs;679 struct device_node *node = dev->of_node;680 681 /*682 * TWL core and pwr interrupts must be contiguous because683 * the hwirqs numbers are defined contiguously from 1 to 15.684 * Create only one domain for both.685 */686 nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;687 688 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);689 if (irq_base < 0) {690 dev_err(dev, "Fail to allocate IRQ descs\n");691 return irq_base;692 }693 694 irq_domain_add_legacy(node, nr_irqs, irq_base, 0,695 &irq_domain_simple_ops, NULL);696 697 irq_end = irq_base + TWL4030_CORE_NR_IRQS;698 699 /*700 * Mask and clear all TWL4030 interrupts since initially we do701 * not have any TWL4030 module interrupt handlers present702 */703 status = twl4030_init_sih_modules(twl_irq_line);704 if (status < 0)705 return status;706 707 twl4030_irq_base = irq_base;708 709 /*710 * Install an irq handler for each of the SIH modules;711 * clone dummy irq_chip since PIH can't *do* anything712 */713 twl4030_irq_chip = dummy_irq_chip;714 twl4030_irq_chip.name = "twl4030";715 716 twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack;717 718 for (i = irq_base; i < irq_end; i++) {719 irq_set_chip_and_handler(i, &twl4030_irq_chip,720 handle_simple_irq);721 irq_set_nested_thread(i, 1);722 activate_irq(i);723 }724 725 dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",726 irq_num, irq_base, irq_end);727 728 /* ... and the PWR_INT module ... */729 status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);730 if (status < 0) {731 dev_err(dev, "sih_setup PWR INT --> %d\n", status);732 goto fail;733 }734 735 /* install an irq handler to demultiplex the TWL4030 interrupt */736 status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih,737 IRQF_ONESHOT,738 "TWL4030-PIH", NULL);739 if (status < 0) {740 dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);741 goto fail_rqirq;742 }743 enable_irq_wake(irq_num);744 745 return irq_base;746fail_rqirq:747 /* clean up twl4030_sih_setup */748fail:749 for (i = irq_base; i < irq_end; i++) {750 irq_set_nested_thread(i, 0);751 irq_set_chip_and_handler(i, NULL, NULL);752 }753 754 return status;755}756 757void twl4030_exit_irq(void)758{759 /* FIXME undo twl_init_irq() */760 if (twl4030_irq_base)761 pr_err("twl4030: can't yet clean up IRQs?\n");762}763 764int twl4030_init_chip_irq(const char *chip)765{766 if (!strcmp(chip, "twl5031")) {767 sih_modules = sih_modules_twl5031;768 nr_sih_modules = ARRAY_SIZE(sih_modules_twl5031);769 } else {770 sih_modules = sih_modules_twl4030;771 nr_sih_modules = ARRAY_SIZE(sih_modules_twl4030);772 }773 774 return 0;775}776