All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support
@ 2013-07-25 13:15 ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol, linux-kernel

This patch series intorduces twl6030-irq module rework to use Threaded IRQ and
linear irq_domain, and adds support for PMIC TWL6032 IRQs.

After this patch series TWL6030/6032 IRQs will be supported only for DT boot mode.

Changes since v1:
- Added new patch "mfd: twl6030-irq: create struct twl6030_irq" 
  which introduces "struct twl6030_irq" to store all local variables inside it.
- Patch "mfd: twl6030-irq: migrate to IRQ threaded handler":
  Minor comments applied; fixed twl6030_exit_irq();
  The Parent IRQ has been set for each nested IRQ.
- Patch "mfd: twl6030-irq: convert to use linear irq_domain":
  The irq_find_mapping() is used in twl6030_mmc_card_detect_config()
  to get virtual IRQ number.

Based on v3.11-rc1

Tested generation of RTC_ALARM(3) and PWRON(0) IRQs on OMAP4430/TWL6030 and
OMAP4470/TWL6032.

Grygorii Strashko (3):
  mfd: twl6030-irq: add error check when IRQs are masked initially
  mfd: twl6030-irq: convert to use linear irq_domain
  mfd: twl6030-irq: create struct twl6030_irq

Naga Venkata Srikanth V (1):
  mfd: twl6030-irq: migrate to IRQ threaded handler

Oleksandr Dmytryshyn (1):
  mfd: twl6030-irq: Add interrupt mapping table for the twl6032

 drivers/mfd/twl6030-irq.c |  377 +++++++++++++++++++++++++--------------------
 1 file changed, 207 insertions(+), 170 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support
@ 2013-07-25 13:15 ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol, linux-kernel

This patch series intorduces twl6030-irq module rework to use Threaded IRQ and
linear irq_domain, and adds support for PMIC TWL6032 IRQs.

After this patch series TWL6030/6032 IRQs will be supported only for DT boot mode.

Changes since v1:
- Added new patch "mfd: twl6030-irq: create struct twl6030_irq" 
  which introduces "struct twl6030_irq" to store all local variables inside it.
- Patch "mfd: twl6030-irq: migrate to IRQ threaded handler":
  Minor comments applied; fixed twl6030_exit_irq();
  The Parent IRQ has been set for each nested IRQ.
- Patch "mfd: twl6030-irq: convert to use linear irq_domain":
  The irq_find_mapping() is used in twl6030_mmc_card_detect_config()
  to get virtual IRQ number.

Based on v3.11-rc1

Tested generation of RTC_ALARM(3) and PWRON(0) IRQs on OMAP4430/TWL6030 and
OMAP4470/TWL6032.

Grygorii Strashko (3):
  mfd: twl6030-irq: add error check when IRQs are masked initially
  mfd: twl6030-irq: convert to use linear irq_domain
  mfd: twl6030-irq: create struct twl6030_irq

Naga Venkata Srikanth V (1):
  mfd: twl6030-irq: migrate to IRQ threaded handler

Oleksandr Dmytryshyn (1):
  mfd: twl6030-irq: Add interrupt mapping table for the twl6032

 drivers/mfd/twl6030-irq.c |  377 +++++++++++++++++++++++++--------------------
 1 file changed, 207 insertions(+), 170 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 1/5] mfd: twl6030-irq: migrate to IRQ threaded handler
  2013-07-25 13:15 ` Grygorii Strashko
@ 2013-07-25 13:15   ` Grygorii Strashko
  -1 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

From: Naga Venkata Srikanth V <vnv.srikanth@samsung.com>

1) Removed request_irq() and replaced it with request_threaded_irq().

2) Removed generic_handle_irq() and replaced it with
handle_nested_irq().
  Handling of these interrupts is nested, as we are handling an
interrupt (for e.g rtc, mmc1) when we are still servicing TWL irq.

3) Removed I2C read-retry logic for the case when twl_i2c_read() is
failed inside IRQ handler - there is no sense to do that, so just report
an error and return.

4) Each nested IRQ is configured with corresponding parent_irq,
which need to be retriggered in case if nested IRQ is marked
as IRQS_PENDING.

Signed-off-by: Naga Venkata Srikanth V <vnv.srikanth@samsung.com>
Signed-off-by: Oleg_Kosheliev <oleg.kosheliev@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |  150 +++++++++++++++------------------------------
 1 file changed, 50 insertions(+), 100 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 277a8db..1606ced 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -90,7 +90,6 @@ static unsigned twl6030_irq_base;
 static int twl_irq;
 static bool twl_irq_wake_enabled;
 
-static struct completion irq_event;
 static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
 
 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
