[PATCH 21/21] ASoC: rt5514-spi: Free the DSP context on component remove

From: Chancel Liu

Date: Mon Sep 21 2026 - 07:34:27 EST


From: Chancel Liu <chancel.liu@xxxxxxx>

component->dev is the underlying SPI bus device, whose devres lifetime
follows the physical device's probe/remove rather than the ASoC card's
bind/unbind. The rt5514_dsp context was allocated in
rt5514_spi_pcm_probe() via devm_kzalloc(component->dev, ...) and its
delayed work and wakeup source were never torn down on component remove,
so the context leaked and the pending copy work / wakeup source were
left dangling on every card bind/unbind cycle.

Allocate the context with plain kzalloc() and add a component .remove
callback that cancels the copy work, undoes device_init_wakeup(),
destroys the mutex and frees the context. The threaded IRQ is requested
with the non-devm request_irq() API and freed explicitly in component
.remove.

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

diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 91290bfe8daa..b7b48a9141ee 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -257,8 +257,7 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
struct rt5514_dsp *rt5514_dsp;
int ret;

- rt5514_dsp = devm_kzalloc(component->dev, sizeof(*rt5514_dsp),
- GFP_KERNEL);
+ rt5514_dsp = kzalloc_obj(*rt5514_dsp);
if (!rt5514_dsp)
return -ENOMEM;

@@ -268,21 +267,40 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
snd_soc_component_set_drvdata(component, rt5514_dsp);

if (rt5514_spi->irq) {
- ret = devm_request_threaded_irq(&rt5514_spi->dev,
- rt5514_spi->irq, NULL, rt5514_spi_irq,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5514-spi",
- rt5514_dsp);
- if (ret)
+ ret = request_threaded_irq(rt5514_spi->irq, NULL,
+ rt5514_spi_irq,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "rt5514-spi", rt5514_dsp);
+ if (ret) {
dev_err(&rt5514_spi->dev,
"%s Failed to request IRQ: %d\n", __func__,
ret);
- else
- device_init_wakeup(rt5514_dsp->dev, true);
+ kfree(rt5514_dsp);
+ return ret;
+ }
+
+ device_init_wakeup(rt5514_dsp->dev, true);
}

return 0;
}

+static void rt5514_spi_pcm_remove(struct snd_soc_component *component)
+{
+ struct rt5514_dsp *rt5514_dsp =
+ snd_soc_component_get_drvdata(component);
+
+ if (rt5514_spi->irq) {
+ free_irq(rt5514_spi->irq, rt5514_dsp);
+ device_init_wakeup(rt5514_dsp->dev, false);
+ }
+
+ cancel_delayed_work_sync(&rt5514_dsp->copy_work);
+
+ mutex_destroy(&rt5514_dsp->dma_lock);
+ kfree(rt5514_dsp);
+}
+
static int rt5514_spi_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
@@ -294,6 +312,7 @@ static int rt5514_spi_pcm_new(struct snd_soc_component *component,
static const struct snd_soc_component_driver rt5514_spi_component = {
.name = DRV_NAME,
.probe = rt5514_spi_pcm_probe,
+ .remove = rt5514_spi_pcm_remove,
.open = rt5514_spi_pcm_open,
.hw_params = rt5514_spi_hw_params,
.hw_free = rt5514_spi_hw_free,
--
2.50.1