From patchwork Tue Mar 1 16:54:19 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 599901 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p21Gs3Z2012771 for ; Tue, 1 Mar 2011 16:54:04 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756343Ab1CAQyC (ORCPT ); Tue, 1 Mar 2011 11:54:02 -0500 Received: from opensource.wolfsonmicro.com ([80.75.67.52]:54429 "EHLO opensource2.wolfsonmicro.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754051Ab1CAQyB (ORCPT ); Tue, 1 Mar 2011 11:54:01 -0500 Received: from finisterre.wolfsonmicro.main (unknown [87.246.78.26]) by opensource2.wolfsonmicro.com (Postfix) with ESMTPSA id 6808B1100DF; Tue, 1 Mar 2011 16:54:00 +0000 (GMT) Received: from broonie by finisterre.wolfsonmicro.main with local (Exim 4.72) (envelope-from ) id 1PuSq5-0003GY-TK; Tue, 01 Mar 2011 16:54:21 +0000 From: Mark Brown To: Dmitry Torokhov Cc: linux-input@vger.kernel.org, patches@opensource.wolfsonmicro.com, Mark Brown Subject: [PATCH] Input: wm831x-ts - Fix races with IRQ management Date: Tue, 1 Mar 2011 16:54:19 +0000 Message-Id: <1298998459-12526-1-git-send-email-broonie@opensource.wolfsonmicro.com> X-Mailer: git-send-email 1.7.2.3 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 01 Mar 2011 16:54:04 +0000 (UTC) diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 1022f71..3c397c8 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; } @@ -185,8 +212,13 @@ static void wm831x_ts_input_close(struct input_dev *idev) WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); - if (wm831x_ts->pen_down) + if (wm831x_ts->pen_down) { + flush_work_sync(&wm831x_ts->data_pd_work); disable_irq(wm831x_ts->data_irq); + enable_irq(wm831x_ts->pd_irq); + } else { + flush_work_sync(&wm831x_ts->pd_data_work); + } } static __devinit int wm831x_ts_probe(struct platform_device *pdev) @@ -210,6 +242,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