linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open
@ 2011-03-14 22:45 Mark Brown
  2011-03-14 22:45 ` [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management Mark Brown
  2011-03-16  6:31 ` [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open Dmitry Torokhov
  0 siblings, 2 replies; 6+ messages in thread
From: Mark Brown @ 2011-03-14 22:45 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, patches, Mark Brown

Explicitly set all the enable bits when opening the device just in case
something left the device in an unexpected state.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/input/touchscreen/wm831x-ts.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index 3db0c29..6ae054f 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -167,7 +167,9 @@ static int wm831x_ts_input_open(struct input_dev *idev)
 	struct wm831x *wm831x = wm831x_ts->wm831x;
 
 	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
-			WM831X_TCH_ENA, WM831X_TCH_ENA);
+			WM831X_TCH_ENA | WM831X_TCH_CVT_ENA |
+			WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
+			WM831X_TCH_Z_ENA, WM831X_TCH_ENA);
 
 	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
 			WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA);
-- 
1.7.4.1


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

* [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management
  2011-03-14 22:45 [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open Mark Brown
@ 2011-03-14 22:45 ` Mark Brown
  2011-03-18 11:20   ` Mark Brown
  2011-03-16  6:31 ` [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open Dmitry Torokhov
  1 sibling, 1 reply; 6+ messages in thread
From: Mark Brown @ 2011-03-14 22:45 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, patches, Mark Brown

If the WM831x pen down and data IRQs run in parallel it is possible for the
data and pen down IRQs to deadlock themselves as one is part way through
disabling its operation while the other is part way through enabling. Fix
this by always disabling the pen down interrupt while data is active and
vice versa.

This also fixes an issue when using the built in IRQs due to enable_irq()
not being valid from interrupt context on an interrupt controller with bus
operations like the built in IRQ controller - this issue may also have
affected other interrupt controllers.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---

This revision reworks the close() implementation, hopefully more
robustly, which should address the main thrust of your comments
previously.  As I said in my previous e-mail the restrictions on
enable_irq() seem reasonable to me, the thing that's nasty here is that
we need to enable and disable the IRQs at all.

 drivers/input/touchscreen/wm831x-ts.c |   60 ++++++++++++++++++++++++++++++--
 1 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index 6ae054f..3f825cb 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -68,8 +68,29 @@ struct wm831x_ts {
 	unsigned int pd_irq;
 	bool pressure;
 	bool pen_down;
+	struct work_struct pd_data_work;
+	struct work_struct data_pd_work;
 };
 
+static void wm831x_pd_data(struct work_struct *work)
+{
+	struct wm831x_ts *wm831x_ts =
+		container_of(work, struct wm831x_ts, pd_data_work);
+
+	disable_irq(wm831x_ts->pd_irq);
+	enable_irq(wm831x_ts->data_irq);
+	dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n");
+}
+
+static void wm831x_data_pd(struct work_struct *work)
+{
+	struct wm831x_ts *wm831x_ts =
+		container_of(work, struct wm831x_ts, data_pd_work);
+
+	enable_irq(wm831x_ts->pd_irq);
+	dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n");
+}
+
 static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
 {
 	struct wm831x_ts *wm831x_ts = irq_data;
@@ -110,7 +131,10 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
 	}
 
 	if (!wm831x_ts->pen_down) {
+		/* Switch from data to pen down */
+		dev_dbg(wm831x->dev, "IRQ DATA->PD\n");
 		disable_irq_nosync(wm831x_ts->data_irq);
+		schedule_work(&wm831x_ts->data_pd_work);
 
 		/* Don't need data any more */
 		wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
@@ -156,7 +180,10 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data)
 			WM831X_TCHPD_EINT, WM831X_TCHPD_EINT);
 
 	wm831x_ts->pen_down = true;
-	enable_irq(wm831x_ts->data_irq);
+
+	/* Switch from pen down to data */
+	dev_dbg(wm831x->dev, "IRQ PD->DATA\n");
+	schedule_work(&wm831x_ts->pd_data_work);
 
 	return IRQ_HANDLED;
 }
@@ -182,13 +209,36 @@ static void wm831x_ts_input_close(struct input_dev *idev)
 	struct wm831x_ts *wm831x_ts = input_get_drvdata(idev);
 	struct wm831x *wm831x = wm831x_ts->wm831x;
 
+	/* Shut the controller down, disabling all other functionality */
+	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+			WM831X_TCH_ENA, 0);
+
+	/* Make sure any pending IRQs are done, the above will prevent
+	 * new ones firing.
+	 */
+	synchronize_irq(wm831x_ts->data_irq);
+	synchronize_irq(wm831x_ts->pd_irq);
+
+	/* Make sure the IRQ completion work is quiesced */
+	flush_work_sync(&wm831x_ts->data_pd_work);
+	flush_work_sync(&wm831x_ts->pd_data_work);
+
+	/* If we ended up with the pen down then make sure we revert back
+	 * to pen detection state for the next time we start up.
+	 */
+	if (wm831x_ts->pen_down) {
+		disable_irq(wm831x_ts->data_irq);
+		enable_irq(wm831x_ts->pd_irq);
+		wm831x_ts->pen_down = false;
+	}
+
+	/* Be nice to the next user and make sure everything is
+	 * flagged as disabled.
+	 */
 	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
 			WM831X_TCH_ENA | WM831X_TCH_CVT_ENA |
 			WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
 			WM831X_TCH_Z_ENA, 0);
-
-	if (wm831x_ts->pen_down)
-		disable_irq(wm831x_ts->data_irq);
 }
 
 static __devinit int wm831x_ts_probe(struct platform_device *pdev)
@@ -212,6 +262,8 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
 
 	wm831x_ts->wm831x = wm831x;
 	wm831x_ts->input_dev = input_dev;
+	INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data);
+	INIT_WORK(&wm831x_ts->data_pd_work, wm831x_data_pd);
 
 	/*
 	 * If we have a direct IRQ use it, otherwise use the interrupt
-- 
1.7.4.1


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

* Re: [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open
  2011-03-14 22:45 [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open Mark Brown
  2011-03-14 22:45 ` [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management Mark Brown
@ 2011-03-16  6:31 ` Dmitry Torokhov
  1 sibling, 0 replies; 6+ messages in thread
From: Dmitry Torokhov @ 2011-03-16  6:31 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-input, patches

On Mon, Mar 14, 2011 at 10:45:00PM +0000, Mark Brown wrote:
> Explicitly set all the enable bits when opening the device just in case
> something left the device in an unexpected state.
> 

Applied, thank you Mark.

-- 
Dmitry

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

* Re: [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management
  2011-03-14 22:45 ` [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management Mark Brown
@ 2011-03-18 11:20   ` Mark Brown
  2011-03-25  7:30     ` Dmitry Torokhov
  0 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2011-03-18 11:20 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, patches

On Mon, Mar 14, 2011 at 10:45:01PM +0000, Mark Brown wrote:

> This revision reworks the close() implementation, hopefully more
> robustly, which should address the main thrust of your comments
> previously.  As I said in my previous e-mail the restrictions on
> enable_irq() seem reasonable to me, the thing that's nasty here is that
> we need to enable and disable the IRQs at all.

It'd be good to get something for this into 2.6.39.  At the very least
this version of the patch avoids issues while the device is open and
keeps any issues in close() which is an improvement.  If this approach
isn't going to be OK please let me know so I can look into alternatives.

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

* Re: [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management
  2011-03-18 11:20   ` Mark Brown
@ 2011-03-25  7:30     ` Dmitry Torokhov
  2011-03-25 10:49       ` Mark Brown
  0 siblings, 1 reply; 6+ messages in thread
From: Dmitry Torokhov @ 2011-03-25  7:30 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-input, patches

On Fri, Mar 18, 2011 at 11:20:44AM +0000, Mark Brown wrote:
> On Mon, Mar 14, 2011 at 10:45:01PM +0000, Mark Brown wrote:
> 
> > This revision reworks the close() implementation, hopefully more
> > robustly, which should address the main thrust of your comments
> > previously.  As I said in my previous e-mail the restrictions on
> > enable_irq() seem reasonable to me, the thing that's nasty here is that
> > we need to enable and disable the IRQs at all.
> 
> It'd be good to get something for this into 2.6.39.  At the very least
> this version of the patch avoids issues while the device is open and
> keeps any issues in close() which is an improvement.  If this approach
> isn't going to be OK please let me know so I can look into alternatives.

Mark,

Sorry for the delay.

I am just not comfortable with a touchcsreen requiring essentially 2
threads to operate (2 IRQ threads, 2 works).  I was thinking about
converting to a thread with a state machine and 2 non-threaded IRQs
disabling themselves and waking the thread up. Do you think something
like that would work?

Thanks.

-- 
Dmitry

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

* Re: [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management
  2011-03-25  7:30     ` Dmitry Torokhov
@ 2011-03-25 10:49       ` Mark Brown
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2011-03-25 10:49 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, patches

On Fri, Mar 25, 2011 at 12:30:32AM -0700, Dmitry Torokhov wrote:

> I am just not comfortable with a touchcsreen requiring essentially 2
> threads to operate (2 IRQ threads, 2 works).  I was thinking about
> converting to a thread with a state machine and 2 non-threaded IRQs
> disabling themselves and waking the thread up. Do you think something
> like that would work?

You can't use non-threaded IRQs as the chip is accessed over I2C or SPI
so when using the built in interrupts you're in thread context before
you've decoded the IRQ.  Given the need to ack the IRQ to stop it trying
to do something it doesn't seem worth trying to move the chip
interaction out of the IRQ handlers there - it'd just be performance
pain and you'd still need to worry about which IRQs are enabled at any
given moment since you'd need to disable the IRQs if you wanted to defer
handling them.

Combining the two work items to do the IRQ enable handovers should be
doable, though.

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

end of thread, other threads:[~2011-03-25 10:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-14 22:45 [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open Mark Brown
2011-03-14 22:45 ` [PATCH 2/2] Input: wm831x-ts - Fix races with IRQ management Mark Brown
2011-03-18 11:20   ` Mark Brown
2011-03-25  7:30     ` Dmitry Torokhov
2011-03-25 10:49       ` Mark Brown
2011-03-16  6:31 ` [PATCH 1/2] Input: wm831x-ts - Ensure the controller is in a known state on open Dmitry Torokhov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).