diff mbox

[3/4] input: ti_tsc: Enable shared IRQ for TSC and add overrun, underflow checks

Message ID 1376412499-21007-4-git-send-email-zubair.lutfullah@gmail.com
State New, archived
Headers show

Commit Message

Zubair Lutfullah Aug. 13, 2013, 4:48 p.m. UTC
Enable shared IRQ to allow ADC to share IRQ line from
parent MFD core. Only FIFO0 IRQs are for TSC and handled
on the TSC side.

Patch also adds overrun and underflow irq handlers.

Russ Dill (TI) worked on overrun and underflow handlers.
Rachna Patil (TI) laid ground work for shared IRQ.

Signed-off-by: Zubair Lutfullah <zubair.lutfullah@gmail.com>
---
 drivers/input/touchscreen/ti_am335x_tsc.c |   37 +++++++++++++++++++++++++----
 include/linux/mfd/ti_am335x_tscadc.h      |    2 ++
 2 files changed, 34 insertions(+), 5 deletions(-)

Comments

Lee Jones Aug. 13, 2013, 5:07 p.m. UTC | #1
On Tue, 13 Aug 2013, Zubair Lutfullah wrote:

> Enable shared IRQ to allow ADC to share IRQ line from
> parent MFD core. Only FIFO0 IRQs are for TSC and handled
> on the TSC side.
> 
> Patch also adds overrun and underflow irq handlers.
> 
> Russ Dill (TI) worked on overrun and underflow handlers.
> Rachna Patil (TI) laid ground work for shared IRQ.
> 
> Signed-off-by: Zubair Lutfullah <zubair.lutfullah@gmail.com>
> ---
>  drivers/input/touchscreen/ti_am335x_tsc.c |   37 +++++++++++++++++++++++++----
>  include/linux/mfd/ti_am335x_tscadc.h      |    2 ++
>  2 files changed, 34 insertions(+), 5 deletions(-)

For the MFD part when the remainder of the entries have been placed in
order:

Acked-by: Lee Jones <lee.jones@linaro.org>
Sebastian Andrzej Siewior Aug. 16, 2013, 9:14 a.m. UTC | #2
* Zubair Lutfullah | 2013-08-13 17:48:18 [+0100]:

>Enable shared IRQ to allow ADC to share IRQ line from
>parent MFD core. Only FIFO0 IRQs are for TSC and handled
>on the TSC side.
>
>Patch also adds overrun and underflow irq handlers.
>
>Russ Dill (TI) worked on overrun and underflow handlers.
>Rachna Patil (TI) laid ground work for shared IRQ.
>
>Signed-off-by: Zubair Lutfullah <zubair.lutfullah@gmail.com>
>---
> drivers/input/touchscreen/ti_am335x_tsc.c |   37 +++++++++++++++++++++++++----
> include/linux/mfd/ti_am335x_tscadc.h      |    2 ++
> 2 files changed, 34 insertions(+), 5 deletions(-)
>
>diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
>index 766bc7e..9c114b2 100644
>--- a/drivers/input/touchscreen/ti_am335x_tsc.c
>+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
>@@ -256,14 +256,39 @@ static irqreturn_t titsc_irq(int irq, void *dev)
> {
> 	struct titsc *ts_dev = dev;
> 	struct input_dev *input_dev = ts_dev->input;
>-	unsigned int status, irqclr = 0;
>+	unsigned int status, irqclr = 0, config = 0;
> 	unsigned int x = 0, y = 0;
> 	unsigned int z1, z2, z;
> 	unsigned int fsm;
> 
> 	status = titsc_readl(ts_dev, REG_IRQSTATUS);
>-	if (status & IRQENB_FIFO0THRES) {
>+	/*
>+	 * ADC and touchscreen share the IRQ line.
>+	 * FIFO1 threshold, FIFO1 Overrun and FIFO1 underflow
>+	 * interrupts are used by ADC. Handle FIFO0 IRQs here only
>+	 * and check if any IRQs left in case both fifos interrupt.
>+	 * If any irq left, return none, else return handled.
>+	 */
>+	if ((status & IRQENB_FIFO0OVRRUN) ||
>+			(status & IRQENB_FIFO0UNDRFLW)) {
>+
>+		config = titsc_readl(ts_dev, REG_CTRL);
>+		config &= ~(CNTRLREG_TSCSSENB);
>+		titsc_writel(ts_dev, REG_CTRL, config);
>+
>+		if (status & IRQENB_FIFO0UNDRFLW) {
>+			titsc_writel(ts_dev, REG_IRQSTATUS,
>+				(status | IRQENB_FIFO0UNDRFLW));
>+			irqclr |= IRQENB_FIFO0UNDRFLW;
>+		} else {
>+			titsc_writel(ts_dev, REG_IRQSTATUS,
>+				(status | IRQENB_FIFO0OVRRUN));
>+			irqclr |= IRQENB_FIFO0OVRRUN;
>+		}

You don't do anything on overflow / underflow. Is this due to the fact
once enabled for FIFO1 it also triggers for FIFO0?

>+		titsc_writel(ts_dev, REG_CTRL,
>+			(config | CNTRLREG_TSCSSENB));
>+	} else if (status & IRQENB_FIFO0THRES) {
> 		titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
> 
> 		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
>@@ -317,9 +342,11 @@ static irqreturn_t titsc_irq(int irq, void *dev)
> 	}
> 
> 	if (irqclr) {
>-		titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
>+		titsc_writel(ts_dev, REG_IRQSTATUS, (status | irqclr));

Shouldn't FIFO1UNDRFLW & OVRRUN be handled by the adc driver? Why do you
or the unhandled bits as well here?

> 		am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask);
>-		return IRQ_HANDLED;
>+		status = titsc_readl(ts_dev, REG_IRQSTATUS);
>+		if (status == false)
>+			return IRQ_HANDLED;

And why this? If you something you handled it, if you didn't you return
NONE. Why does it depend on REG_IRQSTATUS?

> 	}
> 	return IRQ_NONE;
> }

