Yuhang Zheng

wm8960砰砰声时钟问题排查

N 人看过

背景:

这篇文章接上一篇问题继续排查,这次硬件的同事帮忙量了一下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设备工作不正常。

img

在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;
        }
    ...
    ...
}

img

可以看到驱动中优先使用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。