[PATCH 6/6] ASoC: cs42l56: Fix beep input device leak on card re-bind

From: Chancel Liu

Date: Sun Sep 13 2026 - 06:20:11 EST


From: Chancel Liu <chancel.liu@xxxxxxx>

cs42l56 allocates its beep input device with devm_input_allocate_device()
from the ASoC component probe, but the associated devres cleanup is tied
to the underlying I2C device, while cs42l56_free_beep() on the component
remove path only clears the cs42l56->beep pointer.

The input device is only leaked when the sound card is unregistered and
re-registered while the I2C device stays bound. On that path the
component probe runs again and allocates and registers a new input
device every time, leaking the previous one and its sysfs/input node.

Allocate the beep device with input_allocate_device() and pair it with
the component lifecycle: input_free_device() on registration failure and
input_unregister_device() in cs42l56_free_beep().

Signed-off-by: Chancel Liu <chancel.liu@xxxxxxx>
---
sound/soc/codecs/cs42l56.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index 4d9a22a1029c..37df94fbc887 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -1077,7 +1077,7 @@ static void cs42l56_init_beep(struct snd_soc_component *component)
struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
int ret;

- cs42l56->beep = devm_input_allocate_device(component->dev);
+ cs42l56->beep = input_allocate_device();
if (!cs42l56->beep) {
dev_err(component->dev, "Failed to allocate beep device\n");
return;
@@ -1098,8 +1098,10 @@ static void cs42l56_init_beep(struct snd_soc_component *component)

ret = input_register_device(cs42l56->beep);
if (ret != 0) {
+ input_free_device(cs42l56->beep);
cs42l56->beep = NULL;
dev_err(component->dev, "Failed to register beep device\n");
+ return;
}

ret = device_create_file(component->dev, &dev_attr_beep);
@@ -1115,7 +1117,10 @@ static void cs42l56_free_beep(struct snd_soc_component *component)

device_remove_file(component->dev, &dev_attr_beep);
cancel_work_sync(&cs42l56->beep_work);
- cs42l56->beep = NULL;
+ if (cs42l56->beep) {
+ input_unregister_device(cs42l56->beep);
+ cs42l56->beep = NULL;
+ }

snd_soc_component_update_bits(component, CS42L56_BEEP_TONE_CFG,
CS42L56_BEEP_EN_MASK, 0);
--
2.50.1