Sebastian
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zubair Lutfullah Aug. 16, 2013, 9:31 p.m. UTC | #3
On Fri, Aug 16, 2013 at 11:14:09AM +0200, Sebastian Andrzej Siewior wrote:
> * Zubair Lutfullah | 2013-08-13 17:48:18 [+0100]:
> >+	if ((status & IRQENB_FIFO0OVRRUN) ||
> >+			(status & IRQENB_FIFO0UNDRFLW)) {
> >+
> >+		config = titsc_readl(ts_dev, REG_CTRL);
> >+		config &= ~(CNTRLREG_TSCSSENB);
> >+		titsc_writel(ts_dev, REG_CTRL, config);
> >+
> >+		if (status & IRQENB_FIFO0UNDRFLW) {
> >+			titsc_writel(ts_dev, REG_IRQSTATUS,
> >+				(status | IRQENB_FIFO0UNDRFLW));
> >+			irqclr |= IRQENB_FIFO0UNDRFLW;
> >+		} else {
> >+			titsc_writel(ts_dev, REG_IRQSTATUS,
> >+				(status | IRQENB_FIFO0OVRRUN));
> >+			irqclr |= IRQENB_FIFO0OVRRUN;
> >+		}
> 
> You don't do anything on overflow / underflow. Is this due to the fact
> once enabled for FIFO1 it also triggers for FIFO0?
> 
The TSCADC module doesn't recover from these interrupts.

> >+		titsc_writel(ts_dev, REG_CTRL,
> >+			(config | CNTRLREG_TSCSSENB));

The fix is to re-enable the module after disabling 
and clearing the interrupts.

That is what the handler is doing.
> >+	} else if (status & IRQENB_FIFO0THRES) {
> > 		titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
> > 
> > 		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
> >@@ -317,9 +342,11 @@ static irqreturn_t titsc_irq(int irq, void *dev)
> > 	}
> > 
> > 	if (irqclr) {
> >-		titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
> >+		titsc_writel(ts_dev, REG_IRQSTATUS, (status | irqclr));
> 
> Shouldn't FIFO1UNDRFLW & OVRRUN be handled by the adc driver? Why do you
> or the unhandled bits as well here?
FIFO1 is only used by TSC. ADC doesn't touch it.
> 
> > 		am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask);
> >-		return IRQ_HANDLED;
> >+		status = titsc_readl(ts_dev, REG_IRQSTATUS);
> >+		if (status == false)
> >+			return IRQ_HANDLED;
> 
> And why this? If you something you handled it, if you didn't you return
> NONE. Why does it depend on REG_IRQSTATUS?