@@ -131,95 +130,57 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
 };
 
 /*
- * This thread processes interrupts reported by the Primary Interrupt Handler.
- */
-static int twl6030_irq_thread(void *data)
+* 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 irqreturn_t twl6030_irq_thread(int irq, void *data)
 {
-	long irq = (long)data;
-	static unsigned i2c_errors;
-	static const unsigned max_i2c_errors = 100;
-	int ret;
-
-	while (!kthread_should_stop()) {
-		int i;
-		union {
+	int i, ret;
+	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;
 
+	/* 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_warn("twl6030_irq: I2C error %d reading PIH ISR\n", ret);
+		return IRQ_HANDLED;
+	}
 
-		sts.bytes[3] = 0; /* Only 24 bits are valid*/
+	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;
+	/*
+	 * 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;
 
-		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 +
+	for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
+		if (sts.int_sts & 0x1) {
+			int module_irq = twl6030_irq_base +
 					twl6030_interrupt_mapping[i];
-				generic_handle_irq(module_irq);
-
-			}
-		local_irq_enable();
+			handle_nested_irq(module_irq);
+			pr_debug("twl6030_irq: PIH ISR %u, virq%u\n",
+				 i, 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_warn("twl6030_irq: 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;
 }
 
@@ -351,7 +312,6 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 {
 	struct			device_node *node = dev->of_node;
 	int			nr_irqs, irq_base, irq_end;
-	struct task_struct	*task;
 	static struct irq_chip  twl6030_irq_chip;
 	int			status = 0;
 	int			i;
@@ -396,36 +356,26 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 		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, true);
+		irq_set_parent(i, irq_num);
 		activate_irq(i);
 	}
 
-	dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
-			irq_num, irq_base, irq_end);
+	dev_info(dev, "PIH (irq %d) nested IRQs %d..%d\n",
+		 irq_num, irq_base, irq_end);
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
-	init_completion(&irq_event);
-
-	status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
-			     &irq_event);
+	status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
+				      IRQF_ONESHOT, "TWL6030-PIH", NULL);
 	if (status < 0) {
 		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
 	}
 
-	task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
-	if (IS_ERR(task)) {
-		dev_err(dev, "could not create irq %d thread!\n", irq_num);
-		status = PTR_ERR(task);
-		goto fail_kthread;
-	}
-
 	twl_irq = irq_num;
 	register_pm_notifier(&twl6030_irq_pm_notifier_block);
 	return irq_base;
 
-fail_kthread:
-	free_irq(irq_num, &irq_event);
-
 fail_irq:
 	for (i = irq_base; i < irq_end; i++)
 		irq_set_chip_and_handler(i, NULL, NULL);
@@ -435,12 +385,12 @@ fail_irq:
 
 int twl6030_exit_irq(void)
 {
-	unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
 
-	if (twl6030_irq_base) {
-		pr_err("twl6030: can't yet clean up IRQs?\n");
-		return -ENOSYS;
+	if (twl_irq) {
+		unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
+		free_irq(twl_irq, NULL);
 	}
+
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 1/5] mfd: twl6030-irq: migrate to IRQ threaded handler
@ 2013-07-25 13:15   ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

From: Naga Venkata Srikanth V <vnv.srikanth@samsung.com>

1) Removed request_irq() and replaced it with request_threaded_irq().

2) Removed generic_handle_irq() and replaced it with
handle_nested_irq().
  Handling of these interrupts is nested, as we are handling an
interrupt (for e.g rtc, mmc1) when we are still servicing TWL irq.

3) Removed I2C read-retry logic for the case when twl_i2c_read() is
failed inside IRQ handler - there is no sense to do that, so just report
an error and return.

4) Each nested IRQ is configured with corresponding parent_irq,
which need to be retriggered in case if nested IRQ is marked
as IRQS_PENDING.

Signed-off-by: Naga Venkata Srikanth V <vnv.srikanth@samsung.com>
Signed-off-by: Oleg_Kosheliev <oleg.kosheliev@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |  150 +++++++++++++++------------------------------
 1 file changed, 50 insertions(+), 100 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 277a8db..1606ced 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -90,7 +90,6 @@ static unsigned twl6030_irq_base;
 static int twl_irq;
 static bool twl_irq_wake_enabled;
 
-static struct completion irq_event;
 static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
 
 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
@@ -131,95 +130,57 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
 };
 
 /*
- * This thread processes interrupts reported by the Primary Interrupt Handler.
- */
-static int twl6030_irq_thread(void *data)
+* 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 irqreturn_t twl6030_irq_thread(int irq, void *data)
 {
-	long irq = (long)data;
-	static unsigned i2c_errors;
-	static const unsigned max_i2c_errors = 100;
-	int ret;
-
-	while (!kthread_should_stop()) {
-		int i;
-		union {
+	int i, ret;
+	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;
 
+	/* 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_warn("twl6030_irq: I2C error %d reading PIH ISR\n", ret);
+		return IRQ_HANDLED;
+	}
 
-		sts.bytes[3] = 0; /* Only 24 bits are valid*/
+	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;
+	/*
+	 * 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;
 
-		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 +
+	for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
+		if (sts.int_sts & 0x1) {
+			int module_irq = twl6030_irq_base +
 					twl6030_interrupt_mapping[i];
-				generic_handle_irq(module_irq);
-
-			}
-		local_irq_enable();
+			handle_nested_irq(module_irq);
+			pr_debug("twl6030_irq: PIH ISR %u, virq%u\n",
+				 i, 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_warn("twl6030_irq: 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;
 }
 
@@ -351,7 +312,6 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 {
 	struct			device_node *node = dev->of_node;
 	int			nr_irqs, irq_base, irq_end;
-	struct task_struct	*task;
 	static struct irq_chip  twl6030_irq_chip;
 	int			status = 0;
 	int			i;
@@ -396,36 +356,26 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 		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, true);
+		irq_set_parent(i, irq_num);
 		activate_irq(i);
 	}
 
-	dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
-			irq_num, irq_base, irq_end);
+	dev_info(dev, "PIH (irq %d) nested IRQs %d..%d\n",
+		 irq_num, irq_base, irq_end);
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
-	init_completion(&irq_event);
-
-	status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
-			     &irq_event);
+	status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
+				      IRQF_ONESHOT, "TWL6030-PIH", NULL);
 	if (status < 0) {
 		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
 	}
 
-	task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
-	if (IS_ERR(task)) {
-		dev_err(dev, "could not create irq %d thread!\n", irq_num);
-		status = PTR_ERR(task);
-		goto fail_kthread;
-	}
-
 	twl_irq = irq_num;
 	register_pm_notifier(&twl6030_irq_pm_notifier_block);
 	return irq_base;
 
-fail_kthread:
-	free_irq(irq_num, &irq_event);
-
 fail_irq:
 	for (i = irq_base; i < irq_end; i++)
 		irq_set_chip_and_handler(i, NULL, NULL);
@@ -435,12 +385,12 @@ fail_irq:
 
 int twl6030_exit_irq(void)
 {
-	unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
 
-	if (twl6030_irq_base) {
-		pr_err("twl6030: can't yet clean up IRQs?\n");
-		return -ENOSYS;
+	if (twl_irq) {
+		unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
+		free_irq(twl_irq, NULL);
 	}
+
 	return 0;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 2/5] mfd: twl6030-irq: add error check when IRQs are masked initially
  2013-07-25 13:15 ` Grygorii Strashko
@ 2013-07-25 13:15   ` Grygorii Strashko
  -1 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

Add a missed check for errors when TWL IRQs are masked
initially on probe and report an error in case of failure.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
Hi Graeme,

I've tried to use only one write to STS_A register to clear IRQ status bits, but,
unfortunatelly, It is *not* working. Seems, all STS registers need to be cleaned
at least once to make everything working.

BR
-grygorii

 drivers/mfd/twl6030-irq.c |   13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 1606ced..f7da261 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -313,7 +313,7 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	struct			device_node *node = dev->of_node;
 	int			nr_irqs, irq_base, irq_end;
 	static struct irq_chip  twl6030_irq_chip;
-	int			status = 0;
+	int			status;
 	int			i;
 	u8			mask[3];
 
@@ -335,11 +335,16 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	mask[2] = 0xFF;
 
 	/* mask all int lines */
-	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+	status = twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
 	/* mask all int sts */
-	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+	status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
 	/* clear INT_STS_A,B,C */
-	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
+	status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
+
+	if (status < 0) {
+		dev_err(dev, "I2C err writing TWL_MODULE_PIH: %d\n", status);
+		return status;
+	}
 
 	twl6030_irq_base = irq_base;
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 2/5] mfd: twl6030-irq: add error check when IRQs are masked initially
@ 2013-07-25 13:15   ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

Add a missed check for errors when TWL IRQs are masked
initially on probe and report an error in case of failure.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
Hi Graeme,

I've tried to use only one write to STS_A register to clear IRQ status bits, but,
unfortunatelly, It is *not* working. Seems, all STS registers need to be cleaned
at least once to make everything working.

BR
-grygorii

 drivers/mfd/twl6030-irq.c |   13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 1606ced..f7da261 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -313,7 +313,7 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	struct			device_node *node = dev->of_node;
 	int			nr_irqs, irq_base, irq_end;
 	static struct irq_chip  twl6030_irq_chip;
-	int			status = 0;
+	int			status;
 	int			i;
 	u8			mask[3];
 
@@ -335,11 +335,16 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	mask[2] = 0xFF;
 
 	/* mask all int lines */
-	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+	status = twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
 	/* mask all int sts */
-	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+	status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
 	/* clear INT_STS_A,B,C */
-	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
+	status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
+
+	if (status < 0) {
+		dev_err(dev, "I2C err writing TWL_MODULE_PIH: %d\n", status);
+		return status;
+	}
 
 	twl6030_irq_base = irq_base;
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 3/5] mfd: twl6030-irq: convert to use linear irq_domain
  2013-07-25 13:15 ` Grygorii Strashko
@ 2013-07-25 13:15   ` Grygorii Strashko
  -1 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

Since the TWL6030 PMIC is used with OMAP4 SoCs only and OMAP4 legacy
boot is dropped there are no needs to allocate the range of IRQ
descriptors during system boot to support TWL6030 IRQs.

Hence, convert it to use linear irq_domain and move IRQ configuration in
.map()/.unmap() callbacks of irq_domain. So, IRQ mapping and descriptors
allocation will be performed dynamically basing on DT configuration.

The error message will be reported in case if unmapped IRQ is received by
TWL6030 (virq==0).

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |  119 ++++++++++++++++++++++++++-------------------
 1 file changed, 69 insertions(+), 50 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index f7da261..1b03ce9 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -86,11 +86,11 @@ static int twl6030_interrupt_mapping[24] = {
 };
 /*----------------------------------------------------------------------*/
 
-static unsigned twl6030_irq_base;
 static int twl_irq;
 static bool twl_irq_wake_enabled;
 
 static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
+struct irq_domain	*irq_domain;
 
 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
 				   unsigned long pm_event, void *unused)
@@ -138,6 +138,7 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
 static irqreturn_t twl6030_irq_thread(int irq, void *data)
 {
 	int i, ret;
+	struct irq_domain *irq_domain = (struct irq_domain *)data;
 	union {
 		u8 bytes[4];
 		u32 int_sts;
@@ -161,9 +162,14 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 
 	for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
 		if (sts.int_sts & 0x1) {
-			int module_irq = twl6030_irq_base +
-					twl6030_interrupt_mapping[i];
-			handle_nested_irq(module_irq);
+			int module_irq =
+				irq_find_mapping(irq_domain,
+						 twl6030_interrupt_mapping[i]);
+			if (module_irq)
+				handle_nested_irq(module_irq);
+			else
+				pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n",
+				       i);
 			pr_debug("twl6030_irq: PIH ISR %u, virq%u\n",
 				 i, module_irq);
 		}
@@ -186,19 +192,6 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 
 /*----------------------------------------------------------------------*/
 
-static inline void activate_irq(int irq)
-{
-#ifdef CONFIG_ARM
-	/* ARM requires an extra step to clear IRQ_NOREQUEST, which it
-	 * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
-	 */
-	set_irq_flags(irq, IRQF_VALID);
-#else
-	/* same effect on other architectures */
-	irq_set_noprobe(irq);
-#endif
-}
-
 static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	if (on)
@@ -279,7 +272,7 @@ int twl6030_mmc_card_detect_config(void)
 		return ret;
 	}
 
-	return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
+	return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET);
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -308,28 +301,54 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
+static struct irq_chip twl6030_irq_chip;
+
+static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
+			      irq_hw_number_t hwirq)
+{
+	irq_set_chip_data(virq, &twl6030_irq_chip);
+	irq_set_chip_and_handler(virq,  &twl6030_irq_chip, handle_simple_irq);
+	irq_set_nested_thread(virq, true);
+	irq_set_parent(virq, twl_irq);
+
+#ifdef CONFIG_ARM
+	/*
+	 * ARM requires an extra step to clear IRQ_NOREQUEST, which it
+	 * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
+	 */
+	set_irq_flags(virq, IRQF_VALID);
+#else
+	/* same effect on other architectures */
+	irq_set_noprobe(virq);
+#endif
+
+	return 0;
+}
+
+static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq)
+{
+#ifdef CONFIG_ARM
+	set_irq_flags(virq, 0);
+#endif
+	irq_set_chip_and_handler(virq, NULL, NULL);
+	irq_set_chip_data(virq, NULL);
+}
+
+static struct irq_domain_ops twl6030_irq_domain_ops = {
+	.map	= twl6030_irq_map,
+	.unmap	= twl6030_irq_unmap,
+	.xlate	= irq_domain_xlate_onetwocell,
+};
+
 int twl6030_init_irq(struct device *dev, int irq_num)
 {
 	struct			device_node *node = dev->of_node;
-	int			nr_irqs, irq_base, irq_end;
-	static struct irq_chip  twl6030_irq_chip;
+	int			nr_irqs;
 	int			status;
-	int			i;
 	u8			mask[3];
 
 	nr_irqs = TWL6030_NR_IRQS;
 
-	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
-	if (IS_ERR_VALUE(irq_base)) {
-		dev_err(dev, "Fail to allocate IRQ descs\n");
-		return irq_base;
-	}
-
-	irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
-			      &irq_domain_simple_ops, NULL);
-
-	irq_end = irq_base + nr_irqs;
-
 	mask[0] = 0xFF;
 	mask[1] = 0xFF;
 	mask[2] = 0xFF;
