* [PATCH 1/2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload
@ 2026-09-03 19:29 Zhian Liang
2026-09-03 19:29 ` [PATCH 2/2] Input: tca8418_keypad - fix race condition in interrupt handler Zhian Liang
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Zhian Liang @ 2026-09-03 19:29 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, stable, Zhian Liang
tca8418_configure() enables TCA8418 interrupts by writing the CFG
register. If input_register_device() fails afterwards, probe returns
an error and devres releases the IRQ handler, but the hardware is
left with interrupts still enabled.
Fix it by registering a devm action that clears the CFG register
when the device is released, disabling
all interrupts on both probe failure and driver unbind.
Signed-off-by: Zhian Liang <liangzhan5dev@gmail.com>
---
drivers/input/keyboard/tca8418_keypad.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 36d4a7c38bb1..9f0aace6bd21 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -270,6 +270,20 @@ static int tca8418_configure(struct tca8418_keypad *keypad_data,
return error;
}
+static void tca8418_disable_hw(void *data)
+{
+ struct tca8418_keypad *keypad_data = data;
+ int error;
+
+ error = tca84818_write_byte(keypad_data, REG_CFG, 0);
+ if (error)
+ dev_warn(&keypad_data->client->dev, "unable to disable interrupts: %d\n", error);
+
+ error = tca8418_write_byte(keypad_data, REG_INT_STAT, 0xff);
+ if (error)
+ dev_warn(&keypad_data->client->dev, "unable to clear interrupt status: %d\n", error);
+}
+
static int tca8418_keypad_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -356,6 +370,10 @@ static int tca8418_keypad_probe(struct i2c_client *client)
if (error < 0)
return error;
+ error = devm_add_action_or_reset(dev, tca8418_diable_hw, keypad_data);
+ if (error)
+ return error;
+
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device, error: %d\n",
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 2/2] Input: tca8418_keypad - fix race condition in interrupt handler
2026-09-03 19:29 [PATCH 1/2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload Zhian Liang
@ 2026-09-03 19:29 ` Zhian Liang
2026-09-03 21:06 ` [PATCH v2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload Zhian Liang
2026-09-05 9:37 ` [PATCH 1/2] " Dmitry Torokhov
2 siblings, 0 replies; 5+ messages in thread
From: Zhian Liang @ 2026-09-03 19:29 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, stable, Zhian Liang
There is a race condition in tca8418_irq_handler() where a new key event
can be lost if it arrives after the FIFO is drained but before the
interrupt status register is cleared.
Fix this by re-reading INT_STAT after draining the FIFO and repeating
the process if K_INT is still asserted. This ensures the FIFO is truly
empty before clearing interrupts.
The FIFO depth is 10 events, so a loop limit of 16 provides sufficient
margin while preventing infinite loops in case of hardware misbehavior.
Signed-off-by: Zhian Liang <liangzhan5dev@gmail.com>
---
drivers/input/keyboard/tca8418_keypad.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 9f0aace6bd21..0952370c0636 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -212,6 +212,7 @@ static irqreturn_t tca8418_irq_handler(int irq, void *dev_id)
struct tca8418_keypad *keypad_data = dev_id;
u8 reg;
int error;
+ int max_loops = 16;
error = tca8418_read_byte(keypad_data, REG_INT_STAT, ®);
if (error) {
@@ -225,9 +226,19 @@ static irqreturn_t tca8418_irq_handler(int irq, void *dev_id)
if (reg & INT_STAT_OVR_FLOW_INT)
dev_warn(&keypad_data->client->dev, "overflow occurred\n");
+ do {
+ if (reg & INT_STAT_K_INT)
+ tca8418_read_keypad(keypad_data);
+
+ /* Re-read interrupt status to check for new events */
+ error = tca8418_read_byte(keypad_data, REG_INT_STAT, ®);
+ if (error) {
+ dev_err(&keypad_data->client->dev,
+ "unable to re-read REG_INT_STAT\n");
+ return IRQ_HANDLED;
+ }
- if (reg & INT_STAT_K_INT)
- tca8418_read_keypad(keypad_data);
+ } while ((reg & INT_STAT_K_INT) && --max_loops);
/* Clear all interrupts, even IRQs we didn't check (GPI, CAD, LCK) */
reg = 0xff;
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload
2026-09-03 19:29 [PATCH 1/2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload Zhian Liang
2026-09-03 19:29 ` [PATCH 2/2] Input: tca8418_keypad - fix race condition in interrupt handler Zhian Liang
@ 2026-09-03 21:06 ` Zhian Liang
2026-09-05 9:37 ` [PATCH 1/2] " Dmitry Torokhov
2 siblings, 0 replies; 5+ messages in thread
From: Zhian Liang @ 2026-09-03 21:06 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, stable, Zhian Liang
tca8418_configure() enables TCA8418 interrupts by writing the CFG
register. If input_register_device() fails afterwards, probe returns
an error and devres releases the IRQ handler, but the hardware is
left with interrupts still enabled.
Fix it by registering a devm action that clears the CFG register
when the device is released, disabling
all interrupts on both probe failure and driver unbind.
Signed-off-by: Zhian Liang <liangzhan5dev@gmail.com>
---
Changes in v2:
- Fixed typo: tca84818_write_byte -> tca8418_write_byte
- Fixed typo: tca8418_diable_hw -> tca8418_disable_hw
---
drivers/input/keyboard/tca8418_keypad.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 36d4a7c38bb1..413b404a08ba 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -270,6 +270,20 @@ static int tca8418_configure(struct tca8418_keypad *keypad_data,
return error;
}
+static void tca8418_disable_hw(void *data)
+{
+ struct tca8418_keypad *keypad_data = data;
+ int error;
+
+ error = tca8418_write_byte(keypad_data, REG_CFG, 0);
+ if (error)
+ dev_warn(&keypad_data->client->dev, "unable to disable interrupts: %d\n", error);
+
+ error = tca8418_write_byte(keypad_data, REG_INT_STAT, 0xff);
+ if (error)
+ dev_warn(&keypad_data->client->dev, "unable to clear interrupt status: %d\n", error);
+}
+
static int tca8418_keypad_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -356,6 +370,10 @@ static int tca8418_keypad_probe(struct i2c_client *client)
if (error < 0)
return error;
+ error = devm_add_action_or_reset(dev, tca8418_disable_hw, keypad_data);
+ if (error)
+ return error;
+
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device, error: %d\n",
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 1/2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload
2026-09-03 19:29 [PATCH 1/2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload Zhian Liang
2026-09-03 19:29 ` [PATCH 2/2] Input: tca8418_keypad - fix race condition in interrupt handler Zhian Liang
2026-09-03 21:06 ` [PATCH v2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload Zhian Liang
@ 2026-09-05 9:37 ` Dmitry Torokhov
2026-09-06 6:54 ` Zhian Liang
2 siblings, 1 reply; 5+ messages in thread
From: Dmitry Torokhov @ 2026-09-05 9:37 UTC (permalink / raw)
To: Zhian Liang; +Cc: linux-input, linux-kernel, stable
Hi Zhian,
On Fri, Sep 04, 2026 at 03:29:41AM +0800, Zhian Liang wrote:
> tca8418_configure() enables TCA8418 interrupts by writing the CFG
> register. If input_register_device() fails afterwards, probe returns
> an error and devres releases the IRQ handler, but the hardware is
> left with interrupts still enabled.
What kind of issues does it cause?
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload
2026-09-05 9:37 ` [PATCH 1/2] " Dmitry Torokhov
@ 2026-09-06 6:54 ` Zhian Liang
0 siblings, 0 replies; 5+ messages in thread
From: Zhian Liang @ 2026-09-06 6:54 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, stable
Hi Dmitry,
The INT output is "active-low interrupt output, open drain structure" (Datasheet §5, pin
table). With the handler gone but hardware still enabled, a key press pulls INT low with nobody to service it.
And the driver requests the IRQ with IRQF_SHARED,
error = devm_request_threaded_irq(dev, client->irq,
NULL, tca8418_irq_handler,
IRQF_SHARED | IRQF_ONESHOT,
client->name, keypad_data);
if (error) {
dev_err(dev, "Unable to claim irq %d; error %d\n",
client->irq, error);
return error;
}
this stuck interrupt is seen by every other device sharing the line, and may trigger "nobody cared" IRQ storms or, in the worst case, cause the kernel to disable the shared IRQ line entirely, breaking unrelated devices.
The same leak happens on driver unbind (I think it's a rare case though).
--
Zhian
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-06 6:54 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-03 19:29 [PATCH 1/2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload Zhian Liang
2026-09-03 19:29 ` [PATCH 2/2] Input: tca8418_keypad - fix race condition in interrupt handler Zhian Liang
2026-09-03 21:06 ` [PATCH v2] Input: tca8418_keypad - Add devm cleanup to disable interrupts on unload Zhian Liang
2026-09-05 9:37 ` [PATCH 1/2] " Dmitry Torokhov
2026-09-06 6:54 ` Zhian Liang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®