diff options
author | Naga Venkata Srikanth V <vnv.srikanth@samsung.com> | 2012-10-26 17:18:24 +0300 |
---|---|---|
committer | Ziyann <jaraidaniel@gmail.com> | 2014-11-20 16:46:46 +0100 |
commit | b353a379266ffb18cea07e9aabc89d57bac89952 (patch) | |
tree | a941245c322930a7448d2cf036bc2e6206f4e7d5 /drivers/mfd | |
parent | 1262361537e11b1b7d4a9cb155901bab03edb1a4 (diff) | |
download | kernel_samsung_tuna-b353a379266ffb18cea07e9aabc89d57bac89952.tar.gz kernel_samsung_tuna-b353a379266ffb18cea07e9aabc89d57bac89952.tar.bz2 kernel_samsung_tuna-b353a379266ffb18cea07e9aabc89d57bac89952.zip |
TWL603X: IRQ: Migration to IRQ threaded handler
1)Removed request_irq() and replaced it with request_threaded_irq().
2)Removed generic_handle_irq() and replaced it with handle_nested_irq().
Handling these interrupts is nested, as we are handling an interrupt
(for e.g rtc,mmc1) when we are still servicing TWL irq.
Change-Id: I2eb46653a676ce8481fb934e02e8cc7e3e87df02
Signed-off-by: Naga Venkata Srikanth V <vnv.srikanth@samsung.com>
Signed-off-by: Oleg_Kosheliev <oleg.kosheliev@ti.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/twl6030-irq.c | 155 |
1 files changed, 57 insertions, 98 deletions
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 2e5f3dcd587..a7739f5202c 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -119,8 +119,6 @@ static unsigned twl6030_irq_base, twl6030_irq_end; static int twl_irq; static bool twl_irq_wake_enabled; -static struct task_struct *task; -static struct completion irq_event; static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); static u8 vbatmin_hi_threshold; @@ -163,28 +161,22 @@ static struct notifier_block twl6030_irq_pm_notifier_block = { }; /* - * This thread processes interrupts reported by the Primary Interrupt Handler. + * Threaded irq handler for the twl6030 interrupt. + * We query the interrupt controller in the twl6030 to determine + * which module is generating the interrupt request and call + * handle_nested_irq for that module. */ -static int twl6030_irq_thread(void *data) +static irqreturn_t twl6030_irq_thread(int irq, void *devid) { - long irq = (long)data; - static unsigned i2c_errors; - static const unsigned max_i2c_errors = 100; - int ret; - - current->flags |= PF_NOFREEZE; - - while (!kthread_should_stop()) { - int i; - union { + unsigned i2c_errors = 0; + const unsigned max_i2c_errors = 100; + int i, ret; + union { u8 bytes[4]; u32 int_sts; - } sts; - u32 int_sts; /* sts.int_sts converted to CPU endianness */ - - /* Wait for IRQ, then read PIH irq status (also blocking) */ - wait_for_completion_interruptible(&irq_event); - + } sts; + u32 int_sts; /* sts.int_sts converted to CPU endianness */ + while (1) { /* read INT_STS_A, B and C in one shot using a burst read */ ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3); @@ -192,70 +184,47 @@ static int twl6030_irq_thread(void *data) pr_warning("twl6030: I2C error %d reading PIH ISR\n", ret); if (++i2c_errors >= max_i2c_errors) { - printk(KERN_ERR "Maximum I2C error count" + pr_err("Maximum I2C error count" " exceeded. Terminating %s.\n", __func__); - break; + return IRQ_NONE; } - complete(&irq_event); continue; - } - - - - sts.bytes[3] = 0; /* Only 24 bits are valid*/ - - /* - * Since VBUS status bit is not reliable for VBUS disconnect - * use CHARGER VBUS detection status bit instead. - */ - if (sts.bytes[2] & 0x10) - sts.bytes[2] |= 0x08; + } else + break; + } - int_sts = le32_to_cpu(sts.int_sts); - for (i = 0; int_sts; int_sts >>= 1, i++) { - local_irq_disable(); - if (int_sts & 0x1) { - int module_irq = twl6030_irq_base + - twl6030_interrupt_mapping[i]; - generic_handle_irq(module_irq); + sts.bytes[3] = 0; /* Only 24 bits are valid*/ - } - local_irq_enable(); + /* + * Since VBUS status bit is not reliable for VBUS disconnect + * use CHARGER VBUS detection status bit instead. + */ + if (sts.bytes[2] & 0x10) + sts.bytes[2] |= 0x08; + + int_sts = le32_to_cpu(sts.int_sts); + for (i = 0; int_sts; int_sts >>= 1, i++) { + if (int_sts & 0x1) { + int module_irq = twl6030_irq_base + + twl6030_interrupt_mapping[i]; + handle_nested_irq(module_irq); } - - /* - * NOTE: - * Simulation confirms that documentation is wrong w.r.t the - * interrupt status clear operation. A single *byte* write to - * any one of STS_A to STS_C register results in all three - * STS registers being reset. Since it does not matter which - * value is written, all three registers are cleared on a - * single byte write, so we just use 0x0 to clear. - */ - ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A); - if (ret) - pr_warning("twl6030: I2C error in clearing PIH ISR\n"); - - enable_irq(irq); } - return 0; -} + /* + * NOTE: + * Simulation confirms that documentation is wrong w.r.t the + * interrupt status clear operation. A single *byte* write to + * any one of STS_A to STS_C register results in all three + * STS registers being reset. Since it does not matter which + * value is written, all three registers are cleared on a + * single byte write, so we just use 0x0 to clear. + */ + ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A); + if (ret) + pr_warning("twl6030: I2C error in clearing PIH ISR\n"); -/* - * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. - * This is a chained interrupt, so there is no desc->action method for it. - * Now we need to query the interrupt controller in the twl6030 to determine - * which module is generating the interrupt request. However, we can't do i2c - * transactions in interrupt context, so we must defer that work to a kernel - * thread. All we do here is acknowledge and mask the interrupt and wakeup - * the kernel thread. - */ -static irqreturn_t handle_twl6030_pih(int irq, void *devid) -{ - disable_irq_nosync(irq); - complete(devid); return IRQ_HANDLED; } @@ -486,9 +455,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end, unsigned long features) { - int status = 0; + int status; int i; - int ret; u8 mask[4]; static struct irq_chip twl6030_irq_chip; @@ -499,12 +467,17 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end, mask[1] = 0xFF; mask[2] = 0xFF; mask[3] = 0xFF; - ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], + status = twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */ - ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], + status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */ - ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], + status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */ + if (status < 0) { + pr_err("twl6030: I2C err writing TWL_MODULE_PIH: %d\n", + status); + return status; + } twl6030_irq_base = irq_base; twl6030_irq_end = irq_end; @@ -521,6 +494,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end, irq_set_chip_and_handler(i, &twl6030_irq_chip, handle_simple_irq); irq_set_chip_data(i, (void *)irq_num); + irq_set_nested_thread(i, 1); activate_irq(i); } @@ -528,17 +502,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end, pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", irq_num, irq_base, twl6030_irq_next - 1); - /* install an irq handler to demultiplex the TWL6030 interrupt */ - init_completion(&irq_event); - task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); - if (IS_ERR(task)) { - pr_err("twl6030: could not create irq %d thread!\n", irq_num); - status = PTR_ERR(task); - goto fail_kthread; - } - - status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED, - "TWL6030-PIH", &irq_event); + status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread, + IRQF_ONESHOT, "TWL6030-PIH", NULL); if (status < 0) { pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status); goto fail_irq; @@ -554,12 +519,9 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end, return status; fail_vlow: - free_irq(irq_num, &irq_event); + free_irq(irq_num, NULL); fail_irq: - kthread_stop(task); - -fail_kthread: for (i = irq_base; i < irq_end; i++) irq_set_chip_and_handler(i, NULL, NULL); return status; @@ -570,9 +532,6 @@ int twl6030_exit_irq(void) int i; unregister_pm_notifier(&twl6030_irq_pm_notifier_block); - if (task) - kthread_stop(task); - if (!twl6030_irq_base || !twl6030_irq_end) { pr_err("twl6030: can't yet clean up IRQs?\n"); return -ENOSYS; @@ -581,7 +540,7 @@ int twl6030_exit_irq(void) free_irq(twl6030_irq_base + TWL_VLOW_INTR_OFFSET, handle_twl6030_vlow); - free_irq(twl_irq, &irq_event); + free_irq(twl_irq, NULL); for (i = twl6030_irq_base; i < twl6030_irq_end; i++) irq_set_chip_and_handler(i, NULL, NULL); |