I2S(Inter-IC Sound)是一种数字音频总线,主要作用是依托CPU输出的数字信号转换为音频使用的模拟信号,或者反过来采集模拟信号为数字信号。
一般I2S由4根数据线组成:
位时钟(BCLK/SCLK),用于音频时钟相位调整,方便对其采样
帧时钟(LRCK/WS),用于切换左右声道
串行数据(SDATA),实际承载音频采样值的信号,分为IN和OUT两根
I2S是一种简单的数据传输格式,除了上述4根信号之外,有时候也会在ES8326芯片这样的例子中引入一个外部基准时钟线,所以总的可以实现全双工的I2S线是4到5根。
协议简介
飞利浦最早修订的《I2S Bus Specification》已经过去很久了,这里针对苏州顺芯半导体推出两个主要的芯片手册文件:(由于ES8388芯片过于古老,现在顺芯科技已经不在官网支持了,所以这里重点放一个ES8326芯片的手册啊)
此外,还可以搞来一个kernel的用户手册:
可以说,总的来讲就是一个8bit数据位被不断采集的事情。
这里附带一个具体的时序关系图:

这里,这个文献的描述是,首先完成了I2C下的寄存器设置,在约定好双方要进行一次音频传输后,开启I2S把数据传出来。
外设简介
从kernel驱动的角度上看的话,提及要支持的有ES8326、ES8388两款主要芯片:
都在/sound/soc/codec/目录下存在
这一点可以从kernel的文件中佐证:(注意,kernel中有关sound部分的代码维护是外包给了Mark Brown大法师)
来源:https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git/tree/sound/soc/codecs

其协议内部事实上使用了一种ASOC总线+设备枚举的方式,具体到这些ES芯片来说,是通过进行I2C的寄存器操作,来实现kernel的纳管的。最终,alsa-utils工具也是调用ASOC的封装函数,而不是调用这些驱动本身,来实现音频输出的。
ASOC总线的核心文件是/sound/soc/soc-core.c
这个文件定义了声卡设备的一些核心框架:
snd_soc_register_card(),大总管,初始化声卡落地
snd_soc_bind_card(),进行设备树解析,将DTB文件或ACPI文件填入的dai_link数据结构去匹配
snd_card_new() 和 snd_card_register()(调用底层 ALSA 核心),在把硬件都准备好之后,它会向 Linux 的 ALSA 核心层注册一个真正的声卡节点,这时候 /dev/snd/controlC0 等节点才会生成。
soc_new_pcm_runtime(),这个函数负责把 DAI Link(CPU 和 Codec 之间的连接)实例化。它决定了一张声卡上会有几个 PCM 设备(Playback 和 Capture)。
soc_new_pcm(),它负责向 ALSA 核心层注册 PCM 设备。你 aplay -l 看到的 card 1: device 0,就是它创建出来的。
snd_soc_add_component_controls(),这个函数负责把 Codec 驱动(比如 es8326.c 里定义的那些音量、静音等结构体)注册到 ALSA 核心中。
snd_soc_cnew(),负责创建具体的控件实例。它让底层的寄存器操作变成了用户态可以看的 UI 控件。
snd_soc_dapm_add_routes(),把 Machine 驱动里定义的音频路径(比如 DAC 怎么走到耳机)注册进内核。
snd_soc_dapm_new_controls(),注册 DAPM 控件。
测试工具简介
alsa-utils 是一套运行在用户态的命令行工具集,用来测试、配置和调试 ALSA 音频驱动。它本身不碰硬件寄存器,只通过标准接口与内核里的 ASoC/ALSA 框架交互。对于你手头 ES8326 的调试,最核心的就是 aplay、arecord、alsamixer 和 amixer 这几个。
使用方法:
# 列出所有声卡和数字音频设备
aplay -l
# 播放一个 wav 文件(wav 头会自动识别格式)
aplay test.wav
# 指定声卡和设备播放(比如 card 1, device 0)
aplay -D plughw:1,0 test.wav