[RFC/PATCH 1/2] mfd: twl6030-irq: move to threaded_irq

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



... and while at that, also start using
handle_nested_irq() as we should.

Signed-off-by: Felipe Balbi <balbi@xxxxxx>
---
 drivers/mfd/twl6030-irq.c |  141 ++++++++++++++++-----------------------------
 1 files changed, 49 insertions(+), 92 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index aaedb11..1530411 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -84,99 +84,64 @@ static int twl6030_interrupt_mapping[24] = {
 
 static unsigned twl6030_irq_base;
 
-static struct completion irq_event;
-
 /*
  * This thread processes interrupts reported by the Primary Interrupt Handler.
  */
-static int twl6030_irq_thread(void *data)
+static irqreturn_t twl6030_irq_thread(int irq, void *unused)
 {
-	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 {
+	int i;
+	union {
 		u8 bytes[4];
 		u32 int_sts;
-		} sts;
-
-		/* Wait for IRQ, then read PIH irq status (also blocking) */
-		wait_for_completion_interruptible(&irq_event);
-
-		/* 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);
-		if (ret) {
-			pr_warning("twl6030: I2C error %d reading PIH ISR\n",
-					ret);
-			if (++i2c_errors >= max_i2c_errors) {
-				printk(KERN_ERR "Maximum I2C error count"
-						" exceeded.  Terminating %s.\n",
-						__func__);
-				break;
-			}
-			complete(&irq_event);
-			continue;
-		}
-
+	} sts;
 
+	disable_irq_nosync(irq);
 
-		sts.bytes[3] = 0; /* Only 24 bits are valid*/
+	/* 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);
+	if (ret) {
+		pr_warning("twl6030: I2C error %d reading PIH ISR\n",
+				ret);
+		return IRQ_NONE;
+	}
 
-		for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
-			local_irq_disable();
-			if (sts.int_sts & 0x1) {
-				int module_irq = twl6030_irq_base +
-					twl6030_interrupt_mapping[i];
-				struct irq_desc *d = irq_to_desc(module_irq);
 
-				if (!d) {
-					pr_err("twl6030: Invalid SIH IRQ: %d\n",
-					       module_irq);
-					return -EINVAL;
-				}
+	sts.bytes[3] = 0; /* Only 24 bits are valid*/
 
-				/* These can't be masked ... always warn
-				 * if we get any surprises.
-				 */
-				if (d->status & IRQ_DISABLED)
-					note_interrupt(module_irq, d,
-							IRQ_NONE);
-				else
-					d->handle_irq(module_irq, d);
+	for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
+		local_irq_disable();
+		if (sts.int_sts & 0x1) {
+			int module_irq = twl6030_irq_base +
+				twl6030_interrupt_mapping[i];
+			struct irq_desc *d = irq_to_desc(module_irq);
 
+			if (!d) {
+				pr_err("twl6030: Invalid SIH IRQ: %d\n",
+						module_irq);
+				return IRQ_NONE;
 			}
-		local_irq_enable();
-		}
-		ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
-				REG_INT_STS_A, 3); /* clear INT_STS_A */
-		if (ret)
-			pr_warning("twl6030: I2C error in clearing PIH ISR\n");
 
-		enable_irq(irq);
+			/* These can't be masked ... always warn
+			 * if we get any surprises.
+			 */
+			if (d->status & IRQ_DISABLED)
+				note_interrupt(module_irq, d,
+						IRQ_NONE);
+			else
+				handle_nested_irq(module_irq);
+
+		}
+		local_irq_enable();
 	}
+	ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
+			REG_INT_STS_A, 3); /* clear INT_STS_A */
+	if (ret)
+		pr_warning("twl6030: I2C error in clearing PIH ISR\n");
 
-	return 0;
-}
+	enable_irq(irq);
 
-/*
- * 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;
 }
 
@@ -303,7 +268,6 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 
 	int	status = 0;
 	int	i;
-	struct task_struct	*task;
 	int ret;
 	u8 mask[4];
 
@@ -337,28 +301,21 @@ 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_DISABLED, "TWL6030-PIH", NULL);
 	if (status < 0) {
 		pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
-		goto fail_irq;
+		goto fail;
 	}
-	return status;
-fail_irq:
-	free_irq(irq_num, &irq_event);
 
-fail_kthread:
+	return 0;
+
+fail:
+	free_irq(irq_num, NULL);
+
 	for (i = irq_base; i < irq_end; i++)
 		set_irq_chip_and_handler(i, NULL, NULL);
+
 	return status;
 }
 
-- 
1.7.3.4.598.g85356

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux