ASoC: adau1372: Fix error handling in adau1372_set_power()
Subsystems (3)
cover ASoC: adau1372: Fix error handling in adau1372_set_power()
adau1372_set_power() had two related error handling issues in its enable
path: clk_prepare_enable() was called but its return value discarded, and adau1372_enable_pll() was a void function that silently swallowed lock failures, leaving mclk enabled and adau1372->enabled set to true despite the device being in a broken state.
Patch 1 fixes the unchecked clk_prepare_enable() by making adau1372_set_power() return int and propagating the error.
Patch 2 converts adau1372_enable_pll() to return int and adds a clk_disable_unprepare() unwind in adau1372_set_power() if PLL lock fails.
Jihed Chaibi (2):
ASoC: adau1372: Fix unchecked clk_prepare_enable() return value
ASoC: adau1372: Fix clock leak on PLL lock failure
sound/soc/codecs/adau1372.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-)
Signature · 1 line
2.47.3
PATCH 1/2 ASoC: adau1372: Fix unchecked clk_prepare_enable() return value
adau1372_set_power() calls clk_prepare_enable() but discards the return value. If the clock enable fails, the driver proceeds to access registers on unpowered hardware, potentially causing silent corruption.
Make adau1372_set_power() return int and propagate the error from clk_prepare_enable(). Update adau1372_set_bias_level() to return the error directly for the STANDBY and OFF cases.
--- sound/soc/codecs/adau1372.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
sound/soc/codecs/adau1372.c +10 -7
@@ -782,15 +782,18 @@ static void adau1372_enable_pll(struct adau1372 *adau1372)dev_err (adau1372->dev,"Failed to lock PLL\n" ); } -static void adau1372_set_power (struct adau1372 *adau1372,bool enable) +static int adau1372_set_power (struct adau1372 *adau1372,bool enable) {if (adau1372->enabled == enable) -return ; +return 0 ;if (enable) {unsigned int clk_ctrl =ADAU1372_CLK_CTRL_MCLK_EN ; +int ret; -clk_prepare_enable (adau1372->mclk); + ret =clk_prepare_enable (adau1372->mclk); +if (ret) +return ret;if (adau1372->pd_gpio)gpiod_set_value (adau1372->pd_gpio,0 );
@@ -829,6 +832,8 @@ static void adau1372_set_power(struct adau1372 *adau1372, bool enable) } adau1372->enabled = enable; + +return 0 ; } static int adau1372_set_bias_level(struct snd_soc_component *component,
@@ -842,11 +847,9 @@ static int adau1372_set_bias_level(struct snd_soc_component *component,case SND_SOC_BIAS_PREPARE :break ;case SND_SOC_BIAS_STANDBY : -adau1372_set_power (adau1372, true); -break ; +return adau1372_set_power (adau1372, true);case SND_SOC_BIAS_OFF : -adau1372_set_power (adau1372, false); -break ; +return adau1372_set_power (adau1372, false); }return 0 ;
Signature · 1 line
2.47.3
PATCH 2/2 ASoC: adau1372: Fix clock leak on PLL lock failure
In reply to Jihed Chaibiadau1372_enable_pll() was a void function that logged a dev_err() on PLL lock timeout but did not propagate the error. As a result, adau1372_set_power() would continue with adau1372->enabled set to true despite the PLL being unlocked, and the mclk left enabled with no corresponding disable on the error path.
Convert adau1372_enable_pll() to return int, using -ETIMEDOUT on lock timeout and propagating regmap errors directly. In adau1372_set_power(), check the return value and call clk_disable_unprepare() to unwind the already-enabled mclk before returning the error.
--- sound/soc/codecs/adau1372.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
sound/soc/codecs/adau1372.c +11 -3
@@ -762,7 +762,7 @@ static int adau1372_startup(struct snd_pcm_substream *substream, struct snd_soc_return 0 ; } -static void adau1372_enable_pll (struct adau1372 *adau1372) +static int adau1372_enable_pll (struct adau1372 *adau1372) {unsigned int val, timeout =0 ;int ret;
@@ -778,8 +778,12 @@ static void adau1372_enable_pll(struct adau1372 *adau1372) timeout++; }while (!(val &1 ) && timeout <3 ); -if (ret <0 || !(val &1 )) +if (ret <0 || !(val &1 )) {dev_err (adau1372->dev,"Failed to lock PLL\n" ); +return ret <0 ? ret : -ETIMEDOUT ; + } + +return 0 ; }static int adau1372_set_power (struct adau1372 *adau1372,bool enable)
@@ -807,7 +811,11 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)* accessed. */ if (adau1372->use_pll) { -adau1372_enable_pll (adau1372); + ret =adau1372_enable_pll (adau1372); +if (ret) { +clk_disable_unprepare (adau1372->mclk); +return ret; + } clk_ctrl |=ADAU1372_CLK_CTRL_CLKSRC ; }
Signature · 1 line
2.47.3
Mark Brown
maintainerRe: [PATCH 2/2] ASoC: adau1372: Fix clock leak on PLL lock failure
sound/soc/codecs/adau1372.c static int adau1372_set_power(struct adau1372 *adau1372, bool enable) · line 819
Quoted 11 lines · Jihed Chaibi
sound/soc/codecs/adau1372.c +5
-1@@ -807,7 +811,11 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)* accessed. */ if (adau1372->use_pll) { -adau1372_enable_pll (adau1372); + ret =adau1372_enable_pll (adau1372); +if (ret) { +clk_disable_unprepare (adau1372->mclk); +return ret; + } clk_ctrl |=ADAU1372_CLK_CTRL_CLKSRC ;
This disables the clock but we also put the cache into writable mode and deasserted reset, those need to be unwound too.