Skip to content

Commit a6d0abb

Browse files
SenWang125gregkh
authored andcommitted
ASoC: tlv320aic3x: restrict CLKDIV bypass Q values in dual-rate mode
[ Upstream commit fdf043f ] 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: 4f9c16c ("[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> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent efa9e3b commit a6d0abb

1 file changed

Lines changed: 19 additions & 6 deletions

File tree

sound/soc/codecs/tlv320aic3x.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,11 +1049,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
10491049
struct snd_pcm_hw_params *params,
10501050
struct snd_soc_dai *dai)
10511051
{
1052+
static const u8 dual_rate_q[] = {4, 8, 9, 12, 16};
10521053
struct snd_soc_component *component = dai->component;
10531054
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
10541055
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
10551056
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
10561057
u16 d, pll_d = 1;
1058+
bool dual_rate;
10571059
int clk;
10581060
int width = aic3x->slot_width;
10591061

@@ -1079,14 +1081,25 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
10791081

10801082
/* Fsref can be 44100 or 48000 */
10811083
fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
1084+
dual_rate = params_rate(params) >= 64000;
10821085

10831086
/* Try to find a value for Q which allows us to bypass the PLL and
10841087
* generate CODEC_CLK directly. */
1085-
for (pll_q = 2; pll_q < 18; pll_q++)
1086-
if (aic3x->sysclk / (128 * pll_q) == fsref) {
1087-
bypass_pll = 1;
1088-
break;
1088+
if (dual_rate) {
1089+
for (int i = 0; i < ARRAY_SIZE(dual_rate_q); i++) {
1090+
pll_q = dual_rate_q[i];
1091+
if (aic3x->sysclk / (128 * pll_q) == fsref) {
1092+
bypass_pll = 1;
1093+
break;
1094+
}
10891095
}
1096+
} else {
1097+
for (pll_q = 2; pll_q < 18; pll_q++)
1098+
if (aic3x->sysclk / (128 * pll_q) == fsref) {
1099+
bypass_pll = 1;
1100+
break;
1101+
}
1102+
}
10901103

10911104
if (bypass_pll) {
10921105
pll_q &= 0xf;
@@ -1106,13 +1119,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
11061119
* right DAC to right channel input */
11071120
data = (LDAC2LCH | RDAC2RCH);
11081121
data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
1109-
if (params_rate(params) >= 64000)
1122+
if (dual_rate)
11101123
data |= DUAL_RATE_MODE;
11111124
snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
11121125

11131126
/* codec sample rate select */
11141127
data = (fsref * 20) / params_rate(params);
1115-
if (params_rate(params) < 64000)
1128+
if (!dual_rate)
11161129
data /= 2;
11171130
data /= 5;
11181131
data -= 2;

0 commit comments

Comments
 (0)