mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
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: 4f9c16ccfa ("[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>
This commit is contained in:
parent
1a3c8e2895
commit
fdf043f5f3
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user