diff options
| author | Sen Wang <sen@ti.com> | 2026-06-16 18:33:22 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-06-17 14:56:31 +0100 |
| commit | fdf043f5f3bae150b678feae3d7bb1beed87ec14 (patch) | |
| tree | 43aba14e740d62a376c76a1db892beef8f5a2868 /sound | |
| parent | 1a3c8e28959790ae3e06029681418278b7821a3c (diff) | |
| download | ath-fdf043f5f3bae150b678feae3d7bb1beed87ec14.tar.gz | |
ASoC: tlv320aic3x: restrict CLKDIV bypass Q values in dual-rate mode
The datasheet documents that when the PLL is disabled and dual-rate mode
is enabled, only Q values {4, 8, 9, 12, 16} are valid for the CLKDIV
bypass path; all other Q values produce invalid bitclock output.
The existing loop iterates Q from 2 to 17 without this restriction,
causing silent audio failure when an out-of-spec Q is picked.
Restrict the Q search to the allowed set in dual-rate mode.
Fixes: 4f9c16ccfa26 ("[ALSA] soc - tlv320aic3x - revisit clock setup")
Suggested-by: Mir Jeffres <m-jeffres@ti.com>
Signed-off-by: Sen Wang <sen@ti.com>
Link: https://patch.msgid.link/20260616233322.873081-1-sen@ti.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
| -rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b12c1952823ba..b38393a8130ff 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1049,11 +1049,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + static const u8 dual_rate_q[] = {4, 8, 9, 12, 16}; struct snd_soc_component *component = dai->component; struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component); int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; u16 d, pll_d = 1; + bool dual_rate; int clk; int width = aic3x->slot_width; @@ -1079,14 +1081,25 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, /* Fsref can be 44100 or 48000 */ fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; + dual_rate = params_rate(params) >= 64000; /* Try to find a value for Q which allows us to bypass the PLL and * generate CODEC_CLK directly. */ - for (pll_q = 2; pll_q < 18; pll_q++) - if (aic3x->sysclk / (128 * pll_q) == fsref) { - bypass_pll = 1; - break; + if (dual_rate) { + for (int i = 0; i < ARRAY_SIZE(dual_rate_q); i++) { + pll_q = dual_rate_q[i]; + if (aic3x->sysclk / (128 * pll_q) == fsref) { + bypass_pll = 1; + break; + } } + } else { + for (pll_q = 2; pll_q < 18; pll_q++) + if (aic3x->sysclk / (128 * pll_q) == fsref) { + bypass_pll = 1; + break; + } + } if (bypass_pll) { pll_q &= 0xf; @@ -1106,13 +1119,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, * right DAC to right channel input */ data = (LDAC2LCH | RDAC2RCH); data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; - if (params_rate(params) >= 64000) + if (dual_rate) data |= DUAL_RATE_MODE; snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data); /* codec sample rate select */ data = (fsref * 20) / params_rate(params); - if (params_rate(params) < 64000) + if (!dual_rate) data /= 2; data /= 5; data -= 2; |