@@ -346,8 +365,6 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 		return status;
 	}
 
-	twl6030_irq_base = irq_base;
-
 	/*
 	 * install an irq handler for each of the modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
@@ -357,21 +374,18 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	twl6030_irq_chip.irq_set_type = NULL;
 	twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
 
-	for (i = irq_base; i < irq_end; i++) {
-		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, true);
-		irq_set_parent(i, irq_num);
-		activate_irq(i);
+	irq_domain = irq_domain_add_linear(node, nr_irqs,
+					   &twl6030_irq_domain_ops, NULL);
+	if (!irq_domain) {
+		dev_err(dev, "Can't add irq_domain\n");
+		return -ENOMEM;
 	}
 
-	dev_info(dev, "PIH (irq %d) nested IRQs %d..%d\n",
-		 irq_num, irq_base, irq_end);
+	dev_info(dev, "PIH (irq %d) nested IRQs\n", irq_num);
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
 	status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
-				      IRQF_ONESHOT, "TWL6030-PIH", NULL);
+				      IRQF_ONESHOT, "TWL6030-PIH", irq_domain);
 	if (status < 0) {
 		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
@@ -379,23 +393,28 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	twl_irq = irq_num;
 	register_pm_notifier(&twl6030_irq_pm_notifier_block);
-	return irq_base;
+	return 0;
 
 fail_irq:
-	for (i = irq_base; i < irq_end; i++)
-		irq_set_chip_and_handler(i, NULL, NULL);
-
+	irq_domain_remove(irq_domain);
 	return status;
 }
 
 int twl6030_exit_irq(void)
 {
-
 	if (twl_irq) {
 		unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
 		free_irq(twl_irq, NULL);
+		/*
+		 * TODO: IRQ domain and allocated nested IRQ descriptors
+		 * should be freed somehow here. Now It can't be done, because
+		 * child devices will not be deleted during removing of
+		 * TWL Core driver and they will still contain allocated
+		 * virt IRQs in their Resources tables.
+		 * The same prevents us from using devm_request_threaded_irq()
+		 * in this module.
+		 */
 	}
-
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 3/5] mfd: twl6030-irq: convert to use linear irq_domain
@ 2013-07-25 13:15   ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

Since the TWL6030 PMIC is used with OMAP4 SoCs only and OMAP4 legacy
boot is dropped there are no needs to allocate the range of IRQ
descriptors during system boot to support TWL6030 IRQs.

Hence, convert it to use linear irq_domain and move IRQ configuration in
.map()/.unmap() callbacks of irq_domain. So, IRQ mapping and descriptors
allocation will be performed dynamically basing on DT configuration.

The error message will be reported in case if unmapped IRQ is received by
TWL6030 (virq==0).

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |  119 ++++++++++++++++++++++++++-------------------
 1 file changed, 69 insertions(+), 50 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index f7da261..1b03ce9 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -86,11 +86,11 @@ static int twl6030_interrupt_mapping[24] = {
 };
 /*----------------------------------------------------------------------*/
 
-static unsigned twl6030_irq_base;
 static int twl_irq;
 static bool twl_irq_wake_enabled;
 
 static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
+struct irq_domain	*irq_domain;
 
 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
 				   unsigned long pm_event, void *unused)
@@ -138,6 +138,7 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
 static irqreturn_t twl6030_irq_thread(int irq, void *data)
 {
 	int i, ret;
+	struct irq_domain *irq_domain = (struct irq_domain *)data;
 	union {
 		u8 bytes[4];
 		u32 int_sts;
@@ -161,9 +162,14 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 
 	for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
 		if (sts.int_sts & 0x1) {
-			int module_irq = twl6030_irq_base +
-					twl6030_interrupt_mapping[i];
-			handle_nested_irq(module_irq);
+			int module_irq =
+				irq_find_mapping(irq_domain,
+						 twl6030_interrupt_mapping[i]);
+			if (module_irq)
+				handle_nested_irq(module_irq);
+			else
+				pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n",
+				       i);
 			pr_debug("twl6030_irq: PIH ISR %u, virq%u\n",
 				 i, module_irq);
 		}
@@ -186,19 +192,6 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 
 /*----------------------------------------------------------------------*/
 
-static inline void activate_irq(int irq)
-{
-#ifdef CONFIG_ARM
-	/* ARM requires an extra step to clear IRQ_NOREQUEST, which it
-	 * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
-	 */
-	set_irq_flags(irq, IRQF_VALID);
-#else
-	/* same effect on other architectures */
-	irq_set_noprobe(irq);
-#endif
-}
-
 static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	if (on)
@@ -279,7 +272,7 @@ int twl6030_mmc_card_detect_config(void)
 		return ret;
 	}
 
