diff mbox series

[v4,2/2] input: touch: eeti: read hardware state once after wakeup

Message ID 20190429152411.12835-2-daniel@zonque.org (mailing list archive)
State Under Review
Headers show
Series [v4,1/2] input: touch: eeti: move ISR code to own function | expand

Commit Message

Daniel Mack April 29, 2019, 3:24 p.m. UTC
For systems in which the touch IRQ is acting as wakeup source, and that do
not support level-driven interrupts, the interrupt controller might not
latch the GPIO IRQ during sleep. In such cases, the interrupt will never
occur again after resume, hence the touch screen appears dead.

To fix this, check for the assertion of the attn gpio, and call into
eeti_ts_read() once in the resume path to read the hardware status and
to arm the IRQ again.

Introduce a mutex to guard eeti_ts_read() against parallel invocations
from different contexts.

Signed-off-by: Daniel Mack <daniel@zonque.org>
Reported-by: Sven Neumann <Sven.Neumann@teufel.de>
---
 drivers/input/touchscreen/eeti_ts.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
diff mbox series

Patch

diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 3e13cc12aaaf..48cecdd484a5 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -41,6 +41,7 @@  struct eeti_ts {
 	struct input_dev *input;
 	struct gpio_desc *attn_gpio;
 	struct touchscreen_properties props;
+	struct mutex mutex;
 	bool running;
 };
 
@@ -80,6 +81,8 @@  static void eeti_ts_read(struct eeti_ts *eeti)
 	int len, error;
 	char buf[6];
 
+	mutex_lock(&eeti->mutex);
+
 	do {
 		len = i2c_master_recv(eeti->client, buf, sizeof(buf));
 		if (len != sizeof(buf)) {
@@ -95,6 +98,8 @@  static void eeti_ts_read(struct eeti_ts *eeti)
 			eeti_ts_report_event(eeti, buf);
 	} while (eeti->running &&
 		 eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio));
+
+	mutex_unlock(&eeti->mutex);
 }
 
 static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
@@ -111,6 +116,9 @@  static void eeti_ts_start(struct eeti_ts *eeti)
 	eeti->running = true;
 	wmb();
 	enable_irq(eeti->client->irq);
+
+	if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio))
+		eeti_ts_read(eeti);
 }
 
 static void eeti_ts_stop(struct eeti_ts *eeti)
@@ -157,6 +165,8 @@  static int eeti_ts_probe(struct i2c_client *client,
 		return -ENOMEM;
 	}
 
+	mutex_init(&eeti->mutex);
+
 	input = devm_input_allocate_device(dev);
 	if (!input) {
 		dev_err(dev, "Failed to allocate input device.\n");