Skip to contentSkip to conversation

ASoC: adau1372: Fix error handling in adau1372_set_power()

PATCH In review Jihed Chaibi 3 participants 8 messages Mar 25 – Mar 26

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v2 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 full unwind in adau1372_set_power() if PLL lock fails, reversing the regcache, GPIO power-down, and clock state.

Changes in v2:
- [1/2]: No changes.
- [2/2]: Also unwind regcache and GPIO power-down state on PLL lock failure, as noted by Mark Brown.

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 | 34 ++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 10 deletions(-)

--
2.47.3

#1 lore raw

PATCH v2 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.

---
Changes in v2:
- No changes.

 sound/soc/codecs/adau1372.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
sound/soc/codecs/adau1372.c +10 -7
index fdee689cae53..6345342218d6 100644
@@ -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;

--
2.47.3

#2 lore raw

Re: [PATCH v2 1/2] ASoC: adau1372: Fix unchecked clk_prepare_enable() return value

Quoted 10 lines · Jihed Chaibi

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.

---

No Fixes tag?

- Nuno Sá

Quoted 57 lines

Changes in v2:
- No changes.

 sound/soc/codecs/adau1372.c | 17 ++++++++++-------

 1 file changed, 10 insertions(+), 7 deletions(-)
sound/soc/codecs/adau1372.c +8 -3
index fdee689cae53..6345342218d6 100644
@@ -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:

sound/soc/codecs/adau1372.c +1 -2
-		adau1372_set_power(adau1372, true);
-		break;
+		return adau1372_set_power(adau1372, true);

  case SND_SOC_BIAS_OFF:

sound/soc/codecs/adau1372.c +1 -2
-		adau1372_set_power(adau1372, false);
-		break;
+		return adau1372_set_power(adau1372, false);

  }

  return 0;
--
2.47.3

#3 lore raw

PATCH v2 2/2 ASoC: adau1372: Fix clock leak on PLL lock failure

In reply to Jihed Chaibi

adau1372_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 unwind in reverse order: restore regcache to cache-only mode, reassert GPIO power-down, and disable the clock before returning the error.

---
Changes in v2:
- Also unwind regcache and GPIO power-down state on PLL lock failure, as noted by Mark Brown.

 sound/soc/codecs/adau1372.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)
sound/soc/codecs/adau1372.c +14 -3
index 6345342218d6..e3eba241bdf7 100644
@@ -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,14 @@ 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) {
+				regcache_cache_only(adau1372->regmap, true);
+				if (adau1372->pd_gpio)
+					gpiod_set_value(adau1372->pd_gpio, 1);
+				clk_disable_unprepare(adau1372->mclk);
+				return ret;
+			}
 			clk_ctrl |= ADAU1372_CLK_CTRL_CLKSRC;
 		}
 

--
2.47.3

#4 lore raw

Re: [PATCH v2 2/2] ASoC: adau1372: Fix clock leak on PLL lock failure

Quoted 6 lines · Jihed Chaibi

adau1372_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.

Quoted 8 lines

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 unwind in reverse order: restore regcache to cache-only mode, reassert GPIO power-down, and disable the clock before returning the error.

---

Also deserves a Fixes tag IMO.

Quoted 53 lines

Changes in v2:
- Also unwind regcache and GPIO power-down state on PLL lock failure, as noted by Mark Brown.

 sound/soc/codecs/adau1372.c | 17 ++++++++++++++---

 1 file changed, 14 insertions(+), 3 deletions(-)
sound/soc/codecs/adau1372.c +0 -0
index 6345342218d6..e3eba241bdf7 100644
@@ -762,7 +762,7 @@ static int adau1372_startup(struct snd_pcm_substream *substream, struct

snd_soc_
  return 0;
 }

sound/soc/codecs/adau1372.c +1 -1
-static void adau1372_enable_pll(struct adau1372 *adau1372)
+static int adau1372_enable_pll(struct adau1372 *adau1372)

 {
  unsigned int val, timeout = 0;
  int ret;

sound/soc/codecs/adau1372.c +13 -3
@@ -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,14 @@ 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) {
+				regcache_cache_only(adau1372->regmap, true);
+				if (adau1372->pd_gpio)
+					gpiod_set_value(adau1372->pd_gpio, 1);
+				clk_disable_unprepare(adau1372->mclk);
+				return ret;
+			}
  			clk_ctrl |= ADAU1372_CLK_CTRL_CLKSRC;
  		}
 
--

2.47.3

Reviewed-by on the v2 series
#5 lore raw
In reply to Jihed Chaibi
Quoted 22 lines · Jihed Chaibi

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 full unwind in adau1372_set_power() if PLL lock fails, reversing the regcache, GPIO power-down, and clock state.

Changes in v2:
- [1/2]: No changes.
- [2/2]: Also unwind regcache and GPIO power-down state on PLL lock failure, as noted by Mark Brown.

Jihed Chaibi (2):
  ASoC: adau1372: Fix unchecked clk_prepare_enable() return value
  ASoC: adau1372: Fix clock leak on PLL lock failure

Quoted 5 lines

 sound/soc/codecs/adau1372.c | 34 ++++++++++++++++++++++-----------

 1 file changed, 24 insertions(+), 10 deletions(-)

--
2.47.3

With proper tags:

#6 lore raw
Quoted 27 lines · Nuno Sá
Quoted 25 lines · Jihed Chaibi

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 full unwind in adau1372_set_power() if PLL lock fails, reversing the regcache, GPIO power-down, and clock state.

Changes in v2:
- [1/2]: No changes.
- [2/2]: Also unwind regcache and GPIO power-down state on PLL lock failure, as noted by Mark Brown.

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 | 34 ++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 10 deletions(-)
Quoted 6 lines
Quoted 2 lines

--
2.47.3

With proper tags:

Thanks for the review, Nuno.

Fixes tags for the series:

[v2 1/2] ASoC: adau1372: Fix unchecked clk_prepare_enable() return value

Fixes 6cd4c6459e47 ("ASoC: Add ADAU1372 audio CODEC support")

[v2 2/2] ASoC: adau1372: Fix clock leak on PLL lock failure

Fixes 6cd4c6459e47 ("ASoC: Add ADAU1372 audio CODEC support")
maintainer
#7 lore raw
In reply to Jihed Chaibi
Quoted 9 lines · Jihed Chaibi

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.

[...]

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.0

Thanks!

[1/2] ASoC: adau1372: Fix unchecked clk_prepare_enable() return value

      https://git.kernel.org/broonie/sound/c/326fe8104a40
[2/2] ASoC: adau1372: Fix clock leak on PLL lock failure
      https://git.kernel.org/broonie/sound/c/bfe6a264effc

All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying to this mail.

Thanks,
Mark