1e8deb28cSBalaji T K /* 2e8deb28cSBalaji T K * twl6030-irq.c - TWL6030 irq support 3e8deb28cSBalaji T K * 4e8deb28cSBalaji T K * Copyright (C) 2005-2009 Texas Instruments, Inc. 5e8deb28cSBalaji T K * 6e8deb28cSBalaji T K * Modifications to defer interrupt handling to a kernel thread: 7e8deb28cSBalaji T K * Copyright (C) 2006 MontaVista Software, Inc. 8e8deb28cSBalaji T K * 9e8deb28cSBalaji T K * Based on tlv320aic23.c: 10e8deb28cSBalaji T K * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> 11e8deb28cSBalaji T K * 12e8deb28cSBalaji T K * Code cleanup and modifications to IRQ handler. 13e8deb28cSBalaji T K * by syed khasim <x0khasim@ti.com> 14e8deb28cSBalaji T K * 15e8deb28cSBalaji T K * TWL6030 specific code and IRQ handling changes by 16e8deb28cSBalaji T K * Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com> 17e8deb28cSBalaji T K * Balaji T K <balajitk@ti.com> 18e8deb28cSBalaji T K * 19e8deb28cSBalaji T K * This program is free software; you can redistribute it and/or modify 20e8deb28cSBalaji T K * it under the terms of the GNU General Public License as published by 21e8deb28cSBalaji T K * the Free Software Foundation; either version 2 of the License, or 22e8deb28cSBalaji T K * (at your option) any later version. 23e8deb28cSBalaji T K * 24e8deb28cSBalaji T K * This program is distributed in the hope that it will be useful, 25e8deb28cSBalaji T K * but WITHOUT ANY WARRANTY; without even the implied warranty of 26e8deb28cSBalaji T K * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27e8deb28cSBalaji T K * GNU General Public License for more details. 28e8deb28cSBalaji T K * 29e8deb28cSBalaji T K * You should have received a copy of the GNU General Public License 30e8deb28cSBalaji T K * along with this program; if not, write to the Free Software 31e8deb28cSBalaji T K * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32e8deb28cSBalaji T K */ 33e8deb28cSBalaji T K 34e8deb28cSBalaji T K #include <linux/init.h> 35e8deb28cSBalaji T K #include <linux/interrupt.h> 36e8deb28cSBalaji T K #include <linux/irq.h> 37e8deb28cSBalaji T K #include <linux/kthread.h> 38e8deb28cSBalaji T K #include <linux/i2c/twl.h> 3972f2e2c7Skishore kadiyala #include <linux/platform_device.h> 40e8deb28cSBalaji T K 41b0b4a7c2SG, Manjunath Kondaiah #include "twl-core.h" 42b0b4a7c2SG, Manjunath Kondaiah 43e8deb28cSBalaji T K /* 44e8deb28cSBalaji T K * TWL6030 (unlike its predecessors, which had two level interrupt handling) 45e8deb28cSBalaji T K * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C. 46e8deb28cSBalaji T K * It exposes status bits saying who has raised an interrupt. There are 47e8deb28cSBalaji T K * three mask registers that corresponds to these status registers, that 48e8deb28cSBalaji T K * enables/disables these interrupts. 49e8deb28cSBalaji T K * 50e8deb28cSBalaji T K * We set up IRQs starting at a platform-specified base. An interrupt map table, 51e8deb28cSBalaji T K * specifies mapping between interrupt number and the associated module. 52e8deb28cSBalaji T K * 53e8deb28cSBalaji T K */ 54e8deb28cSBalaji T K 55e8deb28cSBalaji T K static int twl6030_interrupt_mapping[24] = { 56e8deb28cSBalaji T K PWR_INTR_OFFSET, /* Bit 0 PWRON */ 57e8deb28cSBalaji T K PWR_INTR_OFFSET, /* Bit 1 RPWRON */ 58e8deb28cSBalaji T K PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */ 59e8deb28cSBalaji T K RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ 60e8deb28cSBalaji T K RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ 61e8deb28cSBalaji T K HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ 62e8deb28cSBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */ 63e8deb28cSBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 7 VMMC_SHORT */ 64e8deb28cSBalaji T K 65e8deb28cSBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 8 VUSIM_SHORT */ 66e8deb28cSBalaji T K BATDETECT_INTR_OFFSET, /* Bit 9 BAT */ 67e8deb28cSBalaji T K SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */ 68e8deb28cSBalaji T K MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */ 69e8deb28cSBalaji T K RSV_INTR_OFFSET, /* Bit 12 Reserved */ 70e8deb28cSBalaji T K MADC_INTR_OFFSET, /* Bit 13 GPADC_RT_EOC */ 71e8deb28cSBalaji T K MADC_INTR_OFFSET, /* Bit 14 GPADC_SW_EOC */ 72e8deb28cSBalaji T K GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */ 73e8deb28cSBalaji T K 74e8deb28cSBalaji T K USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ 75e8deb28cSBalaji T K USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ 76e8deb28cSBalaji T K USBOTG_INTR_OFFSET, /* Bit 18 ID */ 7777b1d3faSHema HK USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */ 78e8deb28cSBalaji T K CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ 796523b148SGraeme Gregory CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */ 806523b148SGraeme Gregory CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ 81e8deb28cSBalaji T K RSV_INTR_OFFSET, /* Bit 23 Reserved */ 82e8deb28cSBalaji T K }; 83e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 84e8deb28cSBalaji T K 85e8deb28cSBalaji T K static unsigned twl6030_irq_base; 86e8deb28cSBalaji T K 87e8deb28cSBalaji T K static struct completion irq_event; 88e8deb28cSBalaji T K 89e8deb28cSBalaji T K /* 90e8deb28cSBalaji T K * This thread processes interrupts reported by the Primary Interrupt Handler. 91e8deb28cSBalaji T K */ 92e8deb28cSBalaji T K static int twl6030_irq_thread(void *data) 93e8deb28cSBalaji T K { 94e8deb28cSBalaji T K long irq = (long)data; 95e8deb28cSBalaji T K static unsigned i2c_errors; 96e8deb28cSBalaji T K static const unsigned max_i2c_errors = 100; 97e8deb28cSBalaji T K int ret; 98e8deb28cSBalaji T K 99e8deb28cSBalaji T K current->flags |= PF_NOFREEZE; 100e8deb28cSBalaji T K 101e8deb28cSBalaji T K while (!kthread_should_stop()) { 102e8deb28cSBalaji T K int i; 103e8deb28cSBalaji T K union { 104e8deb28cSBalaji T K u8 bytes[4]; 105e8deb28cSBalaji T K u32 int_sts; 106e8deb28cSBalaji T K } sts; 107e8deb28cSBalaji T K 108e8deb28cSBalaji T K /* Wait for IRQ, then read PIH irq status (also blocking) */ 109e8deb28cSBalaji T K wait_for_completion_interruptible(&irq_event); 110e8deb28cSBalaji T K 111e8deb28cSBalaji T K /* read INT_STS_A, B and C in one shot using a burst read */ 112e8deb28cSBalaji T K ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, 113e8deb28cSBalaji T K REG_INT_STS_A, 3); 114e8deb28cSBalaji T K if (ret) { 115e8deb28cSBalaji T K pr_warning("twl6030: I2C error %d reading PIH ISR\n", 116e8deb28cSBalaji T K ret); 117e8deb28cSBalaji T K if (++i2c_errors >= max_i2c_errors) { 118e8deb28cSBalaji T K printk(KERN_ERR "Maximum I2C error count" 119e8deb28cSBalaji T K " exceeded. Terminating %s.\n", 120e8deb28cSBalaji T K __func__); 121e8deb28cSBalaji T K break; 122e8deb28cSBalaji T K } 123e8deb28cSBalaji T K complete(&irq_event); 124e8deb28cSBalaji T K continue; 125e8deb28cSBalaji T K } 126e8deb28cSBalaji T K 127e8deb28cSBalaji T K 128e8deb28cSBalaji T K 129e8deb28cSBalaji T K sts.bytes[3] = 0; /* Only 24 bits are valid*/ 130e8deb28cSBalaji T K 13177b1d3faSHema HK /* 13277b1d3faSHema HK * Since VBUS status bit is not reliable for VBUS disconnect 13377b1d3faSHema HK * use CHARGER VBUS detection status bit instead. 13477b1d3faSHema HK */ 13577b1d3faSHema HK if (sts.bytes[2] & 0x10) 13677b1d3faSHema HK sts.bytes[2] |= 0x08; 13777b1d3faSHema HK 138e8deb28cSBalaji T K for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { 139e8deb28cSBalaji T K local_irq_disable(); 140e8deb28cSBalaji T K if (sts.int_sts & 0x1) { 141e8deb28cSBalaji T K int module_irq = twl6030_irq_base + 142e8deb28cSBalaji T K twl6030_interrupt_mapping[i]; 143c22435a3SThomas Gleixner generic_handle_irq(module_irq); 144e8deb28cSBalaji T K 145e8deb28cSBalaji T K } 146e8deb28cSBalaji T K local_irq_enable(); 147e8deb28cSBalaji T K } 148e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes, 149e8deb28cSBalaji T K REG_INT_STS_A, 3); /* clear INT_STS_A */ 150e8deb28cSBalaji T K if (ret) 151e8deb28cSBalaji T K pr_warning("twl6030: I2C error in clearing PIH ISR\n"); 152e8deb28cSBalaji T K 153e8deb28cSBalaji T K enable_irq(irq); 154e8deb28cSBalaji T K } 155e8deb28cSBalaji T K 156e8deb28cSBalaji T K return 0; 157e8deb28cSBalaji T K } 158e8deb28cSBalaji T K 159e8deb28cSBalaji T K /* 160e8deb28cSBalaji T K * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. 161e8deb28cSBalaji T K * This is a chained interrupt, so there is no desc->action method for it. 162e8deb28cSBalaji T K * Now we need to query the interrupt controller in the twl6030 to determine 163e8deb28cSBalaji T K * which module is generating the interrupt request. However, we can't do i2c 164e8deb28cSBalaji T K * transactions in interrupt context, so we must defer that work to a kernel 165e8deb28cSBalaji T K * thread. All we do here is acknowledge and mask the interrupt and wakeup 166e8deb28cSBalaji T K * the kernel thread. 167e8deb28cSBalaji T K */ 168e8deb28cSBalaji T K static irqreturn_t handle_twl6030_pih(int irq, void *devid) 169e8deb28cSBalaji T K { 170e8deb28cSBalaji T K disable_irq_nosync(irq); 171e8deb28cSBalaji T K complete(devid); 172e8deb28cSBalaji T K return IRQ_HANDLED; 173e8deb28cSBalaji T K } 174e8deb28cSBalaji T K 175e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 176e8deb28cSBalaji T K 177e8deb28cSBalaji T K static inline void activate_irq(int irq) 178e8deb28cSBalaji T K { 179e8deb28cSBalaji T K #ifdef CONFIG_ARM 180e8deb28cSBalaji T K /* ARM requires an extra step to clear IRQ_NOREQUEST, which it 181e8deb28cSBalaji T K * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. 182e8deb28cSBalaji T K */ 183e8deb28cSBalaji T K set_irq_flags(irq, IRQF_VALID); 184e8deb28cSBalaji T K #else 185e8deb28cSBalaji T K /* same effect on other architectures */ 186d5bb1221SThomas Gleixner irq_set_noprobe(irq); 187e8deb28cSBalaji T K #endif 188e8deb28cSBalaji T K } 189e8deb28cSBalaji T K 190e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 191e8deb28cSBalaji T K 192e8deb28cSBalaji T K static unsigned twl6030_irq_next; 193e8deb28cSBalaji T K 194e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 195e8deb28cSBalaji T K int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) 196e8deb28cSBalaji T K { 197e8deb28cSBalaji T K int ret; 198e8deb28cSBalaji T K u8 unmask_value; 199e8deb28cSBalaji T K ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value, 200e8deb28cSBalaji T K REG_INT_STS_A + offset); 201e8deb28cSBalaji T K unmask_value &= (~(bit_mask)); 202e8deb28cSBalaji T K ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value, 203e8deb28cSBalaji T K REG_INT_STS_A + offset); /* unmask INT_MSK_A/B/C */ 204e8deb28cSBalaji T K return ret; 205e8deb28cSBalaji T K } 206e8deb28cSBalaji T K EXPORT_SYMBOL(twl6030_interrupt_unmask); 207e8deb28cSBalaji T K 208e8deb28cSBalaji T K int twl6030_interrupt_mask(u8 bit_mask, u8 offset) 209e8deb28cSBalaji T K { 210e8deb28cSBalaji T K int ret; 211e8deb28cSBalaji T K u8 mask_value; 212e8deb28cSBalaji T K ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value, 213e8deb28cSBalaji T K REG_INT_STS_A + offset); 214e8deb28cSBalaji T K mask_value |= (bit_mask); 215e8deb28cSBalaji T K ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value, 216e8deb28cSBalaji T K REG_INT_STS_A + offset); /* mask INT_MSK_A/B/C */ 217e8deb28cSBalaji T K return ret; 218e8deb28cSBalaji T K } 219e8deb28cSBalaji T K EXPORT_SYMBOL(twl6030_interrupt_mask); 220e8deb28cSBalaji T K 22172f2e2c7Skishore kadiyala int twl6030_mmc_card_detect_config(void) 22272f2e2c7Skishore kadiyala { 22372f2e2c7Skishore kadiyala int ret; 22472f2e2c7Skishore kadiyala u8 reg_val = 0; 22572f2e2c7Skishore kadiyala 22672f2e2c7Skishore kadiyala /* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */ 22772f2e2c7Skishore kadiyala twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, 22872f2e2c7Skishore kadiyala REG_INT_MSK_LINE_B); 22972f2e2c7Skishore kadiyala twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, 23072f2e2c7Skishore kadiyala REG_INT_MSK_STS_B); 23172f2e2c7Skishore kadiyala /* 23225985edcSLucas De Marchi * Initially Configuring MMC_CTRL for receiving interrupts & 23372f2e2c7Skishore kadiyala * Card status on TWL6030 for MMC1 23472f2e2c7Skishore kadiyala */ 23572f2e2c7Skishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); 23672f2e2c7Skishore kadiyala if (ret < 0) { 23772f2e2c7Skishore kadiyala pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret); 23872f2e2c7Skishore kadiyala return ret; 23972f2e2c7Skishore kadiyala } 24072f2e2c7Skishore kadiyala reg_val &= ~VMMC_AUTO_OFF; 24172f2e2c7Skishore kadiyala reg_val |= SW_FC; 24272f2e2c7Skishore kadiyala ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); 24372f2e2c7Skishore kadiyala if (ret < 0) { 24472f2e2c7Skishore kadiyala pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret); 24572f2e2c7Skishore kadiyala return ret; 24672f2e2c7Skishore kadiyala } 24772f2e2c7Skishore kadiyala 24872f2e2c7Skishore kadiyala /* Configuring PullUp-PullDown register */ 24972f2e2c7Skishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, 25072f2e2c7Skishore kadiyala TWL6030_CFG_INPUT_PUPD3); 25172f2e2c7Skishore kadiyala if (ret < 0) { 25272f2e2c7Skishore kadiyala pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n", 25372f2e2c7Skishore kadiyala ret); 25472f2e2c7Skishore kadiyala return ret; 25572f2e2c7Skishore kadiyala } 25672f2e2c7Skishore kadiyala reg_val &= ~(MMC_PU | MMC_PD); 25772f2e2c7Skishore kadiyala ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, 25872f2e2c7Skishore kadiyala TWL6030_CFG_INPUT_PUPD3); 25972f2e2c7Skishore kadiyala if (ret < 0) { 26072f2e2c7Skishore kadiyala pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n", 26172f2e2c7Skishore kadiyala ret); 26272f2e2c7Skishore kadiyala return ret; 26372f2e2c7Skishore kadiyala } 26472f2e2c7Skishore kadiyala return 0; 26572f2e2c7Skishore kadiyala } 26672f2e2c7Skishore kadiyala EXPORT_SYMBOL(twl6030_mmc_card_detect_config); 26772f2e2c7Skishore kadiyala 26872f2e2c7Skishore kadiyala int twl6030_mmc_card_detect(struct device *dev, int slot) 26972f2e2c7Skishore kadiyala { 27072f2e2c7Skishore kadiyala int ret = -EIO; 27172f2e2c7Skishore kadiyala u8 read_reg = 0; 27272f2e2c7Skishore kadiyala struct platform_device *pdev = to_platform_device(dev); 27372f2e2c7Skishore kadiyala 27472f2e2c7Skishore kadiyala if (pdev->id) { 27572f2e2c7Skishore kadiyala /* TWL6030 provide's Card detect support for 27672f2e2c7Skishore kadiyala * only MMC1 controller. 27772f2e2c7Skishore kadiyala */ 27825985edcSLucas De Marchi pr_err("Unknown MMC controller %d in %s\n", pdev->id, __func__); 27972f2e2c7Skishore kadiyala return ret; 28072f2e2c7Skishore kadiyala } 28172f2e2c7Skishore kadiyala /* 28272f2e2c7Skishore kadiyala * BIT0 of MMC_CTRL on TWL6030 provides card status for MMC1 28372f2e2c7Skishore kadiyala * 0 - Card not present ,1 - Card present 28472f2e2c7Skishore kadiyala */ 28572f2e2c7Skishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg, 28672f2e2c7Skishore kadiyala TWL6030_MMCCTRL); 28772f2e2c7Skishore kadiyala if (ret >= 0) 28872f2e2c7Skishore kadiyala ret = read_reg & STS_MMC; 28972f2e2c7Skishore kadiyala return ret; 29072f2e2c7Skishore kadiyala } 29172f2e2c7Skishore kadiyala EXPORT_SYMBOL(twl6030_mmc_card_detect); 29272f2e2c7Skishore kadiyala 293e8deb28cSBalaji T K int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) 294e8deb28cSBalaji T K { 295e8deb28cSBalaji T K 296e8deb28cSBalaji T K int status = 0; 297e8deb28cSBalaji T K int i; 298e8deb28cSBalaji T K struct task_struct *task; 299e8deb28cSBalaji T K int ret; 300e8deb28cSBalaji T K u8 mask[4]; 301e8deb28cSBalaji T K 302e8deb28cSBalaji T K static struct irq_chip twl6030_irq_chip; 303e8deb28cSBalaji T K mask[1] = 0xFF; 304e8deb28cSBalaji T K mask[2] = 0xFF; 305e8deb28cSBalaji T K mask[3] = 0xFF; 306e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 307e8deb28cSBalaji T K REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */ 308e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 309e8deb28cSBalaji T K REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */ 310e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 311e8deb28cSBalaji T K REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */ 312e8deb28cSBalaji T K 313e8deb28cSBalaji T K twl6030_irq_base = irq_base; 314e8deb28cSBalaji T K 315e8deb28cSBalaji T K /* install an irq handler for each of the modules; 316e8deb28cSBalaji T K * clone dummy irq_chip since PIH can't *do* anything 317e8deb28cSBalaji T K */ 318e8deb28cSBalaji T K twl6030_irq_chip = dummy_irq_chip; 319e8deb28cSBalaji T K twl6030_irq_chip.name = "twl6030"; 320c45c685cSLennert Buytenhek twl6030_irq_chip.irq_set_type = NULL; 321e8deb28cSBalaji T K 322e8deb28cSBalaji T K for (i = irq_base; i < irq_end; i++) { 323d5bb1221SThomas Gleixner irq_set_chip_and_handler(i, &twl6030_irq_chip, 324e8deb28cSBalaji T K handle_simple_irq); 325e8deb28cSBalaji T K activate_irq(i); 326e8deb28cSBalaji T K } 327e8deb28cSBalaji T K 328e8deb28cSBalaji T K twl6030_irq_next = i; 329e8deb28cSBalaji T K pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", 330e8deb28cSBalaji T K irq_num, irq_base, twl6030_irq_next - 1); 331e8deb28cSBalaji T K 332e8deb28cSBalaji T K /* install an irq handler to demultiplex the TWL6030 interrupt */ 333e8deb28cSBalaji T K init_completion(&irq_event); 334e8deb28cSBalaji T K 335e8deb28cSBalaji T K status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED, 336e8deb28cSBalaji T K "TWL6030-PIH", &irq_event); 337e8deb28cSBalaji T K if (status < 0) { 338e8deb28cSBalaji T K pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status); 339e8deb28cSBalaji T K goto fail_irq; 340e8deb28cSBalaji T K } 341862de70cSAxel Lin 342862de70cSAxel Lin task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); 343862de70cSAxel Lin if (IS_ERR(task)) { 344862de70cSAxel Lin pr_err("twl6030: could not create irq %d thread!\n", irq_num); 345862de70cSAxel Lin status = PTR_ERR(task); 346862de70cSAxel Lin goto fail_kthread; 347862de70cSAxel Lin } 348e8deb28cSBalaji T K return status; 349e8deb28cSBalaji T K 350e8deb28cSBalaji T K fail_kthread: 351862de70cSAxel Lin free_irq(irq_num, &irq_event); 352862de70cSAxel Lin 353862de70cSAxel Lin fail_irq: 354e8deb28cSBalaji T K for (i = irq_base; i < irq_end; i++) 355d5bb1221SThomas Gleixner irq_set_chip_and_handler(i, NULL, NULL); 356e8deb28cSBalaji T K return status; 357e8deb28cSBalaji T K } 358e8deb28cSBalaji T K 359e8deb28cSBalaji T K int twl6030_exit_irq(void) 360e8deb28cSBalaji T K { 361e8deb28cSBalaji T K 362e8deb28cSBalaji T K if (twl6030_irq_base) { 363e8deb28cSBalaji T K pr_err("twl6030: can't yet clean up IRQs?\n"); 364e8deb28cSBalaji T K return -ENOSYS; 365e8deb28cSBalaji T K } 366e8deb28cSBalaji T K return 0; 367e8deb28cSBalaji T K } 368e8deb28cSBalaji T K 369