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 41e8deb28cSBalaji T K /* 42e8deb28cSBalaji T K * TWL6030 (unlike its predecessors, which had two level interrupt handling) 43e8deb28cSBalaji T K * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C. 44e8deb28cSBalaji T K * It exposes status bits saying who has raised an interrupt. There are 45e8deb28cSBalaji T K * three mask registers that corresponds to these status registers, that 46e8deb28cSBalaji T K * enables/disables these interrupts. 47e8deb28cSBalaji T K * 48e8deb28cSBalaji T K * We set up IRQs starting at a platform-specified base. An interrupt map table, 49e8deb28cSBalaji T K * specifies mapping between interrupt number and the associated module. 50e8deb28cSBalaji T K * 51e8deb28cSBalaji T K */ 52e8deb28cSBalaji T K 53e8deb28cSBalaji T K static int twl6030_interrupt_mapping[24] = { 54e8deb28cSBalaji T K PWR_INTR_OFFSET, /* Bit 0 PWRON */ 55e8deb28cSBalaji T K PWR_INTR_OFFSET, /* Bit 1 RPWRON */ 56e8deb28cSBalaji T K PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */ 57e8deb28cSBalaji T K RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ 58e8deb28cSBalaji T K RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ 59e8deb28cSBalaji T K HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ 60e8deb28cSBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */ 61e8deb28cSBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 7 VMMC_SHORT */ 62e8deb28cSBalaji T K 63e8deb28cSBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 8 VUSIM_SHORT */ 64e8deb28cSBalaji T K BATDETECT_INTR_OFFSET, /* Bit 9 BAT */ 65e8deb28cSBalaji T K SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */ 66e8deb28cSBalaji T K MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */ 67e8deb28cSBalaji T K RSV_INTR_OFFSET, /* Bit 12 Reserved */ 68e8deb28cSBalaji T K MADC_INTR_OFFSET, /* Bit 13 GPADC_RT_EOC */ 69e8deb28cSBalaji T K MADC_INTR_OFFSET, /* Bit 14 GPADC_SW_EOC */ 70e8deb28cSBalaji T K GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */ 71e8deb28cSBalaji T K 72e8deb28cSBalaji T K USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ 73e8deb28cSBalaji T K USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ 74e8deb28cSBalaji T K USBOTG_INTR_OFFSET, /* Bit 18 ID */ 75e8deb28cSBalaji T K USBOTG_INTR_OFFSET, /* Bit 19 VBUS */ 76e8deb28cSBalaji T K CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ 77e8deb28cSBalaji T K CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */ 78e8deb28cSBalaji T K CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */ 79e8deb28cSBalaji T K RSV_INTR_OFFSET, /* Bit 23 Reserved */ 80e8deb28cSBalaji T K }; 81e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 82e8deb28cSBalaji T K 83e8deb28cSBalaji T K static unsigned twl6030_irq_base; 84e8deb28cSBalaji T K 85e8deb28cSBalaji T K static struct completion irq_event; 86e8deb28cSBalaji T K 87e8deb28cSBalaji T K /* 88e8deb28cSBalaji T K * This thread processes interrupts reported by the Primary Interrupt Handler. 89e8deb28cSBalaji T K */ 90e8deb28cSBalaji T K static int twl6030_irq_thread(void *data) 91e8deb28cSBalaji T K { 92e8deb28cSBalaji T K long irq = (long)data; 93e8deb28cSBalaji T K static unsigned i2c_errors; 94e8deb28cSBalaji T K static const unsigned max_i2c_errors = 100; 95e8deb28cSBalaji T K int ret; 96e8deb28cSBalaji T K 97e8deb28cSBalaji T K current->flags |= PF_NOFREEZE; 98e8deb28cSBalaji T K 99e8deb28cSBalaji T K while (!kthread_should_stop()) { 100e8deb28cSBalaji T K int i; 101e8deb28cSBalaji T K union { 102e8deb28cSBalaji T K u8 bytes[4]; 103e8deb28cSBalaji T K u32 int_sts; 104e8deb28cSBalaji T K } sts; 105e8deb28cSBalaji T K 106e8deb28cSBalaji T K /* Wait for IRQ, then read PIH irq status (also blocking) */ 107e8deb28cSBalaji T K wait_for_completion_interruptible(&irq_event); 108e8deb28cSBalaji T K 109e8deb28cSBalaji T K /* read INT_STS_A, B and C in one shot using a burst read */ 110e8deb28cSBalaji T K ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, 111e8deb28cSBalaji T K REG_INT_STS_A, 3); 112e8deb28cSBalaji T K if (ret) { 113e8deb28cSBalaji T K pr_warning("twl6030: I2C error %d reading PIH ISR\n", 114e8deb28cSBalaji T K ret); 115e8deb28cSBalaji T K if (++i2c_errors >= max_i2c_errors) { 116e8deb28cSBalaji T K printk(KERN_ERR "Maximum I2C error count" 117e8deb28cSBalaji T K " exceeded. Terminating %s.\n", 118e8deb28cSBalaji T K __func__); 119e8deb28cSBalaji T K break; 120e8deb28cSBalaji T K } 121e8deb28cSBalaji T K complete(&irq_event); 122e8deb28cSBalaji T K continue; 123e8deb28cSBalaji T K } 124e8deb28cSBalaji T K 125e8deb28cSBalaji T K 126e8deb28cSBalaji T K 127e8deb28cSBalaji T K sts.bytes[3] = 0; /* Only 24 bits are valid*/ 128e8deb28cSBalaji T K 129e8deb28cSBalaji T K for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { 130e8deb28cSBalaji T K local_irq_disable(); 131e8deb28cSBalaji T K if (sts.int_sts & 0x1) { 132e8deb28cSBalaji T K int module_irq = twl6030_irq_base + 133e8deb28cSBalaji T K twl6030_interrupt_mapping[i]; 134e8deb28cSBalaji T K struct irq_desc *d = irq_to_desc(module_irq); 135e8deb28cSBalaji T K 136e8deb28cSBalaji T K if (!d) { 137e8deb28cSBalaji T K pr_err("twl6030: Invalid SIH IRQ: %d\n", 138e8deb28cSBalaji T K module_irq); 139e8deb28cSBalaji T K return -EINVAL; 140e8deb28cSBalaji T K } 141e8deb28cSBalaji T K 142e8deb28cSBalaji T K /* These can't be masked ... always warn 143e8deb28cSBalaji T K * if we get any surprises. 144e8deb28cSBalaji T K */ 145e8deb28cSBalaji T K if (d->status & IRQ_DISABLED) 146e8deb28cSBalaji T K note_interrupt(module_irq, d, 147e8deb28cSBalaji T K IRQ_NONE); 148e8deb28cSBalaji T K else 149e8deb28cSBalaji T K d->handle_irq(module_irq, d); 150e8deb28cSBalaji T K 151e8deb28cSBalaji T K } 152e8deb28cSBalaji T K local_irq_enable(); 153e8deb28cSBalaji T K } 154e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes, 155e8deb28cSBalaji T K REG_INT_STS_A, 3); /* clear INT_STS_A */ 156e8deb28cSBalaji T K if (ret) 157e8deb28cSBalaji T K pr_warning("twl6030: I2C error in clearing PIH ISR\n"); 158e8deb28cSBalaji T K 159e8deb28cSBalaji T K enable_irq(irq); 160e8deb28cSBalaji T K } 161e8deb28cSBalaji T K 162e8deb28cSBalaji T K return 0; 163e8deb28cSBalaji T K } 164e8deb28cSBalaji T K 165e8deb28cSBalaji T K /* 166e8deb28cSBalaji T K * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. 167e8deb28cSBalaji T K * This is a chained interrupt, so there is no desc->action method for it. 168e8deb28cSBalaji T K * Now we need to query the interrupt controller in the twl6030 to determine 169e8deb28cSBalaji T K * which module is generating the interrupt request. However, we can't do i2c 170e8deb28cSBalaji T K * transactions in interrupt context, so we must defer that work to a kernel 171e8deb28cSBalaji T K * thread. All we do here is acknowledge and mask the interrupt and wakeup 172e8deb28cSBalaji T K * the kernel thread. 173e8deb28cSBalaji T K */ 174e8deb28cSBalaji T K static irqreturn_t handle_twl6030_pih(int irq, void *devid) 175e8deb28cSBalaji T K { 176e8deb28cSBalaji T K disable_irq_nosync(irq); 177e8deb28cSBalaji T K complete(devid); 178e8deb28cSBalaji T K return IRQ_HANDLED; 179e8deb28cSBalaji T K } 180e8deb28cSBalaji T K 181e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 182e8deb28cSBalaji T K 183e8deb28cSBalaji T K static inline void activate_irq(int irq) 184e8deb28cSBalaji T K { 185e8deb28cSBalaji T K #ifdef CONFIG_ARM 186e8deb28cSBalaji T K /* ARM requires an extra step to clear IRQ_NOREQUEST, which it 187e8deb28cSBalaji T K * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. 188e8deb28cSBalaji T K */ 189e8deb28cSBalaji T K set_irq_flags(irq, IRQF_VALID); 190e8deb28cSBalaji T K #else 191e8deb28cSBalaji T K /* same effect on other architectures */ 192e8deb28cSBalaji T K set_irq_noprobe(irq); 193e8deb28cSBalaji T K #endif 194e8deb28cSBalaji T K } 195e8deb28cSBalaji T K 196e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 197e8deb28cSBalaji T K 198e8deb28cSBalaji T K static unsigned twl6030_irq_next; 199e8deb28cSBalaji T K 200e8deb28cSBalaji T K /*----------------------------------------------------------------------*/ 201e8deb28cSBalaji T K int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) 202e8deb28cSBalaji T K { 203e8deb28cSBalaji T K int ret; 204e8deb28cSBalaji T K u8 unmask_value; 205e8deb28cSBalaji T K ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value, 206e8deb28cSBalaji T K REG_INT_STS_A + offset); 207e8deb28cSBalaji T K unmask_value &= (~(bit_mask)); 208e8deb28cSBalaji T K ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value, 209e8deb28cSBalaji T K REG_INT_STS_A + offset); /* unmask INT_MSK_A/B/C */ 210e8deb28cSBalaji T K return ret; 211e8deb28cSBalaji T K } 212e8deb28cSBalaji T K EXPORT_SYMBOL(twl6030_interrupt_unmask); 213e8deb28cSBalaji T K 214e8deb28cSBalaji T K int twl6030_interrupt_mask(u8 bit_mask, u8 offset) 215e8deb28cSBalaji T K { 216e8deb28cSBalaji T K int ret; 217e8deb28cSBalaji T K u8 mask_value; 218e8deb28cSBalaji T K ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value, 219e8deb28cSBalaji T K REG_INT_STS_A + offset); 220e8deb28cSBalaji T K mask_value |= (bit_mask); 221e8deb28cSBalaji T K ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value, 222e8deb28cSBalaji T K REG_INT_STS_A + offset); /* mask INT_MSK_A/B/C */ 223e8deb28cSBalaji T K return ret; 224e8deb28cSBalaji T K } 225e8deb28cSBalaji T K EXPORT_SYMBOL(twl6030_interrupt_mask); 226e8deb28cSBalaji T K 22772f2e2c7Skishore kadiyala int twl6030_mmc_card_detect_config(void) 22872f2e2c7Skishore kadiyala { 22972f2e2c7Skishore kadiyala int ret; 23072f2e2c7Skishore kadiyala u8 reg_val = 0; 23172f2e2c7Skishore kadiyala 23272f2e2c7Skishore kadiyala /* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */ 23372f2e2c7Skishore kadiyala twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, 23472f2e2c7Skishore kadiyala REG_INT_MSK_LINE_B); 23572f2e2c7Skishore kadiyala twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, 23672f2e2c7Skishore kadiyala REG_INT_MSK_STS_B); 23772f2e2c7Skishore kadiyala /* 23872f2e2c7Skishore kadiyala * Intially Configuring MMC_CTRL for receving interrupts & 23972f2e2c7Skishore kadiyala * Card status on TWL6030 for MMC1 24072f2e2c7Skishore kadiyala */ 24172f2e2c7Skishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); 24272f2e2c7Skishore kadiyala if (ret < 0) { 24372f2e2c7Skishore kadiyala pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret); 24472f2e2c7Skishore kadiyala return ret; 24572f2e2c7Skishore kadiyala } 24672f2e2c7Skishore kadiyala reg_val &= ~VMMC_AUTO_OFF; 24772f2e2c7Skishore kadiyala reg_val |= SW_FC; 24872f2e2c7Skishore kadiyala ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); 24972f2e2c7Skishore kadiyala if (ret < 0) { 25072f2e2c7Skishore kadiyala pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret); 25172f2e2c7Skishore kadiyala return ret; 25272f2e2c7Skishore kadiyala } 25372f2e2c7Skishore kadiyala 25472f2e2c7Skishore kadiyala /* Configuring PullUp-PullDown register */ 25572f2e2c7Skishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, 25672f2e2c7Skishore kadiyala TWL6030_CFG_INPUT_PUPD3); 25772f2e2c7Skishore kadiyala if (ret < 0) { 25872f2e2c7Skishore kadiyala pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n", 25972f2e2c7Skishore kadiyala ret); 26072f2e2c7Skishore kadiyala return ret; 26172f2e2c7Skishore kadiyala } 26272f2e2c7Skishore kadiyala reg_val &= ~(MMC_PU | MMC_PD); 26372f2e2c7Skishore kadiyala ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, 26472f2e2c7Skishore kadiyala TWL6030_CFG_INPUT_PUPD3); 26572f2e2c7Skishore kadiyala if (ret < 0) { 26672f2e2c7Skishore kadiyala pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n", 26772f2e2c7Skishore kadiyala ret); 26872f2e2c7Skishore kadiyala return ret; 26972f2e2c7Skishore kadiyala } 27072f2e2c7Skishore kadiyala return 0; 27172f2e2c7Skishore kadiyala } 27272f2e2c7Skishore kadiyala EXPORT_SYMBOL(twl6030_mmc_card_detect_config); 27372f2e2c7Skishore kadiyala 27472f2e2c7Skishore kadiyala int twl6030_mmc_card_detect(struct device *dev, int slot) 27572f2e2c7Skishore kadiyala { 27672f2e2c7Skishore kadiyala int ret = -EIO; 27772f2e2c7Skishore kadiyala u8 read_reg = 0; 27872f2e2c7Skishore kadiyala struct platform_device *pdev = to_platform_device(dev); 27972f2e2c7Skishore kadiyala 28072f2e2c7Skishore kadiyala if (pdev->id) { 28172f2e2c7Skishore kadiyala /* TWL6030 provide's Card detect support for 28272f2e2c7Skishore kadiyala * only MMC1 controller. 28372f2e2c7Skishore kadiyala */ 28472f2e2c7Skishore kadiyala pr_err("Unkown MMC controller %d in %s\n", pdev->id, __func__); 28572f2e2c7Skishore kadiyala return ret; 28672f2e2c7Skishore kadiyala } 28772f2e2c7Skishore kadiyala /* 28872f2e2c7Skishore kadiyala * BIT0 of MMC_CTRL on TWL6030 provides card status for MMC1 28972f2e2c7Skishore kadiyala * 0 - Card not present ,1 - Card present 29072f2e2c7Skishore kadiyala */ 29172f2e2c7Skishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg, 29272f2e2c7Skishore kadiyala TWL6030_MMCCTRL); 29372f2e2c7Skishore kadiyala if (ret >= 0) 29472f2e2c7Skishore kadiyala ret = read_reg & STS_MMC; 29572f2e2c7Skishore kadiyala return ret; 29672f2e2c7Skishore kadiyala } 29772f2e2c7Skishore kadiyala EXPORT_SYMBOL(twl6030_mmc_card_detect); 29872f2e2c7Skishore kadiyala 299e8deb28cSBalaji T K int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) 300e8deb28cSBalaji T K { 301e8deb28cSBalaji T K 302e8deb28cSBalaji T K int status = 0; 303e8deb28cSBalaji T K int i; 304e8deb28cSBalaji T K struct task_struct *task; 305e8deb28cSBalaji T K int ret; 306e8deb28cSBalaji T K u8 mask[4]; 307e8deb28cSBalaji T K 308e8deb28cSBalaji T K static struct irq_chip twl6030_irq_chip; 309e8deb28cSBalaji T K mask[1] = 0xFF; 310e8deb28cSBalaji T K mask[2] = 0xFF; 311e8deb28cSBalaji T K mask[3] = 0xFF; 312e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 313e8deb28cSBalaji T K REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */ 314e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 315e8deb28cSBalaji T K REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */ 316e8deb28cSBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 317e8deb28cSBalaji T K REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */ 318e8deb28cSBalaji T K 319e8deb28cSBalaji T K twl6030_irq_base = irq_base; 320e8deb28cSBalaji T K 321e8deb28cSBalaji T K /* install an irq handler for each of the modules; 322e8deb28cSBalaji T K * clone dummy irq_chip since PIH can't *do* anything 323e8deb28cSBalaji T K */ 324e8deb28cSBalaji T K twl6030_irq_chip = dummy_irq_chip; 325e8deb28cSBalaji T K twl6030_irq_chip.name = "twl6030"; 326e8deb28cSBalaji T K twl6030_irq_chip.set_type = NULL; 327e8deb28cSBalaji T K 328e8deb28cSBalaji T K for (i = irq_base; i < irq_end; i++) { 329e8deb28cSBalaji T K set_irq_chip_and_handler(i, &twl6030_irq_chip, 330e8deb28cSBalaji T K handle_simple_irq); 331e8deb28cSBalaji T K activate_irq(i); 332e8deb28cSBalaji T K } 333e8deb28cSBalaji T K 334e8deb28cSBalaji T K twl6030_irq_next = i; 335e8deb28cSBalaji T K pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", 336e8deb28cSBalaji T K irq_num, irq_base, twl6030_irq_next - 1); 337e8deb28cSBalaji T K 338e8deb28cSBalaji T K /* install an irq handler to demultiplex the TWL6030 interrupt */ 339e8deb28cSBalaji T K init_completion(&irq_event); 340e8deb28cSBalaji T K task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); 341e8deb28cSBalaji T K if (IS_ERR(task)) { 342e8deb28cSBalaji T K pr_err("twl6030: could not create irq %d thread!\n", irq_num); 343e8deb28cSBalaji T K status = PTR_ERR(task); 344e8deb28cSBalaji T K goto fail_kthread; 345e8deb28cSBalaji T K } 346e8deb28cSBalaji T K 347e8deb28cSBalaji T K status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED, 348e8deb28cSBalaji T K "TWL6030-PIH", &irq_event); 349e8deb28cSBalaji T K if (status < 0) { 350e8deb28cSBalaji T K pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status); 351e8deb28cSBalaji T K goto fail_irq; 352e8deb28cSBalaji T K } 353e8deb28cSBalaji T K return status; 354e8deb28cSBalaji T K fail_irq: 355e8deb28cSBalaji T K free_irq(irq_num, &irq_event); 356e8deb28cSBalaji T K 357e8deb28cSBalaji T K fail_kthread: 358e8deb28cSBalaji T K for (i = irq_base; i < irq_end; i++) 359e8deb28cSBalaji T K set_irq_chip_and_handler(i, NULL, NULL); 360e8deb28cSBalaji T K return status; 361e8deb28cSBalaji T K } 362e8deb28cSBalaji T K 363e8deb28cSBalaji T K int twl6030_exit_irq(void) 364e8deb28cSBalaji T K { 365e8deb28cSBalaji T K 366e8deb28cSBalaji T K if (twl6030_irq_base) { 367e8deb28cSBalaji T K pr_err("twl6030: can't yet clean up IRQs?\n"); 368e8deb28cSBalaji T K return -ENOSYS; 369e8deb28cSBalaji T K } 370e8deb28cSBalaji T K return 0; 371e8deb28cSBalaji T K } 372e8deb28cSBalaji T K 373