Skip to content

Commit a8075ad

Browse files
SenWang125broonie
authored andcommitted
ASoC: ti: davinci-mcasp: improve aux_div selection for mid-range dividers
When the ideal total divider (sysclk/bclk) is between 33 and 4096 and AUXCLK is enabled, the driver computes aux_div as ceil(div/32) and then recomputes bclk_div from the truncated sysclk. This two-step integer division loses precision due to truncation and can sometimes produce PPM errors large enough for ALSA's hw_rule_format to reject otherwise valid sample formats. For example, on AM62D-EVM (auxclk-fs-ratio=2177, tdm-slots=2, fck=96 MHz), playing S16_LE at 44100 Hz gives BCLK = 1,411,200 Hz and an ideal total divider of 68. The old code picks aux_div = ceil(68/32) = 3, then bclk_div = (96005700/3) / 1411200 = 22, for a total of 3 x 22 = 66 -- two steps from ideal. The resulting error exceeds the PPM threshold and causes S16_LE, S24_LE to be rejected. Therefore when the total divider fits in the AHCLKXDIV register alone (<=4096), use it directly as aux_div with bclk_div=1, and compare floor and ceil to pick the closer match, to ensure the best ideal total dividers. Dividers at or below 32 never enter this path, and dividers above 4096 still fall through to the existing DIV_ROUND_UP path, so previously working configurations remains unaffected. Signed-off-by: Sen Wang <sen@ti.com> Link: https://patch.msgid.link/20260305195825.9998-3-sen@ti.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 5bebbfd commit a8075ad

1 file changed

Lines changed: 22 additions & 12 deletions

File tree

sound/soc/ti/davinci-mcasp.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,19 +1358,29 @@ static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
13581358
auxclk_div_id = MCASP_CLKDIV_AUXCLK;
13591359
}
13601360

1361-
if (div > (ACLKXDIV_MASK + 1)) {
1362-
if (auxclk_enabled) {
1363-
aux_div = div / (ACLKXDIV_MASK + 1);
1364-
if (div % (ACLKXDIV_MASK + 1))
1365-
aux_div++;
1366-
1367-
sysclk_freq /= aux_div;
1368-
div = sysclk_freq / bclk_freq;
1369-
rem = sysclk_freq % bclk_freq;
1370-
} else if (set) {
1371-
dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
1372-
sysclk_freq);
1361+
if (div > (ACLKXDIV_MASK + 1) && auxclk_enabled) {
1362+
if (div <= (AHCLKXDIV_MASK + 1)) {
1363+
/* aux_div absorbs entire division; bclk_div = 1 */
1364+
aux_div = div;
1365+
if ((div + 1) <= (AHCLKXDIV_MASK + 1)) {
1366+
unsigned int err_lo = sysclk_freq / div -
1367+
bclk_freq;
1368+
unsigned int err_hi = bclk_freq -
1369+
sysclk_freq / (div + 1);
1370+
1371+
if (err_hi < err_lo)
1372+
aux_div = div + 1;
1373+
}
1374+
} else {
1375+
aux_div = DIV_ROUND_UP(div, ACLKXDIV_MASK + 1);
13731376
}
1377+
1378+
sysclk_freq /= aux_div;
1379+
div = sysclk_freq / bclk_freq;
1380+
rem = sysclk_freq % bclk_freq;
1381+
} else if (div > (ACLKXDIV_MASK + 1) && set) {
1382+
dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
1383+
sysclk_freq);
13741384
}
13751385

13761386
if (rem != 0) {

0 commit comments

Comments
 (0)