summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/ads7846.c
diff options
context:
space:
mode:
authorDavid Jander <david@protonic.nl>2020-11-11 11:00:59 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2020-11-17 16:28:12 -0800
commite52cd628a03f72a547dbf90ccb703ee64800504a (patch)
treebc159cd504091b3c0fb396a528467faddd0d9a5e /drivers/input/touchscreen/ads7846.c
parentcd536aa5b438351ea170d5e5f0cd75650eaab005 (diff)
Input: ads7846 - fix race that causes missing releases
If touchscreen is released while busy reading HWMON device, the release can be missed. The IRQ thread is not started because no touch is active and BTN_TOUCH release event is never sent. Fixes: f5a28a7d4858f94a ("Input: ads7846 - avoid pen up/down when reading hwmon") Co-developed-by: Oleksij Rempel <o.rempel@pengutronix.de> Signed-off-by: David Jander <david@protonic.nl> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Link: https://lore.kernel.org/r/20201027105416.18773-1-o.rempel@pengutronix.de Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/touchscreen/ads7846.c')
-rw-r--r--drivers/input/touchscreen/ads7846.c44
1 files changed, 26 insertions, 18 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index ee74da2ad7b8..1e3fc62d0ea8 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -199,6 +199,26 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
+static int get_pendown_state(struct ads7846 *ts)
+{
+ if (ts->get_pendown_state)
+ return ts->get_pendown_state();
+
+ return !gpio_get_value(ts->gpio_pendown);
+}
+
+static void ads7846_report_pen_up(struct ads7846 *ts)
+{
+ struct input_dev *input = ts->input;
+
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
+
+ ts->pendown = false;
+ dev_vdbg(&ts->spi->dev, "UP\n");
+}
+
/* Must be called with ts->lock held */
static void ads7846_stop(struct ads7846 *ts)
{
@@ -215,6 +235,10 @@ static void ads7846_stop(struct ads7846 *ts)
static void ads7846_restart(struct ads7846 *ts)
{
if (!ts->disabled && !ts->suspended) {
+ /* Check if pen was released since last stop */
+ if (ts->pendown && !get_pendown_state(ts))
+ ads7846_report_pen_up(ts);
+
/* Tell IRQ thread that it may poll the device. */
ts->stopped = false;
mb();
@@ -606,14 +630,6 @@ static const struct attribute_group ads784x_attr_group = {
/*--------------------------------------------------------------------------*/
-static int get_pendown_state(struct ads7846 *ts)
-{
- if (ts->get_pendown_state)
- return ts->get_pendown_state();
-
- return !gpio_get_value(ts->gpio_pendown);
-}
-
static void null_wait_for_sync(void)
{
}
@@ -868,16 +884,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
msecs_to_jiffies(TS_POLL_PERIOD));
}
- if (ts->pendown && !ts->stopped) {
- struct input_dev *input = ts->input;
-
- input_report_key(input, BTN_TOUCH, 0);
- input_report_abs(input, ABS_PRESSURE, 0);
- input_sync(input);
-
- ts->pendown = false;
- dev_vdbg(&ts->spi->dev, "UP\n");
- }
+ if (ts->pendown && !ts->stopped)
+ ads7846_report_pen_up(ts);
return IRQ_HANDLED;
}