3. 内核音频驱动框架

在嵌入式 ALSA 音频驱动中,snd_soc_card、snd_soc_dai_link、snd_soc_platform 和 snd_soc_codec 是构成 ASoC(ALSA System on Chip)框架的四大支柱。理解它们之间的组合与引用关系,是进行驱动移植与 Kconfig 裁剪的前提。

核心概念:ASoC 将音频系统抽象为 Card(声卡)、Link(链路)、Platform(DMA/CPU侧) 和 Codec(编解码器) 四个层次。Card 是顶层容器,Link 描述连接关系,Platform 负责数据传输,Codec 负责音频信号转换。

3.1 结构体职责与关键字段

结构体 角色 关键字段 对应硬件
snd_soc_card 声卡顶层实例 name, dai_link, num_links, dev 整个音频设备(如:板级声卡)
snd_soc_dai_link CPU DAI 与 Codec DAI 的连接 name, cpus, codecs, platforms, ops I2S/PCM 总线连接
snd_soc_platform CPU 侧 DMA 引擎 name, pcm_new, pcm_free, ops SoC 内置 DMA 控制器
snd_soc_codec 音频编解码芯片 name, dapm, controls, driver WM8960、ES8316、TLV320AIC3x 等
移植要点:在设备树匹配或板级文件中,snd_soc_card 通过 dai_link 数组将 platform 和 codec 绑定在一起。裁剪 Kconfig 时,必须确保 platform 和 codec 对应的驱动模块被选中,否则声卡注册会失败。

3.2 结构体关系 SVG 架构图

下图展示了四个核心结构体在 ASoC 框架中的层级关系与数据流向:

ASoC 核心结构体关系图 ASoC 核心结构体关系图 snd_soc_card 声卡顶层实例(name, dev, num_links) dai_link 数组 snd_soc_dai_link CPU DAI ↔ Codec DAI 连接描述 platforms 指针 codecs 指针 snd_soc_platform CPU DMA 引擎 pcm_new / ops snd_soc_codec 音频编解码芯片 dapm / controls 硬件抽象层 I2S / PCM 总线 · DMA 通道 · I2C/SPI 控制 说明: 1. snd_soc_card 通过 dai_link 数组管理多个音频链路。 2. 每个 dai_link 必须绑定一个 platform 和一个 codec,才能完成 PCM 数据流。 3. 裁剪 Kconfig 时,需同时选中 SND_SOC、对应 platform 驱动和 codec 驱动。

3.3 典型注册流程与代码片段

在板级驱动中,通常按以下步骤组织这四个结构体:

  1. 定义 Codec 驱动:填充 snd_soc_codec_driver,注册编解码器控制接口。
  2. 定义 Platform 驱动:填充 snd_soc_platform_driver,实现 DMA 传输回调。
  3. 定义 DAI Link:将 CPU DAI 和 Codec DAI 通过 snd_soc_dai_link 连接。
  4. 定义 Card:填充 snd_soc_card,挂载 dai_link 数组,调用 devm_snd_soc_register_card()。
/* 示例:板级声卡注册代码片段 */
static struct snd_soc_dai_link imx_wm8960_dai_link = {
    .name           = "WM8960-HIFI",
    .stream_name    = "WM8960-HIFI",
    .cpus           = &imx_cpu_dai,
    .num_cpus       = 1,
    .codecs         = &wm8960_codec,
    .num_codecs     = 1,
    .platforms      = &imx_platform,
    .num_platforms  = 1,
    .ops            = &imx_wm8960_ops,
};

static struct snd_soc_card imx_wm8960_card = {
    .name       = "imx-wm8960",
    .owner      = THIS_MODULE,
    .dai_link   = &imx_wm8960_dai_link,
    .num_links  = 1,
};

static int imx_audio_probe(struct platform_device *pdev) {
    struct snd_soc_card *card = &imx_wm8960_card;
    card->dev = &pdev->dev;
    return devm_snd_soc_register_card(&pdev->dev, card);
}
常见错误:在裁剪 Kconfig 时,如果只选中了 SND_SOC_IMX_WM8960 而忘记选中 SND_SOC_WM8960(Codec 驱动),内核编译不会报错,但运行时 snd_soc_register_card 会因找不到 Codec 组件而返回 -EPROBE_DEFER 或 -ENODEV。

3.4 结构体依赖关系总结

依赖方向 源结构体 目标结构体 说明
1 snd_soc_card snd_soc_dai_link Card 通过 dai_link 指针引用 Link 数组
2 snd_soc_dai_link snd_soc_platform Link 通过 platforms 指针绑定 DMA 引擎
3 snd_soc_dai_link snd_soc_codec Link 通过 codecs 指针绑定编解码器
4 snd_soc_platform 硬件 DMA Platform 驱动操作 DMA 寄存器
5 snd_soc_codec 硬件 I2C/SPI Codec 驱动通过控制总线配置芯片

3.5 实战:Kconfig 裁剪与结构体对应关系

在 sound/soc/ 目录下,Kconfig 的配置项与上述结构体存在直接映射:

  • CONFIG_SND_SOC:顶层开关,对应 ASoC 框架基础支持。
  • CONFIG_SND_SOC_IMX_CPU_DAI:对应 snd_soc_dai_link 中的 CPU DAI 部分。
  • CONFIG_SND_SOC_WM8960:对应 snd_soc_codec 驱动。
  • CONFIG_SND_SOC_IMX_PCM:对应 snd_soc_platform 驱动。
  • CONFIG_SND_SOC_IMX_WM8960:对应 snd_soc_card 板级实例。
裁剪原则:如果目标硬件只使用 WM8960 一个 Codec,且 SoC 是 i.MX6,则只需选中上述 5 个配置项,其余 Codec 驱动(如 ES8316、TLV320AIC3x)全部取消,可显著减小内核体积。