[PATCH] Input: wm831x-ts - drain pen-down work at teardown

From: Fan Wu

Date: Tue Jul 21 2026 - 22:47:04 EST


The pen-down and data IRQ handlers queue pd_data_work to switch between the
two IRQs. The worker obtains wm831x_ts with container_of() and calls
enable_irq(). free_irq() synchronizes an IRQ handler, but does not drain a
work item already queued by that handler.

wm831x_ts_remove() can therefore free the IRQ actions while pd_data_work is
pending or running. The work may then dereference wm831x_ts after devres
frees it, or enable an IRQ after its action has been freed.

Disable both IRQs before cancelling the work, so neither handler can queue
another instance while cancel_work_sync() drains it. Free the IRQ actions
only after the work has stopped. Apply the same sequence to err_pd_irq:
both IRQ actions exist there when input_register_device() fails.

This issue was found by an in-house static analysis tool and confirmed by
manual code review.

Fixes: f5346668150c ("Input: wm831x-ts - fix races with IRQ management")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@xxxxxxxxxx>
---
drivers/input/touchscreen/wm831x-ts.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index 98f8ec408cad..705772025648 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -366,6 +366,10 @@ static int wm831x_ts_probe(struct platform_device *pdev)
return 0;

err_pd_irq:
+ disable_irq(wm831x_ts->pd_irq);
+ disable_irq(wm831x_ts->data_irq);
+ cancel_work_sync(&wm831x_ts->pd_data_work);
+
free_irq(wm831x_ts->pd_irq, wm831x_ts);
err_data_irq:
free_irq(wm831x_ts->data_irq, wm831x_ts);
@@ -378,6 +382,10 @@ static void wm831x_ts_remove(struct platform_device *pdev)
{
struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev);

+ disable_irq(wm831x_ts->pd_irq);
+ disable_irq(wm831x_ts->data_irq);
+ cancel_work_sync(&wm831x_ts->pd_data_work);
+
free_irq(wm831x_ts->pd_irq, wm831x_ts);
free_irq(wm831x_ts->data_irq, wm831x_ts);
}
--
2.34.1