These quirks are to handle the situation where both IRQs happen
simultaneously. Which can occur when someone is using the TSC
while continuously sampling using the ADC.

REG_IRQSTATUS has flags for FIFO0 used by ADC as well.

If there are still those IRQs to handle, then IRQ_NONE is returned.
Otherwise, all IRQ flags are clear so IRQ_HANDLED is returned.

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

Patch

diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 766bc7e..9c114b2 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -256,14 +256,39 @@  static irqreturn_t titsc_irq(int irq, void *dev)
 {
 	struct titsc *ts_dev = dev;
 	struct input_dev *input_dev = ts_dev->input;
-	unsigned int status, irqclr = 0;
+	unsigned int status, irqclr = 0, config = 0;
 	unsigned int x = 0, y = 0;
 	unsigned int z1, z2, z;
 	unsigned int fsm;
 
 	status = titsc_readl(ts_dev, REG_IRQSTATUS);
-	if (status & IRQENB_FIFO0THRES) {
+	/*
+	 * ADC and touchscreen share the IRQ line.
+	 * FIFO1 threshold, FIFO1 Overrun and FIFO1 underflow
+	 * interrupts are used by ADC. Handle FIFO0 IRQs here only
+	 * and check if any IRQs left in case both fifos interrupt.
+	 * If any irq left, return none, else return handled.
+	 */
+	if ((status & IRQENB_FIFO0OVRRUN) ||
+			(status & IRQENB_FIFO0UNDRFLW)) {
+
+		config = titsc_readl(ts_dev, REG_CTRL);
+		config &= ~(CNTRLREG_TSCSSENB);
+		titsc_writel(ts_dev, REG_CTRL, config);
+
+		if (status & IRQENB_FIFO0UNDRFLW) {
+			titsc_writel(ts_dev, REG_IRQSTATUS,
+				(status | IRQENB_FIFO0UNDRFLW));
+			irqclr |= IRQENB_FIFO0UNDRFLW;
+		} else {
+			titsc_writel(ts_dev, REG_IRQSTATUS,
+				(status | IRQENB_FIFO0OVRRUN));
+			irqclr |= IRQENB_FIFO0OVRRUN;
+		}
 
+		titsc_writel(ts_dev, REG_CTRL,
+			(config | CNTRLREG_TSCSSENB));
+	} else if (status & IRQENB_FIFO0THRES) {
 		titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
 
 		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
@@ -317,9 +342,11 @@  static irqreturn_t titsc_irq(int irq, void *dev)
 	}
 
 	if (irqclr) {
-		titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+		titsc_writel(ts_dev, REG_IRQSTATUS, (status | irqclr));
 		am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask);
-		return IRQ_HANDLED;
+		status = titsc_readl(ts_dev, REG_IRQSTATUS);
+		if (status == false)
+			return IRQ_HANDLED;
 	}
 	return IRQ_NONE;
 }
@@ -391,7 +418,7 @@  static int titsc_probe(struct platform_device *pdev)
 	}
 
 	err = request_irq(ts_dev->irq, titsc_irq,
-			  0, pdev->dev.driver->name, ts_dev);
+			  IRQF_SHARED, pdev->dev.driver->name, ts_dev);
 	if (err) {
 		dev_err(&pdev->dev, "failed to allocate irq.\n");
 		goto err_free_mem;
diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h
index db1791b..e2db978 100644
--- a/include/linux/mfd/ti_am335x_tscadc.h
+++ b/include/linux/mfd/ti_am335x_tscadc.h
@@ -50,6 +50,8 @@ 
 /* IRQ enable */
 #define IRQENB_HW_PEN		BIT(0)
 #define IRQENB_FIFO0THRES	BIT(2)
+#define IRQENB_FIFO0OVRRUN	BIT(3)
+#define IRQENB_FIFO0UNDRFLW	BIT(4)
 #define IRQENB_FIFO1THRES	BIT(5)
 #define IRQENB_PENUP		BIT(9)