-	return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
+	return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET);
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -308,28 +301,54 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
+static struct irq_chip twl6030_irq_chip;
+
+static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
+			      irq_hw_number_t hwirq)
+{
+	irq_set_chip_data(virq, &twl6030_irq_chip);
+	irq_set_chip_and_handler(virq,  &twl6030_irq_chip, handle_simple_irq);
+	irq_set_nested_thread(virq, true);
+	irq_set_parent(virq, twl_irq);
+
+#ifdef CONFIG_ARM
+	/*
+	 * ARM requires an extra step to clear IRQ_NOREQUEST, which it
+	 * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
+	 */
+	set_irq_flags(virq, IRQF_VALID);
+#else
+	/* same effect on other architectures */
+	irq_set_noprobe(virq);
+#endif
+
+	return 0;
+}
+
+static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq)
+{
+#ifdef CONFIG_ARM
+	set_irq_flags(virq, 0);
+#endif
+	irq_set_chip_and_handler(virq, NULL, NULL);
+	irq_set_chip_data(virq, NULL);
+}
+
+static struct irq_domain_ops twl6030_irq_domain_ops = {
+	.map	= twl6030_irq_map,
+	.unmap	= twl6030_irq_unmap,
+	.xlate	= irq_domain_xlate_onetwocell,
+};
+
 int twl6030_init_irq(struct device *dev, int irq_num)
 {
 	struct			device_node *node = dev->of_node;
-	int			nr_irqs, irq_base, irq_end;
-	static struct irq_chip  twl6030_irq_chip;
+	int			nr_irqs;
 	int			status;
-	int			i;
 	u8			mask[3];
 
 	nr_irqs = TWL6030_NR_IRQS;
 
-	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
-	if (IS_ERR_VALUE(irq_base)) {
-		dev_err(dev, "Fail to allocate IRQ descs\n");
-		return irq_base;
-	}
-
-	irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
-			      &irq_domain_simple_ops, NULL);
-
-	irq_end = irq_base + nr_irqs;
-
 	mask[0] = 0xFF;
 	mask[1] = 0xFF;
 	mask[2] = 0xFF;
@@ -346,8 +365,6 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 		return status;
 	}
 
-	twl6030_irq_base = irq_base;
-
 	/*
 	 * install an irq handler for each of the modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
@@ -357,21 +374,18 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	twl6030_irq_chip.irq_set_type = NULL;
 	twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
 
-	for (i = irq_base; i < irq_end; i++) {
-		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, true);
-		irq_set_parent(i, irq_num);
-		activate_irq(i);
+	irq_domain = irq_domain_add_linear(node, nr_irqs,
+					   &twl6030_irq_domain_ops, NULL);
+	if (!irq_domain) {
+		dev_err(dev, "Can't add irq_domain\n");
+		return -ENOMEM;
 	}
 
-	dev_info(dev, "PIH (irq %d) nested IRQs %d..%d\n",
-		 irq_num, irq_base, irq_end);
+	dev_info(dev, "PIH (irq %d) nested IRQs\n", irq_num);
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
 	status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
-				      IRQF_ONESHOT, "TWL6030-PIH", NULL);
+				      IRQF_ONESHOT, "TWL6030-PIH", irq_domain);
 	if (status < 0) {
 		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
@@ -379,23 +393,28 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	twl_irq = irq_num;
 	register_pm_notifier(&twl6030_irq_pm_notifier_block);
-	return irq_base;
+	return 0;
 
 fail_irq:
-	for (i = irq_base; i < irq_end; i++)
-		irq_set_chip_and_handler(i, NULL, NULL);
-
+	irq_domain_remove(irq_domain);
 	return status;
 }
 
 int twl6030_exit_irq(void)
 {
-
 	if (twl_irq) {
 		unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
 		free_irq(twl_irq, NULL);
+		/*
+		 * TODO: IRQ domain and allocated nested IRQ descriptors
+		 * should be freed somehow here. Now It can't be done, because
+		 * child devices will not be deleted during removing of
+		 * TWL Core driver and they will still contain allocated
+		 * virt IRQs in their Resources tables.
+		 * The same prevents us from using devm_request_threaded_irq()
+		 * in this module.
+		 */
 	}
-
 	return 0;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 4/5] mfd: twl6030-irq: create struct twl6030_irq
  2013-07-25 13:15 ` Grygorii Strashko
@ 2013-07-25 13:15   ` Grygorii Strashko
  -1 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

Create "struct twl6030_irq" and place all local variables inside it.
Also allocate twl6030_irq structure dynamically during initialization.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |  101 ++++++++++++++++++++++++++-------------------
 1 file changed, 59 insertions(+), 42 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 1b03ce9..e3c54f8 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -86,36 +86,44 @@ static int twl6030_interrupt_mapping[24] = {
 };
 /*----------------------------------------------------------------------*/
 
-static int twl_irq;
-static bool twl_irq_wake_enabled;
+struct twl6030_irq {
+	unsigned int		irq_base;
+	int			twl_irq;
+	bool			irq_wake_enabled;
+	atomic_t		wakeirqs;
+	struct notifier_block	pm_nb;
+	struct irq_chip		irq_chip;
+	struct irq_domain	*irq_domain;
+};
 
-static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
-struct irq_domain	*irq_domain;
+static struct twl6030_irq *twl6030_irq;
 
 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
 				   unsigned long pm_event, void *unused)
 {
 	int chained_wakeups;
+	struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq,
+						  pm_nb);
 
 	switch (pm_event) {
 	case PM_SUSPEND_PREPARE:
-		chained_wakeups = atomic_read(&twl6030_wakeirqs);
+		chained_wakeups = atomic_read(&pdata->wakeirqs);
 
-		if (chained_wakeups && !twl_irq_wake_enabled) {
-			if (enable_irq_wake(twl_irq))
+		if (chained_wakeups && !pdata->irq_wake_enabled) {
+			if (enable_irq_wake(pdata->twl_irq))
 				pr_err("twl6030 IRQ wake enable failed\n");
 			else
-				twl_irq_wake_enabled = true;
-		} else if (!chained_wakeups && twl_irq_wake_enabled) {
-			disable_irq_wake(twl_irq);
-			twl_irq_wake_enabled = false;
+				pdata->irq_wake_enabled = true;
+		} else if (!chained_wakeups && pdata->irq_wake_enabled) {
+			disable_irq_wake(pdata->twl_irq);
+			pdata->irq_wake_enabled = false;
 		}
 
-		disable_irq(twl_irq);
+		disable_irq(pdata->twl_irq);
 		break;
 
 	case PM_POST_SUSPEND:
-		enable_irq(twl_irq);
+		enable_irq(pdata->twl_irq);
 		break;
 
 	default:
@@ -125,10 +133,6 @@ static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
 	return NOTIFY_DONE;
 }
 
-static struct notifier_block twl6030_irq_pm_notifier_block = {
-	.notifier_call = twl6030_irq_pm_notifier,
-};
-
 /*
 * Threaded irq handler for the twl6030 interrupt.
 * We query the interrupt controller in the twl6030 to determine
@@ -138,11 +142,11 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
 static irqreturn_t twl6030_irq_thread(int irq, void *data)
 {
 	int i, ret;
-	struct irq_domain *irq_domain = (struct irq_domain *)data;
 	union {
 		u8 bytes[4];
 		u32 int_sts;
 	} sts;
+	struct twl6030_irq *pdata = data;
 
 	/* 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);
@@ -163,7 +167,7 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 	for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
 		if (sts.int_sts & 0x1) {
 			int module_irq =
-				irq_find_mapping(irq_domain,
+				irq_find_mapping(pdata->irq_domain,
 						 twl6030_interrupt_mapping[i]);
 			if (module_irq)
 				handle_nested_irq(module_irq);
@@ -194,10 +198,12 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 
 static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
+	struct twl6030_irq *pdata = irq_get_chip_data(d->irq);
+
 	if (on)
-		atomic_inc(&twl6030_wakeirqs);
+		atomic_inc(&pdata->wakeirqs);
 	else
-		atomic_dec(&twl6030_wakeirqs);
+		atomic_dec(&pdata->wakeirqs);
 
 	return 0;
 }
@@ -272,7 +278,8 @@ int twl6030_mmc_card_detect_config(void)
 		return ret;
 	}
 
-	return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET);
+	return irq_find_mapping(twl6030_irq->irq_domain,
+				 MMCDETECT_INTR_OFFSET);
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -301,15 +308,15 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
-static struct irq_chip twl6030_irq_chip;
-
 static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
 			      irq_hw_number_t hwirq)
 {
-	irq_set_chip_data(virq, &twl6030_irq_chip);
-	irq_set_chip_and_handler(virq,  &twl6030_irq_chip, handle_simple_irq);
+	struct twl6030_irq *pdata = d->host_data;
+
+	irq_set_chip_data(virq, pdata);
+	irq_set_chip_and_handler(virq,  &pdata->irq_chip, handle_simple_irq);
 	irq_set_nested_thread(virq, true);
-	irq_set_parent(virq, twl_irq);
+	irq_set_parent(virq, pdata->twl_irq);
 
 #ifdef CONFIG_ARM
 	/*
@@ -349,6 +356,12 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	nr_irqs = TWL6030_NR_IRQS;
 
+	twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL);
+	if (!twl6030_irq) {
+		dev_err(dev, "twl6030_irq: Memory allocation failed\n");
+		return -ENOMEM;
+	}
+
 	mask[0] = 0xFF;
 	mask[1] = 0xFF;
 	mask[2] = 0xFF;
@@ -369,14 +382,18 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	 * install an irq handler for each of the modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 */
-	twl6030_irq_chip = dummy_irq_chip;
-	twl6030_irq_chip.name = "twl6030";
-	twl6030_irq_chip.irq_set_type = NULL;
-	twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
-
-	irq_domain = irq_domain_add_linear(node, nr_irqs,
-					   &twl6030_irq_domain_ops, NULL);
-	if (!irq_domain) {
+	twl6030_irq->irq_chip = dummy_irq_chip;
+	twl6030_irq->irq_chip.name = "twl6030";
+	twl6030_irq->irq_chip.irq_set_type = NULL;
+	twl6030_irq->irq_chip.irq_set_wake = twl6030_irq_set_wake;
+
+	twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
+	atomic_set(&twl6030_irq->wakeirqs, 0);
+
+	twl6030_irq->irq_domain =
+		irq_domain_add_linear(node, nr_irqs,
+				      &twl6030_irq_domain_ops, twl6030_irq);
+	if (!twl6030_irq->irq_domain) {
 		dev_err(dev, "Can't add irq_domain\n");
 		return -ENOMEM;
 	}
@@ -385,26 +402,26 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
 	status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
-				      IRQF_ONESHOT, "TWL6030-PIH", irq_domain);
+				      IRQF_ONESHOT, "TWL6030-PIH", twl6030_irq);
 	if (status < 0) {
 		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
 	}
 
