From 1e5351ba60f5355809f30c61bbd27e97611d2be9 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Wed, 29 Oct 2025 10:39:18 +0100 Subject: [PATCH 1/3] ASoC: cs4271: Disable regulators in component_probe() error path The commit 9a397f473657 ("ASoC: cs4271: add regulator consumer support") has introduced regulators in the driver. Regulators are enabled at the beginning of component_probe() but they are not disabled on errors. This can lead to unbalanced enable/disable. Fix the error path to disable regulators on errors. Fixes: 9a397f473657 ("ASoC: cs4271: add regulator consumer support") Cc: stable@vger.kernel.org Signed-off-by: Herve Codina Reviewed-by: Alexander Sverdlin Link: https://patch.msgid.link/20251029093921.624088-3-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 0ed73ba3625c..f636900e0c1a 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -581,17 +581,17 @@ static int cs4271_component_probe(struct snd_soc_component *component) ret = regcache_sync(cs4271->regmap); if (ret < 0) - return ret; + goto err_disable_regulators; ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, CS4271_MODE2_PDN | CS4271_MODE2_CPEN, CS4271_MODE2_PDN | CS4271_MODE2_CPEN); if (ret < 0) - return ret; + goto err_disable_regulators; ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, CS4271_MODE2_PDN, 0); if (ret < 0) - return ret; + goto err_disable_regulators; /* Power-up sequence requires 85 uS */ udelay(85); @@ -601,6 +601,10 @@ static int cs4271_component_probe(struct snd_soc_component *component) CS4271_MODE2_MUTECAEQUB); return 0; + +err_disable_regulators: + regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies); + return ret; } static void cs4271_component_remove(struct snd_soc_component *component) From 3cd523ba270665861647304aa30500f238ebf26e Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Wed, 29 Oct 2025 10:39:19 +0100 Subject: [PATCH 2/3] ASoC: dt-bindings: cirrus,cs4271: Document mclk clock The Cirrus CS4271 codec can use an external clock as an input Master Clock. When no crystal is used, the CS4271 component considers its MCLK pin as an input pin and expects the external clock connected to provide the Master Clock. This clock is not documented in the binding. Add the missing clock. Signed-off-by: Herve Codina Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251029093921.624088-4-herve.codina@bootlin.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cirrus,cs4271.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml index 68fbf5cc208f..d286eb169915 100644 --- a/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml +++ b/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml @@ -25,6 +25,16 @@ properties: reg: maxItems: 1 + clocks: + items: + - description: + Master clock connected to the MCLK pin if MCLK is an input (i.e. no + crystal used). + + clock-names: + items: + - const: mclk + spi-cpha: true spi-cpol: true From cf6bf51b53252284bafc7377a4d8dbf10f048b4d Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Wed, 29 Oct 2025 10:39:20 +0100 Subject: [PATCH 3/3] ASoC: cs4271: Add support for the external mclk The mclk (master clock) of the cs4271 codec can be an input clock. In this case the connected clock needs to be enabled outside of any audio stream. Indeed, this clock is needed for i2c communication. Add support of this clock and enable it before the first i2c transfer. Signed-off-by: Herve Codina Reviewed-by: Alexander Sverdlin Link: https://patch.msgid.link/20251029093921.624088-5-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index f636900e0c1a..a24e926ba282 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -10,6 +10,7 @@ * DAPM support not implemented. */ +#include #include #include #include @@ -163,6 +164,7 @@ struct cs4271_private { /* enable soft reset workaround */ bool enable_soft_reset; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + struct clk *clk; }; static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = { @@ -505,6 +507,7 @@ static int cs4271_soc_suspend(struct snd_soc_component *component) return ret; regcache_mark_dirty(cs4271->regmap); + clk_disable_unprepare(cs4271->clk); regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies); return 0; @@ -522,6 +525,12 @@ static int cs4271_soc_resume(struct snd_soc_component *component) return ret; } + ret = clk_prepare_enable(cs4271->clk); + if (ret) { + dev_err(component->dev, "Failed to enable clk: %d\n", ret); + return ret; + } + /* Do a proper reset after power up */ cs4271_reset(component); @@ -576,22 +585,29 @@ static int cs4271_component_probe(struct snd_soc_component *component) cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; } + ret = clk_prepare_enable(cs4271->clk); + if (ret) { + dev_err(component->dev, "Failed to enable clk: %d\n", ret); + goto err_disable_regulators; + } + /* Reset codec */ cs4271_reset(component); ret = regcache_sync(cs4271->regmap); if (ret < 0) - goto err_disable_regulators; + goto err_disable_clk; ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, CS4271_MODE2_PDN | CS4271_MODE2_CPEN, CS4271_MODE2_PDN | CS4271_MODE2_CPEN); if (ret < 0) - goto err_disable_regulators; + goto err_disable_clk; ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, CS4271_MODE2_PDN, 0); if (ret < 0) - goto err_disable_regulators; + goto err_disable_clk; + /* Power-up sequence requires 85 uS */ udelay(85); @@ -602,6 +618,8 @@ static int cs4271_component_probe(struct snd_soc_component *component) return 0; +err_disable_clk: + clk_disable_unprepare(cs4271->clk); err_disable_regulators: regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies); return ret; @@ -616,6 +634,7 @@ static void cs4271_component_remove(struct snd_soc_component *component) regcache_mark_dirty(cs4271->regmap); regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies); + clk_disable_unprepare(cs4271->clk); }; static const struct snd_soc_component_driver soc_component_dev_cs4271 = { @@ -650,6 +669,10 @@ static int cs4271_common_probe(struct device *dev, "error retrieving RESET GPIO\n"); gpiod_set_consumer_name(cs4271->reset, "CS4271 Reset"); + cs4271->clk = devm_clk_get_optional(dev, "mclk"); + if (IS_ERR(cs4271->clk)) + return dev_err_probe(dev, PTR_ERR(cs4271->clk), "Failed to get mclk\n"); + for (i = 0; i < ARRAY_SIZE(supply_names); i++) cs4271->supplies[i].supply = supply_names[i];