* [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind
@ 2026-09-21 10:46 Chancel Liu
2026-09-21 10:46 ` [PATCH 01/21] ASoC: cpcap: Fix devm " Chancel Liu
` (20 more replies)
0 siblings, 21 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
For an ASoC component, component->dev is the underlying bus device
(I2C / SPI / platform). Its devres lifetime is tied to the physical
device's probe/remove, not to the ASoC card's bind/unbind.
A card bind (snd_soc_bind_card()) / unbind (snd_soc_unbind_card())
runs the component .probe / .remove callbacks, but the bus device
itself stays bound across the cycle. Resources requested from the
component .probe (or from a runtime DAI callback) with
devm_*(component->dev, ...), or allocated there and only released when
the bus device is removed, therefore outlive a card unbind and
accumulate one extra copy on every bind/unbind cycle.
Each codec is fixed following one of two principles, chosen by what the
resource actually depends on:
1. Pure hardware resources (clk / regulator / regmap / GPIO / board
description) only depend on the physical device, not on the ASoC
component.
Their acquisition is moved to the bus probe (i2c / spi / platform probe)
using devm_*(&client->dev, ...), so their devres lifetime correctly
follows the device and they are not re-requested on every bind.
2. Resources that genuinely depend on the card/component (they are bound
to the component, or must be torn down when the card is unbound)
They are kept in the component .probe, but switched from devm to
plain allocation and released in a paired component .remove:
memory (kzalloc/kcalloc + kfree), IRQ (request_irq + free_irq),
delayed work (cancel), wakeup source and mutex.
While working on the card re-bind resource leaks fixed in
https://lore.kernel.org/linux-sound/20260913101531.2787654-1-chancel.liu@oss.nxp.com/
I noticed that the same devm-on-component->dev pattern is present in
many other codecs, leaking resources in the same way.
This series is the result of code analysis only, based on the same
devm-without-remove leak pattern I confirmed by repeated card bind/unbind
with wm8962. The individual fixes have not been tested on hardware, as I
do not have access to these codecs; review of the resource lifetimes
is therefore appreciated.
Chancel Liu (21):
ASoC: cpcap: Fix devm resource leaks across card bind/unbind
ASoC: da7218: Fix devm resource leaks across card bind/unbind
ASoC: tlv320aic32x4: Fix clock leak from runtime callbacks
ASoC: twl4030: Acquire board params and hs_extmute GPIO in the
platform probe
ASoC: es8316: Move mclk acquisition to the i2c probe
ASoC: es8323: Move mclk acquisition to the i2c probe
ASoC: es8311: Move mclk acquisition to the i2c probe
ASoC: es8328: Move clk acquisition to the bus probe
ASoC: rt5640: Move mclk acquisition to the i2c probe
ASoC: rt5616: Move mclk acquisition to the i2c probe
ASoC: rt5514: Move clk acquisition to the i2c probe
ASoC: rt5682s: Move mclk acquisition to the i2c probe
ASoC: max98090: Move mclk acquisition to the i2c probe
ASoC: max98095: Move mclk acquisition to the i2c probe
ASoC: wm8985: Move regulator acquisition to the bus probe
ASoC: wm8955: Move regulator acquisition to the i2c probe
ASoC: es8389: Move regulator and mclk acquisition to the i2c probe
ASoC: rt5677-spi: Free the DSP context on component remove
ASoC: rt1011: Free the bq/drc coefficient arrays on component remove
ASoC: rt5645: Free the hardware EQ parameters on component remove
ASoC: rt5514-spi: Free the DSP context on component remove
sound/soc/codecs/cpcap.c | 74 +++++++++++++++----------
sound/soc/codecs/da7218.c | 49 +++++++++--------
sound/soc/codecs/es8311.c | 10 ++--
sound/soc/codecs/es8316.c | 14 ++---
sound/soc/codecs/es8323.c | 15 ++---
sound/soc/codecs/es8328.c | 13 ++---
sound/soc/codecs/es8389.c | 34 ++++++------
sound/soc/codecs/max98090.c | 10 ++--
sound/soc/codecs/max98095.c | 10 ++--
sound/soc/codecs/rt1011.c | 30 +++++++---
sound/soc/codecs/rt5514-spi.c | 37 ++++++++++---
sound/soc/codecs/rt5514.c | 23 ++++----
sound/soc/codecs/rt5616.c | 10 ++--
sound/soc/codecs/rt5640.c | 10 ++--
sound/soc/codecs/rt5645.c | 11 ++--
sound/soc/codecs/rt5677-spi.c | 16 +++++-
sound/soc/codecs/rt5682s.c | 12 ++--
sound/soc/codecs/tlv320aic32x4.c | 94 +++++++++++++++-----------------
sound/soc/codecs/twl4030.c | 63 ++++++++++++++-------
sound/soc/codecs/wm8955.c | 24 ++++----
sound/soc/codecs/wm8985.c | 34 ++++++++----
21 files changed, 340 insertions(+), 253 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 01/21] ASoC: cpcap: Fix devm resource leaks across card bind/unbind
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 02/21] ASoC: da7218: " Chancel Liu
` (19 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
The ASoC component .probe/.remove are called on card bind/unbind, but
component->dev is the underlying platform device. Resources requested
with devm_*(component->dev, ...) or request_irq() in the component
.probe are only released when the platform device is removed, not on
card unbind, leaking on every bind/unbind cycle.
The VAUDIO regulator is a pure hardware resource that only depends on
the platform device, so acquire it with devm_regulator_get() in the
platform probe where its devres lifetime matches the device.
The headset/mic-button IRQs genuinely depend on the component, so
keep them in cpcap_soc_probe() but request them with the non-devm
request_irq() API and free them explicitly in cpcap_soc_remove().
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/cpcap.c | 74 ++++++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 29 deletions(-)
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 0262900fbb7d..dda68165b817 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -1622,21 +1622,12 @@ static int cpcap_soc_probe(struct snd_soc_component *component)
{
struct platform_device *pdev = to_platform_device(component->dev);
struct snd_soc_card *card = component->card;
- struct cpcap_audio *cpcap;
+ struct cpcap_audio *cpcap = dev_get_drvdata(component->dev);
int err;
- cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL);
- if (!cpcap)
- return -ENOMEM;
-
snd_soc_component_set_drvdata(component, cpcap);
cpcap->component = component;
- cpcap->vaudio = devm_regulator_get(component->dev, "VAUDIO");
- if (IS_ERR(cpcap->vaudio))
- return dev_err_probe(component->dev, PTR_ERR(cpcap->vaudio),
- "Cannot get VAUDIO regulator\n");
-
err = snd_soc_card_jack_new(card, "Headphones",
SND_JACK_HEADSET | SND_JACK_BTN_0,
&cpcap->jack);
@@ -1660,13 +1651,13 @@ static int cpcap_soc_probe(struct snd_soc_component *component)
if (cpcap->hsirq < 0)
return cpcap->hsirq;
- err = devm_request_threaded_irq(component->dev, cpcap->hsirq, NULL,
- cpcap_hs_irq_thread,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT,
- "cpcap-codec-hs",
- component);
+ err = request_threaded_irq(cpcap->hsirq, NULL,
+ cpcap_hs_irq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "cpcap-codec-hs",
+ component);
if (err) {
dev_warn(component->dev, "no HS irq%i: %i\n",
cpcap->hsirq, err);
@@ -1674,25 +1665,27 @@ static int cpcap_soc_probe(struct snd_soc_component *component)
}
cpcap->mb2irq = platform_get_irq_byname(pdev, "mb2");
- if (cpcap->mb2irq < 0)
- return cpcap->mb2irq;
-
- err = devm_request_threaded_irq(component->dev, cpcap->mb2irq, NULL,
- cpcap_mb2_irq_thread,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT,
- "cpcap-codec-mb2",
- component);
+ if (cpcap->mb2irq < 0) {
+ err = cpcap->mb2irq;
+ goto err_free_hsirq;
+ }
+
+ err = request_threaded_irq(cpcap->mb2irq, NULL,
+ cpcap_mb2_irq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "cpcap-codec-mb2",
+ component);
if (err) {
dev_warn(component->dev, "no MB2 irq%i: %i\n",
cpcap->mb2irq, err);
- return err;
+ goto err_free_hsirq;
}
err = cpcap_audio_reset(component, false);
if (err)
- return err;
+ goto err_free_mb2irq;
cpcap_hs_irq_thread(cpcap->hsirq, component);
@@ -1700,6 +1693,13 @@ static int cpcap_soc_probe(struct snd_soc_component *component)
enable_irq_wake(cpcap->mb2irq);
return 0;
+
+err_free_mb2irq:
+ free_irq(cpcap->mb2irq, component);
+err_free_hsirq:
+ free_irq(cpcap->hsirq, component);
+
+ return err;
}
static void cpcap_soc_remove(struct snd_soc_component *component)
@@ -1708,6 +1708,9 @@ static void cpcap_soc_remove(struct snd_soc_component *component)
disable_irq_wake(cpcap->hsirq);
disable_irq_wake(cpcap->mb2irq);
+
+ free_irq(cpcap->mb2irq, component);
+ free_irq(cpcap->hsirq, component);
}
static int cpcap_set_bias_level(struct snd_soc_component *component,
@@ -1754,11 +1757,24 @@ static int cpcap_codec_probe(struct platform_device *pdev)
{
struct device_node *codec_node =
of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+ struct cpcap_audio *cpcap;
+
if (!codec_node)
return -ENODEV;
pdev->dev.of_node = codec_node;
+ cpcap = devm_kzalloc(&pdev->dev, sizeof(*cpcap), GFP_KERNEL);
+ if (!cpcap)
+ return -ENOMEM;
+
+ cpcap->vaudio = devm_regulator_get(&pdev->dev, "VAUDIO");
+ if (IS_ERR(cpcap->vaudio))
+ return dev_err_probe(&pdev->dev, PTR_ERR(cpcap->vaudio),
+ "Cannot get VAUDIO regulator\n");
+
+ platform_set_drvdata(pdev, cpcap);
+
return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap,
cpcap_dai, ARRAY_SIZE(cpcap_dai));
}
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 02/21] ASoC: da7218: Fix devm resource leaks across card bind/unbind
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
2026-09-21 10:46 ` [PATCH 01/21] ASoC: cpcap: Fix devm " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 03/21] ASoC: tlv320aic32x4: Fix clock leak from runtime callbacks Chancel Liu
` (18 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying I2C device, so resources requested
with devm_*(component->dev, ...) in the component .probe are only
released when the I2C device is removed, not on card unbind. This
leaks the mclk clock, the regulator bulk and the IRQ on every card
bind/unbind cycle.
Move the mclk clock and the regulator supplies (pure hardware
resources tied to the platform device) to da7218_i2c_probe() using
devm on &i2c->dev. Keep the IRQ in the component .probe (it feeds the
component) but request it with the non-devm API and free it in
da7218_remove().
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/da7218.c | 49 ++++++++++++++++++++-------------------
1 file changed, 25 insertions(+), 24 deletions(-)
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 361daf14152e..f8928545b70f 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -2638,18 +2638,7 @@ static int da7218_handle_supplies(struct snd_soc_component *component)
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
struct regulator *vddio;
u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V;
- int i, ret;
-
- /* Get required supplies */
- for (i = 0; i < DA7218_NUM_SUPPLIES; ++i)
- da7218->supplies[i].supply = da7218_supply_names[i];
-
- ret = devm_regulator_bulk_get(component->dev, DA7218_NUM_SUPPLIES,
- da7218->supplies);
- if (ret) {
- dev_err(component->dev, "Failed to get supplies\n");
- return ret;
- }
+ int ret;
/* Determine VDDIO voltage provided */
vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer;
@@ -2895,13 +2884,6 @@ static int da7218_probe(struct snd_soc_component *component)
da7218_handle_pdata(component);
- /* Check if MCLK provided, if not the clock is NULL */
- da7218->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(da7218->mclk)) {
- ret = PTR_ERR(da7218->mclk);
- goto err_disable_reg;
- }
-
/* Default PC to free-running */
snd_soc_component_write(component, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
@@ -2965,10 +2947,10 @@ static int da7218_probe(struct snd_soc_component *component)
}
if (da7218->irq) {
- ret = devm_request_threaded_irq(component->dev, da7218->irq, NULL,
- da7218_irq_thread,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "da7218", component);
+ ret = request_threaded_irq(da7218->irq, NULL,
+ da7218_irq_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "da7218", component);
if (ret != 0) {
dev_err(component->dev, "Failed to request IRQ %d: %d\n",
da7218->irq, ret);
@@ -2989,6 +2971,9 @@ static void da7218_remove(struct snd_soc_component *component)
{
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+ if (da7218->irq)
+ free_irq(da7218->irq, component);
+
regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
}
@@ -3259,7 +3244,7 @@ static const struct regmap_config da7218_regmap_config = {
static int da7218_i2c_probe(struct i2c_client *i2c)
{
struct da7218_priv *da7218;
- int ret;
+ int i, ret;
da7218 = devm_kzalloc(&i2c->dev, sizeof(*da7218), GFP_KERNEL);
if (!da7218)
@@ -3284,6 +3269,22 @@ static int da7218_i2c_probe(struct i2c_client *i2c)
return ret;
}
+ /* Get required supplies */
+ for (i = 0; i < DA7218_NUM_SUPPLIES; ++i)
+ da7218->supplies[i].supply = da7218_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev, DA7218_NUM_SUPPLIES,
+ da7218->supplies);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to get supplies\n");
+ return ret;
+ }
+
+ /* Check if MCLK provided, if not the clock is NULL */
+ da7218->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(da7218->mclk))
+ return PTR_ERR(da7218->mclk);
+
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_da7218, &da7218_dai, 1);
if (ret < 0) {
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 03/21] ASoC: tlv320aic32x4: Fix clock leak from runtime callbacks
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
2026-09-21 10:46 ` [PATCH 01/21] ASoC: cpcap: Fix devm " Chancel Liu
2026-09-21 10:46 ` [PATCH 02/21] ASoC: da7218: " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 04/21] ASoC: twl4030: Acquire board params and hs_extmute GPIO in the platform probe Chancel Liu
` (17 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying I2C/SPI device. The driver acquired
its codec clocks with devm_clk_get()/devm_clk_bulk_get(component->dev,
...) from the DAI set_sysclk runtime callback, from set_bias_level and
from the component .probe. Because devres on component->dev is only
released when the platform device is removed, each card bind/unbind
(and, for set_sysclk, each runtime invocation) leaked a fresh clock
reference.
Acquire all codec clocks once in the bus probe with a single
devm_clk_bulk_get() into the private struct, and have the runtime
callbacks and both component probes reuse those stored references.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/tlv320aic32x4.c | 94 +++++++++++++++-----------------
1 file changed, 44 insertions(+), 50 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index af4be5bee723..7fec94768afb 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -48,8 +48,18 @@ struct aic32x4_priv {
enum aic32x4_type type;
unsigned int fmt;
+
+ struct clk_bulk_data clocks[7];
};
+#define AIC32X4_CLK_CODEC_CLKIN 0
+#define AIC32X4_CLK_PLL 1
+#define AIC32X4_CLK_NADC 2
+#define AIC32X4_CLK_MADC 3
+#define AIC32X4_CLK_NDAC 4
+#define AIC32X4_CLK_MDAC 5
+#define AIC32X4_CLK_BDIV 6
+
static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -591,14 +601,10 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = codec_dai->component;
+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
struct clk *mclk;
- struct clk *pll;
-
- pll = devm_clk_get(component->dev, "pll");
- if (IS_ERR(pll))
- return PTR_ERR(pll);
- mclk = clk_get_parent(pll);
+ mclk = clk_get_parent(aic32x4->clocks[AIC32X4_CLK_PLL].clk);
return clk_set_rate(mclk, freq);
}
@@ -750,17 +756,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
unsigned long adc_clock_rate, dac_clock_rate;
int ret;
- struct clk_bulk_data clocks[] = {
- { .id = "pll" },
- { .id = "nadc" },
- { .id = "madc" },
- { .id = "ndac" },
- { .id = "mdac" },
- { .id = "bdiv" },
- };
- ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
- if (ret)
- return ret;
+ struct clk_bulk_data *clocks = &aic32x4->clocks[AIC32X4_CLK_PLL];
ret = aic32x4_configure_rate(component, sample_rate, &aosr,
&adc_resource_class, &dac_resource_class,
@@ -876,18 +872,15 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
int ret;
struct clk_bulk_data clocks[] = {
- { .id = "madc" },
- { .id = "mdac" },
- { .id = "bdiv" },
+ aic32x4->clocks[AIC32X4_CLK_MADC],
+ aic32x4->clocks[AIC32X4_CLK_MDAC],
+ aic32x4->clocks[AIC32X4_CLK_BDIV],
};
- ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
- if (ret)
- return ret;
-
switch (level) {
case SND_SOC_BIAS_ON:
ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
@@ -970,23 +963,16 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
{
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
u32 tmp_reg;
- int ret;
- struct clk_bulk_data clocks[] = {
- { .id = "codec_clkin" },
- { .id = "pll" },
- { .id = "bdiv" },
- { .id = "mdac" },
- };
-
- ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
- if (ret)
- return ret;
+ struct clk *codec_clkin = aic32x4->clocks[AIC32X4_CLK_CODEC_CLKIN].clk;
+ struct clk *pll = aic32x4->clocks[AIC32X4_CLK_PLL].clk;
+ struct clk *bdiv = aic32x4->clocks[AIC32X4_CLK_BDIV].clk;
+ struct clk *mdac = aic32x4->clocks[AIC32X4_CLK_MDAC].clk;
aic32x4_setup_gpios(component);
- clk_set_parent(clocks[0].clk, clocks[1].clk);
- clk_set_parent(clocks[2].clk, clocks[3].clk);
+ clk_set_parent(codec_clkin, pll);
+ clk_set_parent(bdiv, mdac);
/* Power platform configuration */
if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
@@ -1127,23 +1113,16 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
{
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
u32 tmp_reg;
- int ret;
-
- struct clk_bulk_data clocks[] = {
- { .id = "codec_clkin" },
- { .id = "pll" },
- { .id = "bdiv" },
- { .id = "mdac" },
- };
- ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
- if (ret)
- return ret;
+ struct clk *codec_clkin = aic32x4->clocks[AIC32X4_CLK_CODEC_CLKIN].clk;
+ struct clk *pll = aic32x4->clocks[AIC32X4_CLK_PLL].clk;
+ struct clk *bdiv = aic32x4->clocks[AIC32X4_CLK_BDIV].clk;
+ struct clk *mdac = aic32x4->clocks[AIC32X4_CLK_MDAC].clk;
aic32x4_setup_gpios(component);
- clk_set_parent(clocks[0].clk, clocks[1].clk);
- clk_set_parent(clocks[2].clk, clocks[3].clk);
+ clk_set_parent(codec_clkin, pll);
+ clk_set_parent(bdiv, mdac);
/* Power platform configuration */
if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
@@ -1362,6 +1341,21 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap,
if (ret)
goto err_disable_regulators;
+ aic32x4->clocks[AIC32X4_CLK_CODEC_CLKIN].id = "codec_clkin";
+ aic32x4->clocks[AIC32X4_CLK_PLL].id = "pll";
+ aic32x4->clocks[AIC32X4_CLK_NADC].id = "nadc";
+ aic32x4->clocks[AIC32X4_CLK_MADC].id = "madc";
+ aic32x4->clocks[AIC32X4_CLK_NDAC].id = "ndac";
+ aic32x4->clocks[AIC32X4_CLK_MDAC].id = "mdac";
+ aic32x4->clocks[AIC32X4_CLK_BDIV].id = "bdiv";
+
+ ret = devm_clk_bulk_get(dev, ARRAY_SIZE(aic32x4->clocks),
+ aic32x4->clocks);
+ if (ret) {
+ dev_err(dev, "Failed to get clocks\n");
+ goto err_disable_regulators;
+ }
+
switch (aic32x4->type) {
case AIC32X4_TYPE_TAS2505:
ret = devm_snd_soc_register_component(dev,
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 04/21] ASoC: twl4030: Acquire board params and hs_extmute GPIO in the platform probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (2 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 03/21] ASoC: tlv320aic32x4: Fix clock leak from runtime callbacks Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 05/21] ASoC: es8316: Move mclk acquisition to the i2c probe Chancel Liu
` (16 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
The component .probe/.remove callbacks fire on ASoC card bind/unbind, but
component->dev is the underlying platform device whose devres is only
released on physical device removal. Resources allocated with
devm_*(component->dev, ...) in the component probe are therefore never
freed on card unbind, leaking one copy per bind/unbind cycle and leaking
the hs_extmute GPIO descriptor (which can also fail to be re-acquired on
re-bind).
The board parameters and the hs_extmute GPIO are pure hardware/device
level resources: they only depend on the physical device and the DT, not
on the ASoC component. Acquire them (together with the driver context)
in twl4030_codec_probe() using devm on the platform device, and hand the
context to the component through drvdata. Their devres lifetime then
correctly follows the device rather than the card bind/unbind, so no
explicit component .remove is needed. The component probe keeps only the
codec register initialisation that genuinely needs the component.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/twl4030.c | 63 +++++++++++++++++++++++++-------------
1 file changed, 42 insertions(+), 21 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index b986ece55d5a..442624cf2a31 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -212,21 +212,21 @@ twl4030_get_board_param_values(struct twl4030_board_params *board_params,
}
static struct twl4030_board_params*
-twl4030_get_board_params(struct snd_soc_component *component)
+twl4030_get_board_params(struct device *dev)
{
struct twl4030_board_params *board_params = NULL;
struct device_node *twl4030_codec_node = NULL;
- twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node,
+ twl4030_codec_node = of_get_child_by_name(dev->parent->of_node,
"codec");
if (twl4030_codec_node) {
- board_params = devm_kzalloc(component->dev,
+ board_params = devm_kzalloc(dev,
sizeof(struct twl4030_board_params),
GFP_KERNEL);
if (!board_params) {
of_node_put(twl4030_codec_node);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
twl4030_get_board_param_values(board_params, twl4030_codec_node);
of_node_put(twl4030_codec_node);
@@ -235,21 +235,22 @@ twl4030_get_board_params(struct snd_soc_component *component)
return board_params;
}
-static int twl4030_init_chip(struct snd_soc_component *component)
+static int twl4030_get_hw_params(struct device *dev,
+ struct twl4030_priv *twl4030)
{
struct twl4030_board_params *board_params;
- struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
- u8 reg, byte;
- int i = 0;
- board_params = twl4030_get_board_params(component);
+ board_params = twl4030_get_board_params(dev);
+ if (IS_ERR(board_params))
+ return PTR_ERR(board_params);
if (board_params && board_params->hs_extmute) {
- board_params->hs_extmute_gpio = devm_gpiod_get_optional(component->dev,
+ board_params->hs_extmute_gpio = devm_gpiod_get_optional(dev,
"ti,hs_extmute",
GPIOD_OUT_LOW);
if (IS_ERR(board_params->hs_extmute_gpio))
- return dev_err_probe(component->dev, PTR_ERR(board_params->hs_extmute_gpio),
+ return dev_err_probe(dev,
+ PTR_ERR(board_params->hs_extmute_gpio),
"Failed to get hs_extmute GPIO\n");
if (board_params->hs_extmute_gpio) {
@@ -257,7 +258,7 @@ static int twl4030_init_chip(struct snd_soc_component *component)
} else {
u8 pin_mux;
- dev_info(component->dev, "use TWL4030 GPIO6\n");
+ dev_info(dev, "use TWL4030 GPIO6\n");
/* Set TWL4030 GPIO6 as EXTMUTE signal */
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
@@ -269,6 +270,18 @@ static int twl4030_init_chip(struct snd_soc_component *component)
}
}
+ twl4030->board_params = board_params;
+
+ return 0;
+}
+
+static int twl4030_init_chip(struct snd_soc_component *component)
+{
+ struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+ struct twl4030_board_params *board_params = twl4030->board_params;
+ u8 reg, byte;
+ int i = 0;
+
/* Initialize the local ctl register cache */
tw4030_init_ctl_cache(twl4030);
@@ -288,8 +301,6 @@ static int twl4030_init_chip(struct snd_soc_component *component)
if (!board_params)
return 0;
- twl4030->board_params = board_params;
-
reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
reg &= ~TWL4030_RAMP_DELAY;
reg |= (board_params->ramp_delay_value << 2);
@@ -2163,15 +2174,9 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
static int twl4030_soc_probe(struct snd_soc_component *component)
{
- struct twl4030_priv *twl4030;
+ struct twl4030_priv *twl4030 = dev_get_drvdata(component->dev);
- twl4030 = devm_kzalloc(component->dev, sizeof(struct twl4030_priv),
- GFP_KERNEL);
- if (!twl4030)
- return -ENOMEM;
snd_soc_component_set_drvdata(component, twl4030);
- /* Set the defaults, and power up the codec */
- twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
return twl4030_init_chip(component);
}
@@ -2193,6 +2198,22 @@ static const struct snd_soc_component_driver soc_component_dev_twl4030 = {
static int twl4030_codec_probe(struct platform_device *pdev)
{
+ struct twl4030_priv *twl4030;
+ int ret;
+
+ twl4030 = devm_kzalloc(&pdev->dev, sizeof(*twl4030), GFP_KERNEL);
+ if (!twl4030)
+ return -ENOMEM;
+
+ /* Set the defaults, and power up the codec */
+ twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
+
+ ret = twl4030_get_hw_params(&pdev->dev, twl4030);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, twl4030);
+
return devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_twl4030,
twl4030_dai, ARRAY_SIZE(twl4030_dai));
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 05/21] ASoC: es8316: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (3 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 04/21] ASoC: twl4030: Acquire board params and hs_extmute GPIO in the platform probe Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 06/21] ASoC: es8323: " Chancel Liu
` (15 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the mclk with devm_clk_get_optional(component->dev, ...) in the
component probe therefore leaks a clk reference on every card
bind/unbind cycle.
Move the devm_clk_get_optional() to es8316_i2c_probe() so the clk
reference is tied to the i2c device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/es8316.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 59399476b9d7..5e7bf6f020e0 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -771,14 +771,6 @@ static int es8316_probe(struct snd_soc_component *component)
es8316->component = component;
- es8316->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(es8316->mclk)) {
- dev_err(component->dev, "unable to get mclk\n");
- return PTR_ERR(es8316->mclk);
- }
- if (!es8316->mclk)
- dev_warn(component->dev, "assuming static mclk\n");
-
ret = clk_prepare_enable(es8316->mclk);
if (ret) {
dev_err(component->dev, "unable to enable mclk\n");
@@ -883,6 +875,12 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client)
i2c_set_clientdata(i2c_client, es8316);
+ es8316->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(es8316->mclk))
+ return dev_err_probe(dev, PTR_ERR(es8316->mclk), "unable to get mclk\n");
+ if (!es8316->mclk)
+ dev_warn(dev, "assuming static mclk\n");
+
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(es8316_supply_names),
es8316_supply_names);
if (ret)
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 06/21] ASoC: es8323: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (4 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 05/21] ASoC: es8316: Move mclk acquisition to the i2c probe Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 13:17 ` Mark Brown
2026-09-21 10:46 ` [PATCH 07/21] ASoC: es8311: " Chancel Liu
` (14 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the mclk with devm_clk_get_optional(component->dev, ...) in the
component probe therefore leaks a clk reference on every card
bind/unbind cycle.
Move the devm_clk_get_optional() to es8323_i2c_probe() so the clk
reference is tied to the i2c device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/es8323.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c
index 12fcfe017ab2..3f7fbbdb111e 100644
--- a/sound/soc/codecs/es8323.c
+++ b/sound/soc/codecs/es8323.c
@@ -671,15 +671,6 @@ static int es8323_probe(struct snd_soc_component *component)
struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
int ret;
- es8323->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(es8323->mclk)) {
- dev_err(component->dev, "unable to get mclk\n");
- return PTR_ERR(es8323->mclk);
- }
-
- if (!es8323->mclk)
- dev_warn(component->dev, "assuming static mclk\n");
-
ret = clk_prepare_enable(es8323->mclk);
if (ret) {
dev_err(component->dev, "unable to enable mclk\n");
@@ -789,6 +780,12 @@ static int es8323_i2c_probe(struct i2c_client *i2c_client)
i2c_set_clientdata(i2c_client, es8323);
+ es8323->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(es8323->mclk))
+ return dev_err_probe(dev, PTR_ERR(es8323->mclk), "unable to get mclk\n");
+ if (!es8323->mclk)
+ dev_warn(dev, "assuming static mclk\n");
+
es8323->regmap = devm_regmap_init_i2c(i2c_client, &es8323_regmap);
if (IS_ERR(es8323->regmap))
return PTR_ERR(es8323->regmap);
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 07/21] ASoC: es8311: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (5 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 06/21] ASoC: es8323: " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 08/21] ASoC: es8328: Move clk acquisition to the bus probe Chancel Liu
` (13 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the mclk with devm_clk_get_optional(component->dev, ...) in the
component probe therefore leaks a clk reference on every card
bind/unbind cycle.
Move the devm_clk_get_optional() to es8311_i2c_probe() so the clk
reference is tied to the i2c device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/es8311.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c
index e46b85f11d57..ddbbfc2443b3 100644
--- a/sound/soc/codecs/es8311.c
+++ b/sound/soc/codecs/es8311.c
@@ -906,12 +906,6 @@ static int es8311_component_probe(struct snd_soc_component *component)
es8311 = snd_soc_component_get_drvdata(component);
- es8311->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(es8311->mclk)) {
- dev_err(component->dev, "invalid mclk\n");
- return PTR_ERR(es8311->mclk);
- }
-
es8311->mclk_freq = clk_get_rate(es8311->mclk);
if (es8311->mclk_freq > 0 && es8311->mclk_freq < ES8311_MCLK_MAX_FREQ)
es8311_set_sysclk_constraints(es8311->mclk_freq, es8311);
@@ -960,6 +954,10 @@ static int es8311_i2c_probe(struct i2c_client *i2c_client)
if (es8311 == NULL)
return -ENOMEM;
+ es8311->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(es8311->mclk))
+ return dev_err_probe(dev, PTR_ERR(es8311->mclk), "invalid mclk\n");
+
es8311->regmap =
devm_regmap_init_i2c(i2c_client, &es8311_regmap_config);
if (IS_ERR(es8311->regmap))
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 08/21] ASoC: es8328: Move clk acquisition to the bus probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (6 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 07/21] ASoC: es8311: " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 09/21] ASoC: rt5640: Move mclk acquisition to the i2c probe Chancel Liu
` (12 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c/spi device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the codec clock with devm_clk_get(component->dev, ...) in the component
probe therefore leaks a clk reference on every card bind/unbind cycle.
Move the devm_clk_get() to es8328_probe() (the shared i2c/spi bus level
probe) so the clk reference is tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/es8328.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 7d52b5d9d061..37fda2f42b0c 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -829,14 +829,6 @@ static int es8328_component_probe(struct snd_soc_component *component)
return ret;
}
- /* Setup clocks */
- es8328->clk = devm_clk_get(component->dev, NULL);
- if (IS_ERR(es8328->clk)) {
- dev_err(component->dev, "codec clock missing or invalid\n");
- ret = PTR_ERR(es8328->clk);
- goto clk_fail;
- }
-
ret = clk_prepare_enable(es8328->clk);
if (ret) {
dev_err(component->dev, "unable to prepare codec clk\n");
@@ -906,6 +898,11 @@ int es8328_probe(struct device *dev, struct regmap *regmap)
es8328->regmap = regmap;
+ es8328->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(es8328->clk))
+ return dev_err_probe(dev, PTR_ERR(es8328->clk),
+ "codec clock missing or invalid\n");
+
for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++)
es8328->supplies[i].supply = supply_names[i];
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 09/21] ASoC: rt5640: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (7 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 08/21] ASoC: es8328: Move clk acquisition to the bus probe Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 18:28 ` Cezary Rojewski
2026-09-21 10:46 ` [PATCH 10/21] ASoC: rt5616: " Chancel Liu
` (11 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the codec clock with devm_clk_get_optional(component->dev, ...) in the
component probe therefore leaks a clk reference on every card
bind/unbind cycle.
Move the devm_clk_get_optional() to rt5640_i2c_probe() so the clk
reference is tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/rt5640.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 03d0ac3359f5..1a45346cf6b9 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2667,11 +2667,6 @@ static int rt5640_probe(struct snd_soc_component *component)
bool dmic_en = false;
u32 val;
- /* Check if MCLK provided */
- rt5640->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(rt5640->mclk))
- return PTR_ERR(rt5640->mclk);
-
rt5640->component = component;
snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
@@ -3053,6 +3048,11 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
regmap_update_bits(rt5640->regmap, RT5640_GCTL1,
RT5640_MCLK_DET, RT5640_MCLK_DET);
+ /* Check if MCLK provided */
+ rt5640->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(rt5640->mclk))
+ return PTR_ERR(rt5640->mclk);
+
rt5640->hp_mute = true;
rt5640->irq = i2c->irq;
INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work);
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 10/21] ASoC: rt5616: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (8 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 09/21] ASoC: rt5640: Move mclk acquisition to the i2c probe Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 11/21] ASoC: rt5514: Move clk " Chancel Liu
` (10 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the codec clock with devm_clk_get_optional(component->dev, ...) in the
component probe therefore leaks a clk reference on every card
bind/unbind cycle.
Move the devm_clk_get_optional() to rt5616_i2c_probe() so the clk
reference is tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/rt5616.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index 3f9d97d04d48..e30e3b563c90 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -1222,11 +1222,6 @@ static int rt5616_probe(struct snd_soc_component *component)
{
struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
- /* Check if MCLK provided */
- rt5616->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(rt5616->mclk))
- return PTR_ERR(rt5616->mclk);
-
rt5616->component = component;
return 0;
@@ -1357,6 +1352,11 @@ static int rt5616_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, rt5616);
+ /* Check if MCLK provided */
+ rt5616->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(rt5616->mclk))
+ return PTR_ERR(rt5616->mclk);
+
rt5616->regmap = devm_regmap_init_i2c(i2c, &rt5616_regmap);
if (IS_ERR(rt5616->regmap)) {
ret = PTR_ERR(rt5616->regmap);
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 11/21] ASoC: rt5514: Move clk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (9 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 10/21] ASoC: rt5616: " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 12/21] ASoC: rt5682s: Move mclk " Chancel Liu
` (9 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the codec clocks with devm_clk_get*(component->dev, ...) in the
component probe therefore leaks clk references on every card
bind/unbind cycle.
Move the mclk and dsp_calib_clk acquisition to rt5514_i2c_probe() so
the clk references are tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/rt5514.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 753143e2d11f..a33fbc9fb047 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1099,18 +1099,6 @@ static int rt5514_set_bias_level(struct snd_soc_component *component,
static int rt5514_probe(struct snd_soc_component *component)
{
struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
- struct platform_device *pdev = to_platform_device(component->dev);
-
- rt5514->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(rt5514->mclk))
- return PTR_ERR(rt5514->mclk);
-
- if (rt5514->pdata.dsp_calib_clk_name) {
- rt5514->dsp_calib_clk = devm_clk_get(&pdev->dev,
- rt5514->pdata.dsp_calib_clk_name);
- if (PTR_ERR(rt5514->dsp_calib_clk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- }
rt5514->component = component;
rt5514->pll3_cal_value = 0x0078b000;
@@ -1285,6 +1273,17 @@ static int rt5514_i2c_probe(struct i2c_client *i2c)
else
rt5514_parse_dp(rt5514, &i2c->dev);
+ rt5514->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(rt5514->mclk))
+ return PTR_ERR(rt5514->mclk);
+
+ if (rt5514->pdata.dsp_calib_clk_name) {
+ rt5514->dsp_calib_clk = devm_clk_get(&i2c->dev,
+ rt5514->pdata.dsp_calib_clk_name);
+ if (PTR_ERR(rt5514->dsp_calib_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ }
+
rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap);
if (IS_ERR(rt5514->i2c_regmap)) {
ret = PTR_ERR(rt5514->i2c_regmap);
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 12/21] ASoC: rt5682s: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (10 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 11/21] ASoC: rt5514: Move clk " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 18:44 ` Cezary Rojewski
2026-09-21 10:46 ` [PATCH 13/21] ASoC: max98090: " Chancel Liu
` (8 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the codec clock with devm_clk_get_optional(component->dev, ...) in the
component probe chain therefore leaks a clk reference on every card
bind/unbind cycle.
Move the devm_clk_get_optional() to rt5682s_i2c_probe() so the clk
reference is tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/rt5682s.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 6dd0d36a7186..0f80e4c32f57 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -2846,11 +2846,6 @@ static int rt5682s_dai_probe_clks(struct snd_soc_component *component)
struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
int ret;
- /* Check if MCLK provided */
- rt5682s->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(rt5682s->mclk))
- return PTR_ERR(rt5682s->mclk);
-
/* Register CCF DAI clock control */
ret = rt5682s_register_dai_clks(component);
if (ret)
@@ -3152,6 +3147,13 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
return ret;
}
+#ifdef CONFIG_COMMON_CLK
+ /* Check if MCLK provided */
+ rt5682s->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(rt5682s->mclk))
+ return PTR_ERR(rt5682s->mclk);
+#endif
+
for (i = 0; i < ARRAY_SIZE(rt5682s->supplies); i++)
rt5682s->supplies[i].supply = rt5682s_supply_names[i];
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 13/21] ASoC: max98090: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (11 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 12/21] ASoC: rt5682s: Move mclk " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 14/21] ASoC: max98095: " Chancel Liu
` (7 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the codec clock with devm_clk_get(component->dev, ...) in the component
probe therefore leaks a clk reference on every card bind/unbind cycle.
Move the devm_clk_get() to max98090_i2c_probe() so the clk reference is
tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/max98090.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index c31f3d32fa43..4bb5478f4642 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2448,11 +2448,6 @@ static int max98090_probe(struct snd_soc_component *component)
dev_dbg(component->dev, "max98090_probe\n");
- max98090->mclk = devm_clk_get(component->dev, "mclk");
- if (IS_ERR(max98090->mclk))
- if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
-
max98090->component = component;
/* Reset the codec, the DSP core, and disable all interrupts */
@@ -2633,6 +2628,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c)
goto err_enable;
}
+ max98090->mclk = devm_clk_get(&i2c->dev, "mclk");
+ if (IS_ERR(max98090->mclk))
+ if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"max98090_interrupt", max98090);
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 14/21] ASoC: max98095: Move mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (12 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 13/21] ASoC: max98090: " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 15/21] ASoC: wm8985: Move regulator acquisition to the bus probe Chancel Liu
` (6 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the codec clock with devm_clk_get(component->dev, ...) in the component
probe therefore leaks a clk reference on every card bind/unbind cycle.
Move the devm_clk_get() to max98095_i2c_probe() so the clk reference is
tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/max98095.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index a64a5ba00379..c827fd47a5b0 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2005,11 +2005,6 @@ static int max98095_probe(struct snd_soc_component *component)
struct i2c_client *client;
int ret = 0;
- max98095->mclk = devm_clk_get(component->dev, "mclk");
- if (IS_ERR(max98095->mclk))
- if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
-
/* reset the codec, the DSP core, and disable all interrupts */
max98095_reset(component);
@@ -2153,6 +2148,11 @@ static int max98095_i2c_probe(struct i2c_client *i2c)
return ret;
}
+ max98095->mclk = devm_clk_get(&i2c->dev, "mclk");
+ if (IS_ERR(max98095->mclk))
+ if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
max98095->devtype = (uintptr_t)i2c_get_match_data(i2c);
i2c_set_clientdata(i2c, max98095);
max98095->pdata = i2c->dev.platform_data;
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 15/21] ASoC: wm8985: Move regulator acquisition to the bus probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (13 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 14/21] ASoC: max98095: " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 11:52 ` Charles Keepax
2026-09-21 10:46 ` [PATCH 16/21] ASoC: wm8955: Move regulator acquisition to the i2c probe Chancel Liu
` (5 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c/spi device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the regulator supplies with devm_regulator_bulk_get(component->dev, ...)
in the component probe therefore leaks the regulator references on every
card bind/unbind cycle.
Move the devm_regulator_bulk_get() into a helper called from the i2c and
spi probes so the supplies are tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/wm8985.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 877a691c188b..70d0b8667b90 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1029,6 +1029,18 @@ static int wm8985_set_bias_level(struct snd_soc_component *component,
return 0;
}
+static int wm8985_get_regulators(struct device *dev,
+ struct wm8985_priv *wm8985)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
+ wm8985->supplies[i].supply = wm8985_supply_names[i];
+
+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+}
+
static int wm8985_probe(struct snd_soc_component *component)
{
size_t i;
@@ -1037,16 +1049,6 @@ static int wm8985_probe(struct snd_soc_component *component)
wm8985 = snd_soc_component_get_drvdata(component);
- for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
- wm8985->supplies[i].supply = wm8985_supply_names[i];
-
- ret = devm_regulator_bulk_get(component->dev, ARRAY_SIZE(wm8985->supplies),
- wm8985->supplies);
- if (ret) {
- dev_err(component->dev, "Failed to request supplies: %d\n", ret);
- return ret;
- }
-
ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
wm8985->supplies);
if (ret) {
@@ -1176,6 +1178,12 @@ static int wm8985_spi_probe(struct spi_device *spi)
return ret;
}
+ ret = wm8985_get_regulators(&spi->dev, wm8985);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
ret = devm_snd_soc_register_component(&spi->dev,
&soc_component_dev_wm8985, &wm8985_dai, 1);
return ret;
@@ -1212,6 +1220,12 @@ static int wm8985_i2c_probe(struct i2c_client *i2c)
return ret;
}
+ ret = wm8985_get_regulators(&i2c->dev, wm8985);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_wm8985, &wm8985_dai, 1);
return ret;
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 16/21] ASoC: wm8955: Move regulator acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (14 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 15/21] ASoC: wm8985: Move regulator acquisition to the bus probe Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:58 ` Charles Keepax
2026-09-21 10:46 ` [PATCH 17/21] ASoC: es8389: Move regulator and mclk " Chancel Liu
` (4 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the regulator supplies with devm_regulator_bulk_get(component->dev, ...)
in the component probe therefore leaks the regulator references on every
card bind/unbind cycle.
Move the devm_regulator_bulk_get() to the i2c probe so the supplies are
tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/wm8955.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 1d367a957f3e..017ec2e37d1e 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -888,17 +888,7 @@ static int wm8955_probe(struct snd_soc_component *component)
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
struct wm8955_pdata *pdata = dev_get_platdata(component->dev);
- int ret, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
- wm8955->supplies[i].supply = wm8955_supply_names[i];
-
- ret = devm_regulator_bulk_get(component->dev, ARRAY_SIZE(wm8955->supplies),
- wm8955->supplies);
- if (ret != 0) {
- dev_err(component->dev, "Failed to request supplies: %d\n", ret);
- return ret;
- }
+ int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
wm8955->supplies);
@@ -990,7 +980,7 @@ static const struct regmap_config wm8955_regmap = {
static int wm8955_i2c_probe(struct i2c_client *i2c)
{
struct wm8955_priv *wm8955;
- int ret;
+ int i, ret;
wm8955 = devm_kzalloc(&i2c->dev, sizeof(struct wm8955_priv),
GFP_KERNEL);
@@ -1007,6 +997,16 @@ static int wm8955_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, wm8955);
+ for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
+ wm8955->supplies[i].supply = wm8955_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8955->supplies),
+ wm8955->supplies);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_wm8955, &wm8955_dai, 1);
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 17/21] ASoC: es8389: Move regulator and mclk acquisition to the i2c probe
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (15 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 16/21] ASoC: wm8955: Move regulator acquisition to the i2c probe Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 18/21] ASoC: rt5677-spi: Free the DSP context on component remove Chancel Liu
` (3 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. Getting
the core regulator supplies and the mclk with devm_*(component->dev, ...)
in the component probe therefore leaks those references on every card
bind/unbind cycle.
Move the devm_regulator_bulk_get() and devm_clk_get_optional() into the
i2c probe so the resources are tied to the physical device lifetime.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/es8389.c | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index fe341fe56760..931577e5e29f 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -1076,22 +1076,6 @@ static int es8389_probe(struct snd_soc_component *component)
es8389->mclk_src = ES8389_MCLK_SOURCE;
}
- for (i = 0; i < ARRAY_SIZE(es8389_core_supplies); i++)
- es8389->core_supply[i].supply = es8389_core_supplies[i];
- ret = devm_regulator_bulk_get(component->dev, ARRAY_SIZE(es8389_core_supplies), es8389->core_supply);
- if (ret) {
- dev_err(component->dev, "Failed to request core supplies %d\n", ret);
- return ret;
- }
-
- es8389->mclk = devm_clk_get_optional(component->dev, "mclk");
- if (IS_ERR(es8389->mclk))
- return dev_err_probe(component->dev, PTR_ERR(es8389->mclk),
- "ES8389 is unable to get mclk\n");
-
- if (!es8389->mclk)
- dev_err(component->dev, "%s, assuming static mclk\n", __func__);
-
ret = clk_prepare_enable(es8389->mclk);
if (ret) {
dev_err(component->dev, "%s, unable to enable mclk\n", __func__);
@@ -1179,7 +1163,7 @@ static void es8389_i2c_shutdown(struct i2c_client *i2c)
static int es8389_i2c_probe(struct i2c_client *i2c_client)
{
struct es8389_private *es8389;
- int ret;
+ int ret, i;
es8389 = devm_kzalloc(&i2c_client->dev, sizeof(*es8389), GFP_KERNEL);
if (es8389 == NULL)
@@ -1191,6 +1175,22 @@ static int es8389_i2c_probe(struct i2c_client *i2c_client)
return dev_err_probe(&i2c_client->dev, PTR_ERR(es8389->regmap),
"regmap_init() failed\n");
+ for (i = 0; i < ARRAY_SIZE(es8389_core_supplies); i++)
+ es8389->core_supply[i].supply = es8389_core_supplies[i];
+ ret = devm_regulator_bulk_get(&i2c_client->dev, ARRAY_SIZE(es8389_core_supplies),
+ es8389->core_supply);
+ if (ret)
+ return dev_err_probe(&i2c_client->dev, ret,
+ "Failed to request core supplies\n");
+
+ es8389->mclk = devm_clk_get_optional(&i2c_client->dev, "mclk");
+ if (IS_ERR(es8389->mclk))
+ return dev_err_probe(&i2c_client->dev, PTR_ERR(es8389->mclk),
+ "ES8389 is unable to get mclk\n");
+
+ if (!es8389->mclk)
+ dev_err(&i2c_client->dev, "%s, assuming static mclk\n", __func__);
+
ret = devm_snd_soc_register_component(&i2c_client->dev,
&soc_codec_dev_es8389,
&es8389_dai,
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 18/21] ASoC: rt5677-spi: Free the DSP context on component remove
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (16 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 17/21] ASoC: es8389: Move regulator and mclk " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 19/21] ASoC: rt1011: Free the bq/drc coefficient arrays " Chancel Liu
` (2 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
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 rt5677_dsp context allocated in the component probe with
devm_kzalloc(component->dev, ...) therefore leaks on every card
bind/unbind cycle, and the delayed work initialised there is never
cancelled on unbind.
Allocate the context with kzalloc() and add a component .remove callback
that cancels the copy work, destroys the mutex and frees the context.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/rt5677-spi.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index ebc527115ea5..285ea4872cde 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -380,8 +380,7 @@ static int rt5677_spi_pcm_probe(struct snd_soc_component *component)
{
struct rt5677_dsp *rt5677_dsp;
- rt5677_dsp = devm_kzalloc(component->dev, sizeof(*rt5677_dsp),
- GFP_KERNEL);
+ rt5677_dsp = kzalloc_obj(*rt5677_dsp);
if (!rt5677_dsp)
return -ENOMEM;
rt5677_dsp->dev = &g_spi->dev;
@@ -392,9 +391,22 @@ static int rt5677_spi_pcm_probe(struct snd_soc_component *component)
return 0;
}
+static void rt5677_spi_pcm_remove(struct snd_soc_component *component)
+{
+ struct rt5677_dsp *rt5677_dsp =
+ snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_set_drvdata(component, NULL);
+
+ cancel_delayed_work_sync(&rt5677_dsp->copy_work);
+ mutex_destroy(&rt5677_dsp->dma_lock);
+ kfree(rt5677_dsp);
+}
+
static const struct snd_soc_component_driver rt5677_spi_dai_component = {
.name = DRV_NAME,
.probe = rt5677_spi_pcm_probe,
+ .remove = rt5677_spi_pcm_remove,
.open = rt5677_spi_pcm_open,
.close = rt5677_spi_pcm_close,
.hw_params = rt5677_spi_hw_params,
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 19/21] ASoC: rt1011: Free the bq/drc coefficient arrays on component remove
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (17 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 18/21] ASoC: rt5677-spi: Free the DSP context on component remove Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 20/21] ASoC: rt5645: Free the hardware EQ parameters " Chancel Liu
2026-09-21 10:46 ` [PATCH 21/21] ASoC: rt5514-spi: Free the DSP context " Chancel Liu
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying i2c device whose devres is only
released on physical device removal, not on ASoC card unbind. The
bq_drc_params arrays allocated in the component probe with
devm_kcalloc(component->dev, ...) therefore leak on every card
bind/unbind cycle.
Allocate the arrays with kcalloc() and free them in the component
remove callback.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/rt1011.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)
diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c
index d47b0370dd6b..c140c079838d 100644
--- a/sound/soc/codecs/rt1011.c
+++ b/sound/soc/codecs/rt1011.c
@@ -2053,29 +2053,45 @@ static int rt1011_probe(struct snd_soc_component *component)
schedule_work(&rt1011->cali_work);
rt1011->i2s_ref = 0;
- rt1011->bq_drc_params = devm_kcalloc(component->dev,
- RT1011_ADVMODE_NUM, sizeof(struct rt1011_bq_drc_params *),
- GFP_KERNEL);
+ rt1011->bq_drc_params = kcalloc(RT1011_ADVMODE_NUM,
+ sizeof(struct rt1011_bq_drc_params *),
+ GFP_KERNEL);
if (!rt1011->bq_drc_params)
return -ENOMEM;
for (i = 0; i < RT1011_ADVMODE_NUM; i++) {
- rt1011->bq_drc_params[i] = devm_kcalloc(component->dev,
- RT1011_BQ_DRC_NUM, sizeof(struct rt1011_bq_drc_params),
- GFP_KERNEL);
+ rt1011->bq_drc_params[i] = kcalloc(RT1011_BQ_DRC_NUM,
+ sizeof(struct rt1011_bq_drc_params),
+ GFP_KERNEL);
if (!rt1011->bq_drc_params[i])
- return -ENOMEM;
+ goto err;
}
return 0;
+
+err:
+ while (i--)
+ kfree(rt1011->bq_drc_params[i]);
+ kfree(rt1011->bq_drc_params);
+ rt1011->bq_drc_params = NULL;
+
+ return -ENOMEM;
}
static void rt1011_remove(struct snd_soc_component *component)
{
struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component);
+ int i;
cancel_work_sync(&rt1011->cali_work);
rt1011_reset(rt1011->regmap);
+
+ if (rt1011->bq_drc_params) {
+ for (i = 0; i < RT1011_ADVMODE_NUM; i++)
+ kfree(rt1011->bq_drc_params[i]);
+ kfree(rt1011->bq_drc_params);
+ rt1011->bq_drc_params = NULL;
+ }
}
#ifdef CONFIG_PM
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 20/21] ASoC: rt5645: Free the hardware EQ parameters on component remove
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (18 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 19/21] ASoC: rt1011: Free the bq/drc coefficient arrays " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 21/21] ASoC: rt5514-spi: Free the DSP context " Chancel Liu
20 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
component->dev is the underlying I2C bus device, whose devres lifetime
follows the physical device's probe/remove rather than the ASoC card's
bind/unbind. The eq_param array was allocated in rt5645_probe() via
devm_kcalloc(component->dev, ...) but never released on component remove,
so it leaked one allocation on every card bind/unbind cycle.
Allocate eq_param with plain kcalloc() in rt5645_probe() and free it
explicitly in rt5645_remove() to keep its lifetime tied to the component.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
sound/soc/codecs/rt5645.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index bb448254275f..15d21097ed0c 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3487,10 +3487,8 @@ static int rt5645_probe(struct snd_soc_component *component)
if (rt5645->pdata.long_name)
component->card->long_name = rt5645->pdata.long_name;
- rt5645->eq_param = devm_kcalloc(component->dev,
- RT5645_HWEQ_NUM, sizeof(struct rt5645_eq_param_s),
- GFP_KERNEL);
-
+ rt5645->eq_param = kcalloc(RT5645_HWEQ_NUM,
+ sizeof(struct rt5645_eq_param_s), GFP_KERNEL);
if (!rt5645->eq_param)
return -ENOMEM;
@@ -3503,7 +3501,12 @@ static int rt5645_probe(struct snd_soc_component *component)
static void rt5645_remove(struct snd_soc_component *component)
{
+ struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
rt5645_reset(component);
+
+ kfree(rt5645->eq_param);
+ rt5645->eq_param = NULL;
}
#ifdef CONFIG_PM
--
2.50.1
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 21/21] ASoC: rt5514-spi: Free the DSP context on component remove
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
` (19 preceding siblings ...)
2026-09-21 10:46 ` [PATCH 20/21] ASoC: rt5645: Free the hardware EQ parameters " Chancel Liu
@ 2026-09-21 10:46 ` Chancel Liu
2026-09-21 13:23 ` Mark Brown
20 siblings, 1 reply; 33+ messages in thread
From: Chancel Liu @ 2026-09-21 10:46 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
Cc: Support Opensource, linux-sound, linux-kernel, patches
From: Chancel Liu <chancel.liu@nxp.com>
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@nxp.com>
---
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
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 16/21] ASoC: wm8955: Move regulator acquisition to the i2c probe
2026-09-21 10:46 ` [PATCH 16/21] ASoC: wm8955: Move regulator acquisition to the i2c probe Chancel Liu
@ 2026-09-21 10:58 ` Charles Keepax
0 siblings, 0 replies; 33+ messages in thread
From: Charles Keepax @ 2026-09-21 10:58 UTC (permalink / raw)
To: Chancel Liu
Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
On Mon, Sep 21, 2026 at 07:46:35PM +0900, Chancel Liu wrote:
> From: Chancel Liu <chancel.liu@nxp.com>
>
> component->dev is the underlying i2c device whose devres is only
> released on physical device removal, not on ASoC card unbind. Getting
> the regulator supplies with devm_regulator_bulk_get(component->dev, ...)
> in the component probe therefore leaks the regulator references on every
> card bind/unbind cycle.
>
> Move the devm_regulator_bulk_get() to the i2c probe so the supplies are
> tied to the physical device lifetime.
>
> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
> ---
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Thanks,
Charles
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 15/21] ASoC: wm8985: Move regulator acquisition to the bus probe
2026-09-21 10:46 ` [PATCH 15/21] ASoC: wm8985: Move regulator acquisition to the bus probe Chancel Liu
@ 2026-09-21 11:52 ` Charles Keepax
2026-09-22 2:01 ` Chancel Liu
0 siblings, 1 reply; 33+ messages in thread
From: Charles Keepax @ 2026-09-21 11:52 UTC (permalink / raw)
To: Chancel Liu
Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
On Mon, Sep 21, 2026 at 07:46:34PM +0900, Chancel Liu wrote:
> From: Chancel Liu <chancel.liu@nxp.com>
>
> component->dev is the underlying i2c/spi device whose devres is only
> released on physical device removal, not on ASoC card unbind. Getting
> the regulator supplies with devm_regulator_bulk_get(component->dev, ...)
> in the component probe therefore leaks the regulator references on every
> card bind/unbind cycle.
>
> Move the devm_regulator_bulk_get() into a helper called from the i2c and
> spi probes so the supplies are tied to the physical device lifetime.
>
> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
> ---
> @@ -1176,6 +1178,12 @@ static int wm8985_spi_probe(struct spi_device *spi)
> + ret = wm8985_get_regulators(&spi->dev, wm8985);
> + if (ret) {
> + dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
> + return ret;
> + }
> @@ -1212,6 +1220,12 @@ static int wm8985_i2c_probe(struct i2c_client *i2c)
> + ret = wm8985_get_regulators(&i2c->dev, wm8985);
> + if (ret) {
> + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
> + return ret;
> + }
Probably slightly nicer to include the error message in the
helper rather than duplicating it in each probe.
Thanks,
Charles
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 06/21] ASoC: es8323: Move mclk acquisition to the i2c probe
2026-09-21 10:46 ` [PATCH 06/21] ASoC: es8323: " Chancel Liu
@ 2026-09-21 13:17 ` Mark Brown
2026-09-21 13:18 ` Mark Brown
0 siblings, 1 reply; 33+ messages in thread
From: Mark Brown @ 2026-09-21 13:17 UTC (permalink / raw)
To: Chancel Liu
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Charles Keepax,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
[-- Attachment #1: Type: text/plain, Size: 622 bytes --]
On Mon, Sep 21, 2026 at 07:46:25PM +0900, Chancel Liu wrote:
> From: Chancel Liu <chancel.liu@nxp.com>
>
> component->dev is the underlying i2c device whose devres is only
> released on physical device removal, not on ASoC card unbind. Getting
> the mclk with devm_clk_get_optional(component->dev, ...) in the
> component probe therefore leaks a clk reference on every card
> bind/unbind cycle.
>
> Move the devm_clk_get_optional() to es8323_i2c_probe() so the clk
> reference is tied to the i2c device lifetime.
There's also some devm memory allocations in the DT parser which is run
in component probe.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 06/21] ASoC: es8323: Move mclk acquisition to the i2c probe
2026-09-21 13:17 ` Mark Brown
@ 2026-09-21 13:18 ` Mark Brown
2026-09-22 2:18 ` Chancel Liu
0 siblings, 1 reply; 33+ messages in thread
From: Mark Brown @ 2026-09-21 13:18 UTC (permalink / raw)
To: Chancel Liu
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Charles Keepax,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
[-- Attachment #1: Type: text/plain, Size: 755 bytes --]
On Mon, Sep 21, 2026 at 03:17:07PM +0200, Mark Brown wrote:
> On Mon, Sep 21, 2026 at 07:46:25PM +0900, Chancel Liu wrote:
> > From: Chancel Liu <chancel.liu@nxp.com>
> >
> > component->dev is the underlying i2c device whose devres is only
> > released on physical device removal, not on ASoC card unbind. Getting
> > the mclk with devm_clk_get_optional(component->dev, ...) in the
> > component probe therefore leaks a clk reference on every card
> > bind/unbind cycle.
> >
> > Move the devm_clk_get_optional() to es8323_i2c_probe() so the clk
> > reference is tied to the i2c device lifetime.
>
> There's also some devm memory allocations in the DT parser which is run
> in component probe.
Sorry, meant to send this on the da7218.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 21/21] ASoC: rt5514-spi: Free the DSP context on component remove
2026-09-21 10:46 ` [PATCH 21/21] ASoC: rt5514-spi: Free the DSP context " Chancel Liu
@ 2026-09-21 13:23 ` Mark Brown
2026-09-22 2:31 ` Chancel Liu
0 siblings, 1 reply; 33+ messages in thread
From: Mark Brown @ 2026-09-21 13:23 UTC (permalink / raw)
To: Chancel Liu
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Charles Keepax,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
[-- Attachment #1: Type: text/plain, Size: 859 bytes --]
On Mon, Sep 21, 2026 at 07:46:40PM +0900, Chancel Liu wrote:
> 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);
Previously we would ignore the error and carry on without the IRQ, now
we pay attention. I don't know if the device actually worked or not.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 09/21] ASoC: rt5640: Move mclk acquisition to the i2c probe
2026-09-21 10:46 ` [PATCH 09/21] ASoC: rt5640: Move mclk acquisition to the i2c probe Chancel Liu
@ 2026-09-21 18:28 ` Cezary Rojewski
0 siblings, 0 replies; 33+ messages in thread
From: Cezary Rojewski @ 2026-09-21 18:28 UTC (permalink / raw)
To: Chancel Liu
Cc: Support Opensource, linux-sound, linux-kernel, patches,
Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
On 9/21/2026 12:46 PM, Chancel Liu wrote:
> From: Chancel Liu <chancel.liu@nxp.com>
>
> component->dev is the underlying i2c device whose devres is only
> released on physical device removal, not on ASoC card unbind. Getting
> the codec clock with devm_clk_get_optional(component->dev, ...) in the
> component probe therefore leaks a clk reference on every card
> bind/unbind cycle.
>
> Move the devm_clk_get_optional() to rt5640_i2c_probe() so the clk
> reference is tied to the physical device lifetime.
>
> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
> ---
> sound/soc/codecs/rt5640.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
> index 03d0ac3359f5..1a45346cf6b9 100644
> --- a/sound/soc/codecs/rt5640.c
> +++ b/sound/soc/codecs/rt5640.c
> @@ -2667,11 +2667,6 @@ static int rt5640_probe(struct snd_soc_component *component)
> bool dmic_en = false;
> u32 val;
>
> - /* Check if MCLK provided */
> - rt5640->mclk = devm_clk_get_optional(component->dev, "mclk");
> - if (IS_ERR(rt5640->mclk))
> - return PTR_ERR(rt5640->mclk);
> -
> rt5640->component = component;
>
> snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
> @@ -3053,6 +3048,11 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
> regmap_update_bits(rt5640->regmap, RT5640_GCTL1,
> RT5640_MCLK_DET, RT5640_MCLK_DET);
>
> + /* Check if MCLK provided */
> + rt5640->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
> + if (IS_ERR(rt5640->mclk))
> + return PTR_ERR(rt5640->mclk);
> +
> rt5640->hp_mute = true;
> rt5640->irq = i2c->irq;
> INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work);
nitpick: update the title tags so it starts with:
ASoC: codecs: rt5640:
Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 12/21] ASoC: rt5682s: Move mclk acquisition to the i2c probe
2026-09-21 10:46 ` [PATCH 12/21] ASoC: rt5682s: Move mclk " Chancel Liu
@ 2026-09-21 18:44 ` Cezary Rojewski
2026-09-22 2:34 ` Chancel Liu
0 siblings, 1 reply; 33+ messages in thread
From: Cezary Rojewski @ 2026-09-21 18:44 UTC (permalink / raw)
To: Chancel Liu
Cc: Support Opensource, linux-sound, linux-kernel, patches,
Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
On 9/21/2026 12:46 PM, Chancel Liu wrote:
> From: Chancel Liu <chancel.liu@nxp.com>
>
> component->dev is the underlying i2c device whose devres is only
> released on physical device removal, not on ASoC card unbind. Getting
> the codec clock with devm_clk_get_optional(component->dev, ...) in the
> component probe chain therefore leaks a clk reference on every card
> bind/unbind cycle.
>
> Move the devm_clk_get_optional() to rt5682s_i2c_probe() so the clk
> reference is tied to the physical device lifetime.
>
> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
Nitpick: Same as with rt5640 (and TBH all the patches here), updating
the title so it starts "ASoC: codecs: (...)" would be appreciated. Alone
not a reason for resend.
Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 15/21] ASoC: wm8985: Move regulator acquisition to the bus probe
2026-09-21 11:52 ` Charles Keepax
@ 2026-09-22 2:01 ` Chancel Liu
0 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-22 2:01 UTC (permalink / raw)
To: Charles Keepax
Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
Hi Charles,
Many thanks for your review.
On 9/21/2026 7:52 PM, Charles Keepax wrote:
> On Mon, Sep 21, 2026 at 07:46:34PM +0900, Chancel Liu wrote:
>> From: Chancel Liu <chancel.liu@nxp.com>
>>
>> component->dev is the underlying i2c/spi device whose devres is only
>> released on physical device removal, not on ASoC card unbind. Getting
>> the regulator supplies with devm_regulator_bulk_get(component->dev, ...)
>> in the component probe therefore leaks the regulator references on every
>> card bind/unbind cycle.
>>
>> Move the devm_regulator_bulk_get() into a helper called from the i2c and
>> spi probes so the supplies are tied to the physical device lifetime.
>>
>> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
>> ---
>> @@ -1176,6 +1178,12 @@ static int wm8985_spi_probe(struct spi_device *spi)
>> + ret = wm8985_get_regulators(&spi->dev, wm8985);
>> + if (ret) {
>> + dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
>> + return ret;
>> + }
>> @@ -1212,6 +1220,12 @@ static int wm8985_i2c_probe(struct i2c_client *i2c)
>> + ret = wm8985_get_regulators(&i2c->dev, wm8985);
>> + if (ret) {
>> + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
>> + return ret;
>> + }
>
> Probably slightly nicer to include the error message in the
> helper rather than duplicating it in each probe.
>
> Thanks,
> Charles
Agreed, It looks better this way. I'll improve it in the next revision.
Regards,
Chancel Liu
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 06/21] ASoC: es8323: Move mclk acquisition to the i2c probe
2026-09-21 13:18 ` Mark Brown
@ 2026-09-22 2:18 ` Chancel Liu
0 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-22 2:18 UTC (permalink / raw)
To: Mark Brown
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Charles Keepax,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
On 9/21/2026 9:18 PM, Mark Brown wrote:
> On Mon, Sep 21, 2026 at 03:17:07PM +0200, Mark Brown wrote:
>> On Mon, Sep 21, 2026 at 07:46:25PM +0900, Chancel Liu wrote:
>>> From: Chancel Liu <chancel.liu@nxp.com>
>>>
>>> component->dev is the underlying i2c device whose devres is only
>>> released on physical device removal, not on ASoC card unbind. Getting
>>> the mclk with devm_clk_get_optional(component->dev, ...) in the
>>> component probe therefore leaks a clk reference on every card
>>> bind/unbind cycle.
>>>
>>> Move the devm_clk_get_optional() to es8323_i2c_probe() so the clk
>>> reference is tied to the i2c device lifetime.
>>
>> There's also some devm memory allocations in the DT parser which is run
>> in component probe.
>
> Sorry, meant to send this on the da7218.
Thanks for pointing it out. I overlooked these extra devm allocations in
the da7218 component probe. I'll fix it in the next revision.
BTW, I've re-checked the other codecs in the series and didn't find the
same pattern.
Regards,
Chancel Liu
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 21/21] ASoC: rt5514-spi: Free the DSP context on component remove
2026-09-21 13:23 ` Mark Brown
@ 2026-09-22 2:31 ` Chancel Liu
0 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-22 2:31 UTC (permalink / raw)
To: Mark Brown
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Charles Keepax,
Oder Chiou, Support Opensource, linux-sound, linux-kernel,
patches
On 9/21/2026 9:23 PM, Mark Brown wrote:
> On Mon, Sep 21, 2026 at 07:46:40PM +0900, Chancel Liu wrote:
>> 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);
>
> Previously we would ignore the error and carry on without the IRQ, now
> we pay attention. I don't know if the device actually worked or not.
You're right, I'll keep the original behaviour in the next revision.
Regards,
Chancel Liu
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 12/21] ASoC: rt5682s: Move mclk acquisition to the i2c probe
2026-09-21 18:44 ` Cezary Rojewski
@ 2026-09-22 2:34 ` Chancel Liu
0 siblings, 0 replies; 33+ messages in thread
From: Chancel Liu @ 2026-09-22 2:34 UTC (permalink / raw)
To: Cezary Rojewski
Cc: Support Opensource, linux-sound, linux-kernel, patches,
Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Charles Keepax, Oder Chiou
On 9/22/2026 2:44 AM, Cezary Rojewski wrote:
> On 9/21/2026 12:46 PM, Chancel Liu wrote:
>> From: Chancel Liu <chancel.liu@nxp.com>
>>
>> component->dev is the underlying i2c device whose devres is only
>> released on physical device removal, not on ASoC card unbind. Getting
>> the codec clock with devm_clk_get_optional(component->dev, ...) in the
>> component probe chain therefore leaks a clk reference on every card
>> bind/unbind cycle.
>>
>> Move the devm_clk_get_optional() to rt5682s_i2c_probe() so the clk
>> reference is tied to the physical device lifetime.
>>
>> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
>
> Nitpick: Same as with rt5640 (and TBH all the patches here), updating
> the title so it starts "ASoC: codecs: (...)" would be appreciated. Alone
> not a reason for resend.
>
> Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
Many thanks for your review. I'll improve it in the next revision.
Regards,
Chancel Liu
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2026-09-22 2:35 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-21 10:46 [PATCH 00/21] ASoC: codecs: Fix resource leaks across card bind/unbind Chancel Liu
2026-09-21 10:46 ` [PATCH 01/21] ASoC: cpcap: Fix devm " Chancel Liu
2026-09-21 10:46 ` [PATCH 02/21] ASoC: da7218: " Chancel Liu
2026-09-21 10:46 ` [PATCH 03/21] ASoC: tlv320aic32x4: Fix clock leak from runtime callbacks Chancel Liu
2026-09-21 10:46 ` [PATCH 04/21] ASoC: twl4030: Acquire board params and hs_extmute GPIO in the platform probe Chancel Liu
2026-09-21 10:46 ` [PATCH 05/21] ASoC: es8316: Move mclk acquisition to the i2c probe Chancel Liu
2026-09-21 10:46 ` [PATCH 06/21] ASoC: es8323: " Chancel Liu
2026-09-21 13:17 ` Mark Brown
2026-09-21 13:18 ` Mark Brown
2026-09-22 2:18 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 07/21] ASoC: es8311: " Chancel Liu
2026-09-21 10:46 ` [PATCH 08/21] ASoC: es8328: Move clk acquisition to the bus probe Chancel Liu
2026-09-21 10:46 ` [PATCH 09/21] ASoC: rt5640: Move mclk acquisition to the i2c probe Chancel Liu
2026-09-21 18:28 ` Cezary Rojewski
2026-09-21 10:46 ` [PATCH 10/21] ASoC: rt5616: " Chancel Liu
2026-09-21 10:46 ` [PATCH 11/21] ASoC: rt5514: Move clk " Chancel Liu
2026-09-21 10:46 ` [PATCH 12/21] ASoC: rt5682s: Move mclk " Chancel Liu
2026-09-21 18:44 ` Cezary Rojewski
2026-09-22 2:34 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 13/21] ASoC: max98090: " Chancel Liu
2026-09-21 10:46 ` [PATCH 14/21] ASoC: max98095: " Chancel Liu
2026-09-21 10:46 ` [PATCH 15/21] ASoC: wm8985: Move regulator acquisition to the bus probe Chancel Liu
2026-09-21 11:52 ` Charles Keepax
2026-09-22 2:01 ` Chancel Liu
2026-09-21 10:46 ` [PATCH 16/21] ASoC: wm8955: Move regulator acquisition to the i2c probe Chancel Liu
2026-09-21 10:58 ` Charles Keepax
2026-09-21 10:46 ` [PATCH 17/21] ASoC: es8389: Move regulator and mclk " Chancel Liu
2026-09-21 10:46 ` [PATCH 18/21] ASoC: rt5677-spi: Free the DSP context on component remove Chancel Liu
2026-09-21 10:46 ` [PATCH 19/21] ASoC: rt1011: Free the bq/drc coefficient arrays " Chancel Liu
2026-09-21 10:46 ` [PATCH 20/21] ASoC: rt5645: Free the hardware EQ parameters " Chancel Liu
2026-09-21 10:46 ` [PATCH 21/21] ASoC: rt5514-spi: Free the DSP context " Chancel Liu
2026-09-21 13:23 ` Mark Brown
2026-09-22 2:31 ` Chancel Liu
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®