-	twl_irq = irq_num;
-	register_pm_notifier(&twl6030_irq_pm_notifier_block);
+	twl6030_irq->twl_irq = irq_num;
+	register_pm_notifier(&twl6030_irq->pm_nb);
 	return 0;
 
 fail_irq:
-	irq_domain_remove(irq_domain);
+	irq_domain_remove(twl6030_irq->irq_domain);
 	return status;
 }
 
 int twl6030_exit_irq(void)
 {
-	if (twl_irq) {
-		unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
-		free_irq(twl_irq, NULL);
+	if (twl6030_irq && twl6030_irq->twl_irq) {
+		unregister_pm_notifier(&twl6030_irq->pm_nb);
+		free_irq(twl6030_irq->twl_irq, NULL);
 		/*
 		 * TODO: IRQ domain and allocated nested IRQ descriptors
 		 * should be freed somehow here. Now It can't be done, because
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 4/5] mfd: twl6030-irq: create struct twl6030_irq
@ 2013-07-25 13:15   ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

Create "struct twl6030_irq" and place all local variables inside it.
Also allocate twl6030_irq structure dynamically during initialization.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |  101 ++++++++++++++++++++++++++-------------------
 1 file changed, 59 insertions(+), 42 deletions(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 1b03ce9..e3c54f8 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -86,36 +86,44 @@ static int twl6030_interrupt_mapping[24] = {
 };
 /*----------------------------------------------------------------------*/
 
-static int twl_irq;
-static bool twl_irq_wake_enabled;
+struct twl6030_irq {
+	unsigned int		irq_base;
+	int			twl_irq;
+	bool			irq_wake_enabled;
+	atomic_t		wakeirqs;
+	struct notifier_block	pm_nb;
+	struct irq_chip		irq_chip;
+	struct irq_domain	*irq_domain;
+};
 
-static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
-struct irq_domain	*irq_domain;
+static struct twl6030_irq *twl6030_irq;
 
 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
 				   unsigned long pm_event, void *unused)
 {
 	int chained_wakeups;
+	struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq,
+						  pm_nb);
 
 	switch (pm_event) {
 	case PM_SUSPEND_PREPARE:
-		chained_wakeups = atomic_read(&twl6030_wakeirqs);
+		chained_wakeups = atomic_read(&pdata->wakeirqs);
 
-		if (chained_wakeups && !twl_irq_wake_enabled) {
-			if (enable_irq_wake(twl_irq))
+		if (chained_wakeups && !pdata->irq_wake_enabled) {
+			if (enable_irq_wake(pdata->twl_irq))
 				pr_err("twl6030 IRQ wake enable failed\n");
 			else
-				twl_irq_wake_enabled = true;
-		} else if (!chained_wakeups && twl_irq_wake_enabled) {
-			disable_irq_wake(twl_irq);
-			twl_irq_wake_enabled = false;
+				pdata->irq_wake_enabled = true;
+		} else if (!chained_wakeups && pdata->irq_wake_enabled) {
+			disable_irq_wake(pdata->twl_irq);
+			pdata->irq_wake_enabled = false;
 		}
 
-		disable_irq(twl_irq);
+		disable_irq(pdata->twl_irq);
 		break;
 
 	case PM_POST_SUSPEND:
-		enable_irq(twl_irq);
+		enable_irq(pdata->twl_irq);
 		break;
 
 	default:
@@ -125,10 +133,6 @@ static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
 	return NOTIFY_DONE;
 }
 
-static struct notifier_block twl6030_irq_pm_notifier_block = {
-	.notifier_call = twl6030_irq_pm_notifier,
-};
-
 /*
 * Threaded irq handler for the twl6030 interrupt.
 * We query the interrupt controller in the twl6030 to determine
@@ -138,11 +142,11 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
 static irqreturn_t twl6030_irq_thread(int irq, void *data)
 {
 	int i, ret;
-	struct irq_domain *irq_domain = (struct irq_domain *)data;
 	union {
 		u8 bytes[4];
 		u32 int_sts;
 	} sts;
+	struct twl6030_irq *pdata = data;
 
 	/* 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);
@@ -163,7 +167,7 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 	for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
 		if (sts.int_sts & 0x1) {
 			int module_irq =
-				irq_find_mapping(irq_domain,
+				irq_find_mapping(pdata->irq_domain,
 						 twl6030_interrupt_mapping[i]);
 			if (module_irq)
 				handle_nested_irq(module_irq);
@@ -194,10 +198,12 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 
 static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
+	struct twl6030_irq *pdata = irq_get_chip_data(d->irq);
+
 	if (on)
-		atomic_inc(&twl6030_wakeirqs);
+		atomic_inc(&pdata->wakeirqs);
 	else
-		atomic_dec(&twl6030_wakeirqs);
+		atomic_dec(&pdata->wakeirqs);
 
 	return 0;
 }
@@ -272,7 +278,8 @@ int twl6030_mmc_card_detect_config(void)
 		return ret;
 	}
 
-	return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET);
+	return irq_find_mapping(twl6030_irq->irq_domain,
+				 MMCDETECT_INTR_OFFSET);
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -301,15 +308,15 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
-static struct irq_chip twl6030_irq_chip;
-
 static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
 			      irq_hw_number_t hwirq)
 {
-	irq_set_chip_data(virq, &twl6030_irq_chip);
-	irq_set_chip_and_handler(virq,  &twl6030_irq_chip, handle_simple_irq);
+	struct twl6030_irq *pdata = d->host_data;
+
+	irq_set_chip_data(virq, pdata);
+	irq_set_chip_and_handler(virq,  &pdata->irq_chip, handle_simple_irq);
 	irq_set_nested_thread(virq, true);
-	irq_set_parent(virq, twl_irq);
+	irq_set_parent(virq, pdata->twl_irq);
 
 #ifdef CONFIG_ARM
 	/*
@@ -349,6 +356,12 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	nr_irqs = TWL6030_NR_IRQS;
 
+	twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL);
+	if (!twl6030_irq) {
+		dev_err(dev, "twl6030_irq: Memory allocation failed\n");
+		return -ENOMEM;
+	}
+
 	mask[0] = 0xFF;
 	mask[1] = 0xFF;
 	mask[2] = 0xFF;
@@ -369,14 +382,18 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 	 * install an irq handler for each of the modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 */
-	twl6030_irq_chip = dummy_irq_chip;
-	twl6030_irq_chip.name = "twl6030";
-	twl6030_irq_chip.irq_set_type = NULL;
-	twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
-
-	irq_domain = irq_domain_add_linear(node, nr_irqs,
-					   &twl6030_irq_domain_ops, NULL);
-	if (!irq_domain) {
+	twl6030_irq->irq_chip = dummy_irq_chip;
+	twl6030_irq->irq_chip.name = "twl6030";
+	twl6030_irq->irq_chip.irq_set_type = NULL;
+	twl6030_irq->irq_chip.irq_set_wake = twl6030_irq_set_wake;
+
+	twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
+	atomic_set(&twl6030_irq->wakeirqs, 0);
+
+	twl6030_irq->irq_domain =
+		irq_domain_add_linear(node, nr_irqs,
+				      &twl6030_irq_domain_ops, twl6030_irq);
+	if (!twl6030_irq->irq_domain) {
 		dev_err(dev, "Can't add irq_domain\n");
 		return -ENOMEM;
 	}
@@ -385,26 +402,26 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
 	status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
-				      IRQF_ONESHOT, "TWL6030-PIH", irq_domain);
+				      IRQF_ONESHOT, "TWL6030-PIH", twl6030_irq);
 	if (status < 0) {
 		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
 	}
 
-	twl_irq = irq_num;
-	register_pm_notifier(&twl6030_irq_pm_notifier_block);
+	twl6030_irq->twl_irq = irq_num;
+	register_pm_notifier(&twl6030_irq->pm_nb);
 	return 0;
 
 fail_irq:
-	irq_domain_remove(irq_domain);
+	irq_domain_remove(twl6030_irq->irq_domain);
 	return status;
 }
 
 int twl6030_exit_irq(void)
 {
-	if (twl_irq) {
-		unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
-		free_irq(twl_irq, NULL);
+	if (twl6030_irq && twl6030_irq->twl_irq) {
+		unregister_pm_notifier(&twl6030_irq->pm_nb);
+		free_irq(twl6030_irq->twl_irq, NULL);
 		/*
 		 * TODO: IRQ domain and allocated nested IRQ descriptors
 		 * should be freed somehow here. Now It can't be done, because
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 5/5] mfd: twl6030-irq: Add interrupt mapping table for the twl6032
  2013-07-25 13:15 ` Grygorii Strashko
@ 2013-07-25 13:15   ` Grygorii Strashko
  -1 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

From: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@ti.com>

The TWL6032 PMIC has different IRQ status bits meaning.
Hence, add interrupt mapping table for the twl6032.

Signed-off-by: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |   48 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index e3c54f8..517eda8 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -41,6 +41,7 @@
 #include <linux/suspend.h>
 #include <linux/of.h>
 #include <linux/irqdomain.h>
+#include <linux/of_device.h>
 
 #include "twl-core.h"
 
@@ -84,6 +85,36 @@ static int twl6030_interrupt_mapping[24] = {
 	CHARGERFAULT_INTR_OFFSET,	/* Bit 22	INT_CHRG	*/
 	RSV_INTR_OFFSET,	/* Bit 23	Reserved		*/
 };
+
+static int twl6032_interrupt_mapping[24] = {
+	PWR_INTR_OFFSET,	/* Bit 0	PWRON			*/
+	PWR_INTR_OFFSET,	/* Bit 1	RPWRON			*/
+	PWR_INTR_OFFSET,	/* Bit 2	SYS_VLOW		*/
+	RTC_INTR_OFFSET,	/* Bit 3	RTC_ALARM		*/
+	RTC_INTR_OFFSET,	/* Bit 4	RTC_PERIOD		*/
+	HOTDIE_INTR_OFFSET,	/* Bit 5	HOT_DIE			*/
+	SMPSLDO_INTR_OFFSET,	/* Bit 6	VXXX_SHORT		*/
+	PWR_INTR_OFFSET,	/* Bit 7	SPDURATION		*/
+
+	PWR_INTR_OFFSET,	/* Bit 8	WATCHDOG		*/
+	BATDETECT_INTR_OFFSET,	/* Bit 9	BAT			*/
+	SIMDETECT_INTR_OFFSET,	/* Bit 10	SIM			*/
+	MMCDETECT_INTR_OFFSET,	/* Bit 11	MMC			*/
+	MADC_INTR_OFFSET,	/* Bit 12	GPADC_RT_EOC		*/
+	MADC_INTR_OFFSET,	/* Bit 13	GPADC_SW_EOC		*/
+	GASGAUGE_INTR_OFFSET,	/* Bit 14	CC_EOC			*/
+	GASGAUGE_INTR_OFFSET,	/* Bit 15	CC_AUTOCAL		*/
+
+	USBOTG_INTR_OFFSET,	/* Bit 16	ID_WKUP			*/
+	USBOTG_INTR_OFFSET,	/* Bit 17	VBUS_WKUP		*/
+	USBOTG_INTR_OFFSET,	/* Bit 18	ID			*/
+	USB_PRES_INTR_OFFSET,	/* Bit 19	VBUS			*/
+	CHARGER_INTR_OFFSET,	/* Bit 20	CHRG_CTRL		*/
+	CHARGERFAULT_INTR_OFFSET,	/* Bit 21	EXT_CHRG	*/
+	CHARGERFAULT_INTR_OFFSET,	/* Bit 22	INT_CHRG	*/
+	RSV_INTR_OFFSET,	/* Bit 23	Reserved		*/
+};
+
 /*----------------------------------------------------------------------*/
 
 struct twl6030_irq {
@@ -94,6 +125,7 @@ struct twl6030_irq {
 	struct notifier_block	pm_nb;
 	struct irq_chip		irq_chip;
 	struct irq_domain	*irq_domain;
+	const int		*irq_mapping_tbl;
 };
 
 static struct twl6030_irq *twl6030_irq;
@@ -168,7 +200,7 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 		if (sts.int_sts & 0x1) {
 			int module_irq =
 				irq_find_mapping(pdata->irq_domain,
-						 twl6030_interrupt_mapping[i]);
+						 pdata->irq_mapping_tbl[i]);
 			if (module_irq)
 				handle_nested_irq(module_irq);
 			else
@@ -347,12 +379,25 @@ static struct irq_domain_ops twl6030_irq_domain_ops = {
 	.xlate	= irq_domain_xlate_onetwocell,
 };
 
+static const struct of_device_id twl6030_of_match[] = {
+	{.compatible = "ti,twl6030", &twl6030_interrupt_mapping},
+	{.compatible = "ti,twl6032", &twl6032_interrupt_mapping},
+	{ },
+};
+
 int twl6030_init_irq(struct device *dev, int irq_num)
 {
 	struct			device_node *node = dev->of_node;
 	int			nr_irqs;
 	int			status;
 	u8			mask[3];
+	const struct of_device_id *of_id;
+
+	of_id = of_match_device(twl6030_of_match, dev);
+	if (!of_id || !of_id->data) {
+		dev_err(dev, "Unknown TWL device model\n");
+		return -EINVAL;
+	}
 
 	nr_irqs = TWL6030_NR_IRQS;
 
@@ -389,6 +434,7 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
 	atomic_set(&twl6030_irq->wakeirqs, 0);
+	twl6030_irq->irq_mapping_tbl = of_id->data;
 
 	twl6030_irq->irq_domain =
 		irq_domain_add_linear(node, nr_irqs,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 5/5] mfd: twl6030-irq: Add interrupt mapping table for the twl6032
@ 2013-07-25 13:15   ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-07-25 13:15 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones
  Cc: Kevin Hilman, Graeme Gregory, linux-omap, Ruslan Bilovol,
	linux-kernel, Grygorii Strashko

From: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@ti.com>

The TWL6032 PMIC has different IRQ status bits meaning.
Hence, add interrupt mapping table for the twl6032.

Signed-off-by: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/mfd/twl6030-irq.c |   48 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index e3c54f8..517eda8 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -41,6 +41,7 @@
 #include <linux/suspend.h>
 #include <linux/of.h>
 #include <linux/irqdomain.h>
+#include <linux/of_device.h>
 
 #include "twl-core.h"
 
@@ -84,6 +85,36 @@ static int twl6030_interrupt_mapping[24] = {
 	CHARGERFAULT_INTR_OFFSET,	/* Bit 22	INT_CHRG	*/
 	RSV_INTR_OFFSET,	/* Bit 23	Reserved		*/
 };
+
+static int twl6032_interrupt_mapping[24] = {
+	PWR_INTR_OFFSET,	/* Bit 0	PWRON			*/
+	PWR_INTR_OFFSET,	/* Bit 1	RPWRON			*/
+	PWR_INTR_OFFSET,	/* Bit 2	SYS_VLOW		*/
+	RTC_INTR_OFFSET,	/* Bit 3	RTC_ALARM		*/
+	RTC_INTR_OFFSET,	/* Bit 4	RTC_PERIOD		*/
+	HOTDIE_INTR_OFFSET,	/* Bit 5	HOT_DIE			*/
+	SMPSLDO_INTR_OFFSET,	/* Bit 6	VXXX_SHORT		*/
+	PWR_INTR_OFFSET,	/* Bit 7	SPDURATION		*/
+
+	PWR_INTR_OFFSET,	/* Bit 8	WATCHDOG		*/
+	BATDETECT_INTR_OFFSET,	/* Bit 9	BAT			*/
+	SIMDETECT_INTR_OFFSET,	/* Bit 10	SIM			*/
+	MMCDETECT_INTR_OFFSET,	/* Bit 11	MMC			*/
+	MADC_INTR_OFFSET,	/* Bit 12	GPADC_RT_EOC		*/
+	MADC_INTR_OFFSET,	/* Bit 13	GPADC_SW_EOC		*/
+	GASGAUGE_INTR_OFFSET,	/* Bit 14	CC_EOC			*/
+	GASGAUGE_INTR_OFFSET,	/* Bit 15	CC_AUTOCAL		*/
+
+	USBOTG_INTR_OFFSET,	/* Bit 16	ID_WKUP			*/
+	USBOTG_INTR_OFFSET,	/* Bit 17	VBUS_WKUP		*/
+	USBOTG_INTR_OFFSET,	/* Bit 18	ID			*/
+	USB_PRES_INTR_OFFSET,	/* Bit 19	VBUS			*/
+	CHARGER_INTR_OFFSET,	/* Bit 20	CHRG_CTRL		*/
+	CHARGERFAULT_INTR_OFFSET,	/* Bit 21	EXT_CHRG	*/
+	CHARGERFAULT_INTR_OFFSET,	/* Bit 22	INT_CHRG	*/
+	RSV_INTR_OFFSET,	/* Bit 23	Reserved		*/
+};
+
 /*----------------------------------------------------------------------*/
 
 struct twl6030_irq {
@@ -94,6 +125,7 @@ struct twl6030_irq {
 	struct notifier_block	pm_nb;
 	struct irq_chip		irq_chip;
 	struct irq_domain	*irq_domain;
+	const int		*irq_mapping_tbl;
 };
 
 static struct twl6030_irq *twl6030_irq;
@@ -168,7 +200,7 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
 		if (sts.int_sts & 0x1) {
 			int module_irq =
 				irq_find_mapping(pdata->irq_domain,
-						 twl6030_interrupt_mapping[i]);
+						 pdata->irq_mapping_tbl[i]);
 			if (module_irq)
 				handle_nested_irq(module_irq);
 			else
@@ -347,12 +379,25 @@ static struct irq_domain_ops twl6030_irq_domain_ops = {
 	.xlate	= irq_domain_xlate_onetwocell,
 };
 
+static const struct of_device_id twl6030_of_match[] = {
+	{.compatible = "ti,twl6030", &twl6030_interrupt_mapping},
+	{.compatible = "ti,twl6032", &twl6032_interrupt_mapping},
+	{ },
+};
+
 int twl6030_init_irq(struct device *dev, int irq_num)
 {
 	struct			device_node *node = dev->of_node;
 	int			nr_irqs;
 	int			status;
 	u8			mask[3];
+	const struct of_device_id *of_id;
+
+	of_id = of_match_device(twl6030_of_match, dev);
+	if (!of_id || !of_id->data) {
+		dev_err(dev, "Unknown TWL device model\n");
+		return -EINVAL;
+	}
 
 	nr_irqs = TWL6030_NR_IRQS;
 
@@ -389,6 +434,7 @@ int twl6030_init_irq(struct device *dev, int irq_num)
 
 	twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
 	atomic_set(&twl6030_irq->wakeirqs, 0);
+	twl6030_irq->irq_mapping_tbl = of_id->data;
 
 	twl6030_irq->irq_domain =
 		irq_domain_add_linear(node, nr_irqs,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support
  2013-07-25 13:15 ` Grygorii Strashko
                   ` (5 preceding siblings ...)
  (?)
@ 2013-08-20  1:01 ` Samuel Ortiz
  2013-08-20  7:13   ` Graeme Gregory
  -1 siblings, 1 reply; 17+ messages in thread
From: Samuel Ortiz @ 2013-08-20  1:01 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Lee Jones, Kevin Hilman, Graeme Gregory, linux-omap,
	Ruslan Bilovol, linux-kernel

Hi Grygorii,

On Thu, Jul 25, 2013 at 04:15:46PM +0300, Grygorii Strashko wrote:
> This patch series intorduces twl6030-irq module rework to use Threaded IRQ and
> linear irq_domain, and adds support for PMIC TWL6032 IRQs.
> 
> After this patch series TWL6030/6032 IRQs will be supported only for DT boot mode.
> 
> Changes since v1:
> - Added new patch "mfd: twl6030-irq: create struct twl6030_irq" 
>   which introduces "struct twl6030_irq" to store all local variables inside it.
> - Patch "mfd: twl6030-irq: migrate to IRQ threaded handler":
>   Minor comments applied; fixed twl6030_exit_irq();
>   The Parent IRQ has been set for each nested IRQ.
> - Patch "mfd: twl6030-irq: convert to use linear irq_domain":
>   The irq_find_mapping() is used in twl6030_mmc_card_detect_config()
>   to get virtual IRQ number.
This looks good to me. Kevin, Graeme, any further comments/ACKs ?

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support
  2013-08-20  1:01 ` [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support Samuel Ortiz
@ 2013-08-20  7:13   ` Graeme Gregory
  2013-08-20  8:18     ` Samuel Ortiz
  0 siblings, 1 reply; 17+ messages in thread
From: Graeme Gregory @ 2013-08-20  7:13 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Grygorii Strashko, Lee Jones, Kevin Hilman, linux-omap,
	Ruslan Bilovol, linux-kernel

On 20/08/13 02:01, Samuel Ortiz wrote:
> Hi Grygorii,
>
> On Thu, Jul 25, 2013 at 04:15:46PM +0300, Grygorii Strashko wrote:
>> This patch series intorduces twl6030-irq module rework to use Threaded IRQ and
>> linear irq_domain, and adds support for PMIC TWL6032 IRQs.
>>
>> After this patch series TWL6030/6032 IRQs will be supported only for DT boot mode.
>>
>> Changes since v1:
>> - Added new patch "mfd: twl6030-irq: create struct twl6030_irq"
>>    which introduces "struct twl6030_irq" to store all local variables inside it.
>> - Patch "mfd: twl6030-irq: migrate to IRQ threaded handler":
>>    Minor comments applied; fixed twl6030_exit_irq();
>>    The Parent IRQ has been set for each nested IRQ.
>> - Patch "mfd: twl6030-irq: convert to use linear irq_domain":
>>    The irq_find_mapping() is used in twl6030_mmc_card_detect_config()
>>    to get virtual IRQ number.
> This looks good to me. Kevin, Graeme, any further comments/ACKs ?
>
> Cheers,
> Samuel.
>
Yes, it looked good to me as well.

Acked-by: Graeme Gregory <gg@slimlogic.co.uk>

G


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support
  2013-08-20  7:13   ` Graeme Gregory
@ 2013-08-20  8:18     ` Samuel Ortiz
  2013-08-20 16:39         ` Grygorii Strashko
  0 siblings, 1 reply; 17+ messages in thread
From: Samuel Ortiz @ 2013-08-20  8:18 UTC (permalink / raw)
  To: Graeme Gregory
  Cc: Grygorii Strashko, Lee Jones, Kevin Hilman, linux-omap,
	Ruslan Bilovol, linux-kernel

On Tue, Aug 20, 2013 at 08:13:54AM +0100, Graeme Gregory wrote:
> On 20/08/13 02:01, Samuel Ortiz wrote:
> >Hi Grygorii,
> >
> >On Thu, Jul 25, 2013 at 04:15:46PM +0300, Grygorii Strashko wrote:
> >>This patch series intorduces twl6030-irq module rework to use Threaded IRQ and
> >>linear irq_domain, and adds support for PMIC TWL6032 IRQs.
> >>
> >>After this patch series TWL6030/6032 IRQs will be supported only for DT boot mode.
> >>
> >>Changes since v1:
> >>- Added new patch "mfd: twl6030-irq: create struct twl6030_irq"
> >>   which introduces "struct twl6030_irq" to store all local variables inside it.
> >>- Patch "mfd: twl6030-irq: migrate to IRQ threaded handler":
> >>   Minor comments applied; fixed twl6030_exit_irq();
> >>   The Parent IRQ has been set for each nested IRQ.
> >>- Patch "mfd: twl6030-irq: convert to use linear irq_domain":
> >>   The irq_find_mapping() is used in twl6030_mmc_card_detect_config()
> >>   to get virtual IRQ number.
> >This looks good to me. Kevin, Graeme, any further comments/ACKs ?
> >
> >Cheers,
> >Samuel.
> >
> Yes, it looked good to me as well.
> 
> Acked-by: Graeme Gregory <gg@slimlogic.co.uk>
Thanks. All 5 patches applied to mfd-next.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support
  2013-08-20  8:18     ` Samuel Ortiz
@ 2013-08-20 16:39         ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-08-20 16:39 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Graeme Gregory, Lee Jones, Kevin Hilman, linux-omap,
	Ruslan Bilovol, linux-kernel

On 08/20/2013 11:18 AM, Samuel Ortiz wrote:
> On Tue, Aug 20, 2013 at 08:13:54AM +0100, Graeme Gregory wrote:
>> On 20/08/13 02:01, Samuel Ortiz wrote:
>>> Hi Grygorii,
>>>
>>> On Thu, Jul 25, 2013 at 04:15:46PM +0300, Grygorii Strashko wrote:
>>>> This patch series intorduces twl6030-irq module rework to use Threaded IRQ and
>>>> linear irq_domain, and adds support for PMIC TWL6032 IRQs.
>>>>
>>>> After this patch series TWL6030/6032 IRQs will be supported only for DT boot mode.
>>>>
>>>> Changes since v1:
>>>> - Added new patch "mfd: twl6030-irq: create struct twl6030_irq"
>>>>    which introduces "struct twl6030_irq" to store all local variables inside it.
>>>> - Patch "mfd: twl6030-irq: migrate to IRQ threaded handler":
>>>>    Minor comments applied; fixed twl6030_exit_irq();
>>>>    The Parent IRQ has been set for each nested IRQ.
>>>> - Patch "mfd: twl6030-irq: convert to use linear irq_domain":
>>>>    The irq_find_mapping() is used in twl6030_mmc_card_detect_config()
>>>>    to get virtual IRQ number.
>>> This looks good to me. Kevin, Graeme, any further comments/ACKs ?
>>>
>>> Cheers,
>>> Samuel.
>>>
>> Yes, it looked good to me as well.
>>
>> Acked-by: Graeme Gregory <gg@slimlogic.co.uk>
> Thanks. All 5 patches applied to mfd-next.
>
> Cheers,
> Samuel.
>

Thanks.

Regards,
-grygorii



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support
@ 2013-08-20 16:39         ` Grygorii Strashko
  0 siblings, 0 replies; 17+ messages in thread
From: Grygorii Strashko @ 2013-08-20 16:39 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Graeme Gregory, Lee Jones, Kevin Hilman, linux-omap,
	Ruslan Bilovol, linux-kernel

On 08/20/2013 11:18 AM, Samuel Ortiz wrote:
> On Tue, Aug 20, 2013 at 08:13:54AM +0100, Graeme Gregory wrote:
>> On 20/08/13 02:01, Samuel Ortiz wrote:
>>> Hi Grygorii,
>>>
>>> On Thu, Jul 25, 2013 at 04:15:46PM +0300, Grygorii Strashko wrote:
>>>> This patch series intorduces twl6030-irq module rework to use Threaded IRQ and
>>>> linear irq_domain, and adds support for PMIC TWL6032 IRQs.
>>>>
>>>> After this patch series TWL6030/6032 IRQs will be supported only for DT boot mode.
>>>>
>>>> Changes since v1:
>>>> - Added new patch "mfd: twl6030-irq: create struct twl6030_irq"
>>>>    which introduces "struct twl6030_irq" to store all local variables inside it.
>>>> - Patch "mfd: twl6030-irq: migrate to IRQ threaded handler":
>>>>    Minor comments applied; fixed twl6030_exit_irq();
>>>>    The Parent IRQ has been set for each nested IRQ.
>>>> - Patch "mfd: twl6030-irq: convert to use linear irq_domain":
>>>>    The irq_find_mapping() is used in twl6030_mmc_card_detect_config()
>>>>    to get virtual IRQ number.
>>> This looks good to me. Kevin, Graeme, any further comments/ACKs ?
>>>
>>> Cheers,
>>> Samuel.
>>>
>> Yes, it looked good to me as well.
>>
>> Acked-by: Graeme Gregory <gg@slimlogic.co.uk>
> Thanks. All 5 patches applied to mfd-next.
>
> Cheers,
> Samuel.
>

Thanks.

Regards,
-grygorii

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2013-08-20 16:42 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-25 13:15 [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support Grygorii Strashko
2013-07-25 13:15 ` Grygorii Strashko
2013-07-25 13:15 ` [PATCH v2 1/5] mfd: twl6030-irq: migrate to IRQ threaded handler Grygorii Strashko
2013-07-25 13:15   ` Grygorii Strashko
2013-07-25 13:15 ` [PATCH v2 2/5] mfd: twl6030-irq: add error check when IRQs are masked initially Grygorii Strashko
2013-07-25 13:15   ` Grygorii Strashko
2013-07-25 13:15 ` [PATCH v2 3/5] mfd: twl6030-irq: convert to use linear irq_domain Grygorii Strashko
2013-07-25 13:15   ` Grygorii Strashko
2013-07-25 13:15 ` [PATCH v2 4/5] mfd: twl6030-irq: create struct twl6030_irq Grygorii Strashko
2013-07-25 13:15   ` Grygorii Strashko
2013-07-25 13:15 ` [PATCH v2 5/5] mfd: twl6030-irq: Add interrupt mapping table for the twl6032 Grygorii Strashko
2013-07-25 13:15   ` Grygorii Strashko
2013-08-20  1:01 ` [PATCH v2 0/5] mfd: twl6030-irq: rework and add twl6032 support Samuel Ortiz
2013-08-20  7:13   ` Graeme Gregory
2013-08-20  8:18     ` Samuel Ortiz
2013-08-20 16:39       ` Grygorii Strashko
2013-08-20 16:39         ` Grygorii Strashko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.