summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Bouyack <mbouyack@google.com>2022-03-08 09:53:32 -0800
committerMatthew Bouyack <mbouyack@google.com>2022-03-14 14:56:32 -0700
commit827162d04ceba9eb84f4ceb80680b094dbdb4aa1 (patch)
tree913fc943e740aa76eb8ef5a6c2a0955537a71a34
parentd2077b80f97d352c5f5dfb1ffad953978e8ebe76 (diff)
downloaddrivers-827162d04ceba9eb84f4ceb80680b094dbdb4aa1.tar.gz
Avoid accessing i2c from touch in suspend
It is suspected that a touch interrupt which occurs late in suspend may cause us to access i2c after it has suspended. This change disables the interrupt prior to suspend to avoid this case. Note that even with the interrupt disabled we can still call enable_irq_wake to allow touch events to wake the device. Test: tap-to-wake (check 'dmesg' to confirm device was suspended) Signed-off-by: Matthew Bouyack <mbouyack@google.com> Bug: 217742260 Change-Id: I6d726a0c584bf82a03560d95303b8b5ad6fe6179
-rw-r--r--input/touchscreen/nt38350/nt38350.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/input/touchscreen/nt38350/nt38350.c b/input/touchscreen/nt38350/nt38350.c
index f91e862..eb8ad31 100644
--- a/input/touchscreen/nt38350/nt38350.c
+++ b/input/touchscreen/nt38350/nt38350.c
@@ -1889,6 +1889,16 @@ static int32_t nvt_ts_resume(struct device *dev)
static int nvt_ts_wake_enable(struct device *dev) {
unsigned long flags;
struct nvt_ts_touch_stats local;
+ int irq = ts->client->irq;
+
+ NVT_LOG("enabling wake on irq %d\n", irq);
+ enable_irq_wake(irq);
+
+ // This avoids a race condition where an irq mid-suspend
+ // causes us to read from i2c while it is unavailable
+ // Note that disable_irq will block until the IRQ handler is
+ // not running so after this point we are safe to suspend i2c
+ nvt_irq_enable(false);
spin_lock_irqsave(&ts->stats_lock, flags);
local = ts->stats;
@@ -1903,14 +1913,17 @@ static int nvt_ts_wake_enable(struct device *dev) {
del_timer(&ts->stats_timer);
}
- NVT_LOG("enabling wake irq %d\n", ts->client->irq);
- enable_irq_wake(ts->client->irq);
return 0;
}
static int nvt_ts_wake_disable(struct device *dev) {
- NVT_LOG("disabling wake irq %d\n", ts->client->irq);
- disable_irq_wake(ts->client->irq);
+ int irq = ts->client->irq;
+
+ nvt_irq_enable(true);
+
+ NVT_LOG("disabling wake on irq %d\n", irq);
+ disable_irq_wake(irq);
+
return 0;
}
@@ -2008,7 +2021,6 @@ static void nvt_ts_late_resume(struct early_suspend *h)
}
#endif
-
static SIMPLE_DEV_PM_OPS(nvt_ts_pm_ops, nvt_ts_wake_enable, nvt_ts_wake_disable);
static const struct i2c_device_id nvt_ts_id[] = {