E103-W20添加WM8978声卡

前言

在很久之前我看到MT7628AN有i2s接口,于是买了一块WM8978G模块.但因为某些原因,该功能一直没有实现,在国庆期间闲来无事,进行了一番调试,在此记录.

设备环境

  • 模组/开发板:E103-W20路由器,具体参考我的工程:E103-W20路由器
  • 音频模组:W8978G模组,淘宝极客科技店铺购买
  • 系统:OpenWrt 21.02

硬件连接

WM8978                    MT2628
DAT(I2C_SDI/eX_sd)      I2C_SDI
MCK(I2S_MCLK)           I2S_MCLK(refclk)
SCK(I2S_SCLK/BCLK)      I2S_SCK
SDB(I2C_SDO/SD)         I2C_SDO
FSA(I2S_LRC/WS)         I2S_WS

SCL(I2C_SCL)            I2C_SCL
SDA(I2C_SDA)            I2C_SDA


请注意,MT7628没有I2S_MCLK引脚,这里用的是MT7628的REF_CLKO引脚来代替MCLK.
MT7628的REF_CLKO引脚默认功能是12Mhz参考时钟输出.

设备树实现

// 请在'/'根节点添加以下内容
    sound {
        compatible = "simple-audio-card";
        simple-audio-card,name = "WM8978-Sound-Card";
        simple-audio-card,format = "i2s";

        simple-audio-card,bitclock-master = <&codec_dai>;
        simple-audio-card,frame-master = <&codec_dai>;

        simple-audio-card,mclk-fs = <256>;

        cpu_dai: simple-audio-card,cpu {
            sound-dai = <&i2s>;
        };

        codec_dai: simple-audio-card,codec {
            sound-dai = <&wm8978>;
        };
    };
    
//在根节点外添加或者修改以下内容
&i2c {
    status = "okay";
    clock-frequency = <400000>;

    wm8978: wm8978@1a {
        status = "okay";
        compatible = "wlf,wm8978";
        reg = <0x1a>;
        #sound-dai-cells = <0>;
    };

};

&i2s {
    status = "okay";

    #sound-dai-cells = <0>;
    pinctrl-names = "default";
    pinctrl-0 = <&i2s_pins>, <&refclk_pins>;
};

项目编译

因为Openwrt没有提供kmod-soc-wm8978之类的包,所以需要我们在内核中配置.
使用make kernel_menuconfig打开内核配置
请参考以下配置来打开WM8978支持.在这里,我配置的是把WM8978编译成内核模块方便调试,实际可以编译到内核里.

Device Drivers -> I2C support -> <*>I2C Support
Device Drivers -> <*>Sound Card Support -> <*>Advanced Linux Sound Architecture ->
    <*>   Sound hardware support
    [*]   Enable OSS Emulation
    [*]   MIPS sound devices  ----
    <*>   ALSA for SoC audio support  --->
        <*>   SoC Audio (I2S protocol) for Ralink SoC
        <*>   ASoC Simple sound card support
        CODEC drivers  --->
            <M> Wolfson Microelectronics WM8978 codec

使用make menuconfig打开Openwrt配置
请参考以下配置,kmod-usb-audio用于外接usb声卡,可以选择不编译.

Kernel modules -> I2C support ->
                        -*- kmod-i2c-core
                        <*> kmod-i2c-mt7628
Kernel modules -> Sound Support ->
                    -*- kmod-sound-core
                    -*-   kmod-ac97
                    <*>   kmod-sound-mt7620
                    -*-   kmod-sound-soc-core
                    <*>   kmod-usb-audio
Sound -> <*> alsa-utils

使用make -j32来编译整个系统.编译完成之后,固件位于以下目录:
Openwrt-21.02/bin/targets/ramips/mt76x8/openwrt-ramips-mt76x8-hilink_hlk-7628n-squashfs-sysupgrade.bin

请在刷写完成新固件之后进行下一步.

调试

如果一切顺利,你可以在dmesg日志里看到以下被标注出来的输出:

root@LAPTOP-BQECF4:~# dmesg | grep -E "(i2s|wm89)"
[    0.875233] rt2880-pinmux pinctrl: i2s is already enabled
[    0.898742] rt2880-pinmux pinctrl: i2s is already enabled
[    4.234765] rt2880-pinmux pinctrl: i2s is already enabled
[    4.400733] rt2880-pinmux pinctrl: i2s is already enabled
[    4.576246] rt2880-pinmux pinctrl: i2s is already enabled
[    4.632818] rt2880-pinmux pinctrl: i2s is already enabled
[    5.427167] rt2880-pinmux pinctrl: i2s is already enabled
[   16.204231] rt2880-pinmux pinctrl: i2s is already enabled
*** [   16.226524] ralink-i2s 10000a00.i2s: mclk 480MHz //这一行
[   16.311999] i2c i2c-0: of_i2c: register /palmbus@10000000/i2c@900/wm8978@1a
[   16.312146] i2c i2c-0: client [wm8978] registered with bus id 0-001a
[   16.352430] i2c-core: driver [wm8960] registered
[  728.571579] wm8978 0-001a: probe
[  728.572242] i2c-core: driver [wm8978] registered
*** [  728.590344] asoc-simple-card sound: wm8978-hifi <-> 10000a00.i2s mapping ok //这一行

使用aplay -l列出声卡来检验是否存在wm8978声卡

root@LAPTOP-BQECF4:~# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: WM8978SoundCard [WM8978-Sound-Card], device 0: ralink-i2s-wm8978-hifi wm8978-hifi-0 [ralink-i2s-wm8978-hifi wm8978-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

可以看到存在WM8978声卡.

使用alsamixer来进行图形化的音频选项修改.使用F6选择声卡,M改变开关,ESC退出

使用aplay播放测试音频,使用-Dhw:CardID,DeviceID来选择指定声卡,在上面的log可以看到这块声卡cardID为0,DeviceID为0.

aplay -Dhw:0,0 -vv /tmp/test.wav,这将会播放/tmp/test.wav,请把这个改成你自己的路径.在耳机或者喇叭处聆听是否有声音输出.

问题

首先是dts的问题,这里折腾了很久,被ralink-i2s 10000a00.i2s: mclk 480MHz这行日志忽悠了,最后通过示波器检验refclk引脚的时钟输出确认refclk的时钟输出是12Mhz.

第二个就是设备树里的widget和route部件,如果写了就会在日志里报错没有sink和source的问题,最后把这两个去掉,让系统自动配置.

第三个就是在我这块WM8978模块上,只有微弱的声音输出,到现在没有确定是模块的问题还是寄存器数值的问题.

寄存器数值可以通过以下命令查看:cat /sys/kernel/debug/regmap/0-001a/registers.

请注意,由于WM8978在I2C模式下是只写的,寄存器不能读取,所以这里查看的是regmap的写入缓存

鉴于暂时没有能力换一块wm8978,故目前止步于此.

总结与收获

调试很费时间,但是借助D指导(DeepSeek)和不懈搜索,也是感悟良多.几乎把alsa的框架源码和wm8978的源码分析了一整遍.
也参考wm8978的数据手册分析寄存器.通过alsamixer的混音板来反向分析代码和寄存器,大致了解了工作原理.
等以后有时间争取完工.

补充说明

  • 2025.10.05
    使用stm32F407 USB to I2S方式测试wm8978,发现声音也是很小。可能是wm8978坏了的问题。