wm8960砰砰声时钟问题排查
背景:
这篇文章接上一篇问题继续排查,这次硬件的同事帮忙量了一下SYSCLK的时钟,发现当MCLK为24MHz的时候,SYSCLK为22.5792MHz。当MCLK为12MHz的时候,SYSCLK才是我们预计想要的11.2896MHz。
但是通过手册我们可以看到,客户使用的是Class D类设备,也就是Speaker喇叭,而Class D设备需要的时钟为500kHz~1MHz,最优时钟频率为768kHz,DCLKDIV[2:0]的最大分频为16,所以SYSCLK最优时钟为768kHz x16=12.288MHz,最大时钟为1MHz x16=16HMz,但是我们实测SYSCLK已经达到了22.5792MHz,所以造成了Class D设备工作不正常。
在Linux内核驱动文件./sound/soc/codecs/wm8960.c中
static const int sysclk_divs[] = { 1, -1, 2, -1 };
static int wm8960_configure_clocking(struct snd_soc_codec *codec)
{
...
...
/* check if the sysclk frequency is available. */
for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
if (sysclk_divs[i] == -1)
continue;
sysclk = freq_out / sysclk_divs[i];
for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
if (sysclk == dac_divs[j] * lrclk) {
for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
if (sysclk == bclk * bclk_divs[k] / 10)
break;
if (k != ARRAY_SIZE(bclk_divs))
break;
}
}
if (j != ARRAY_SIZE(dac_divs))
break;
}
...
...
}
可以看到驱动中优先使用SYSCLKDIV为1分频的情况进行测试计算。
驱动通过它默认的逻辑计算完成之后,当SYSCLK为22.5792MHz可以满足采样率为44.1KHz的需求,所以它优先采用了此种时钟设置方案,没有考虑Class D设备的工作需求。才导致了问题。
解决方案:
可以将Linux内核驱动文件./sound/soc/codecs/wm8960.c中的
/* -1 for reserved value */
static const int sysclk_divs[] = { 1, -1, 2, -1 };
改为
/* -1 for reserved value */
static const int sysclk_divs[] = { -1, -1, 2, -1 };
使驱动程序在使用sysclk_divs[0]计算的时候无法计算通过,这样它就会采用sysclk_divs[2]的二分频算法进行计算,这样SYSCLK就会变成11.2896MHz。