深入解析 WM8960 音频驱动:Machine Driver、DAI 机制与 ASoC 框架

1. 音频驱动概述

什么是 ASoC(Advanced Sound on Chip)?

ASoC(高级音频子系统)是 Linux 内核中的一个 音频框架,用于管理 SoC(System on Chip)中的音频设备。其核心目标是 模块化设计,将 控制器(SAI/SSI)、音频处理(ASRC)、音频编解码器(Codec) 分离,使驱动更加灵活。
在这里插入图片描述

ASoC 主要组成部分

  1. Machine Driver(机型驱动)
    • 负责 管理 SoC DAI(SAI/SSI)和 Codec DAI(如 WM8960)的连接关系
    • 主要作用:解析 设备树,配置 DAI 格式、时钟、音频路由
  2. Platform Driver(平台驱动)
    • 负责 底层音频控制器(如 SAI、ESAI、I2S) 的寄存器控制。
  3. Codec Driver(编解码器驱动)
    • 负责 具体音频芯片(WM8960、SGTL5000) 的寄存器控制,通常通过 I2C/SPI 进行通讯。

什么是 DAI(Digital Audio Interface)?

DAI(数字音频接口)是 SoC 端 SAI 控制器Codec 端数据接口 之间的桥梁,用于音频数据的传输。

在 i.MX8MP + WM8960 方案中:

  • SoC 端sai3(CPU DAI)
  • Codec 端wm8960-hifi(Codec DAI)

2. WM8960 音频驱动架构

设备树节点解析

sound-wm8960 {
    compatible = "fsl,imx-audio-wm8960";
    model = "wm8960-audio";
    audio-cpu = <&sai3>;   // SoC 端 DAI
    audio-codec = <&codec>; // Codec 端 DAI
    audio-asrc = <&easrc>;
};

&i2c3 {
    codec: wm8960@1a {
        compatible = "wlf,wm8960";
        reg = <0x1a>;
        clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>;
        clock-names = "mclk";
    };
};

关键解析

  • audio-cpu = <&sai3>; 👉 绑定 SoC 侧的 SAI 控制器
  • audio-codec = <&codec>; 👉 绑定 WM8960 编解码器,通过 I2C 配置。
  • clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>; 👉 配置 WM8960 的主时钟 MCLK。

3. Machine Driver 详解

Machine Driver 负责将 SoC DAI(sai3)和 Codec DAI(wm8960-hifi)正确连接,主要工作包括:

  • 解析设备树,获取 sai3wm8960 设备节点。
  • 配置 DAI,如 时钟、数据格式、TDM
  • 注册 snd_soc_card,完成 SoC 和 Codec 的绑定

核心代码解析

static int fsl_asoc_card_probe(struct platform_device *pdev)
{
    struct device_node *cpu_np, *codec_np;
    struct fsl_asoc_card_priv *priv;
    struct platform_device *cpu_pdev;
    
    priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    cpu_np = of_parse_phandle(np, "audio-cpu", 0);
    codec_np = of_parse_phandle(np, "audio-codec", 0);
    
    priv->dai_link[0].cpus->of_node = cpu_np;
    priv->dai_link[0].codecs->of_node = codec_np;
    priv->dai_link[0].platforms->of_node = cpu_np;
    priv->dai_link[0].dai_fmt = priv->dai_fmt;
    priv->card.num_links = 1;
    
    return devm_snd_soc_register_card(&pdev->dev, &priv->card);
}

核心作用

  1. 解析 设备树,找到 sai3wm8960
  2. 通过 snd_soc_dai_link 绑定 SoC 端和 Codec 端
  3. 调用 snd_soc_register_card() 完成注册

4. DAI 机制与 hw_params()

Machine Driver 只负责 注册 DAI,但音频流启动时,还需要 hw_params() 来配置时钟和数据格式。

hw_params() 作用

  • snd_soc_dai_set_sysclk() 👉 设置 MCLK
  • snd_soc_dai_set_fmt() 👉 设置 I2S 格式
  • snd_soc_dai_set_tdm_slot() 👉 设置 时分复用(TDM)
static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *params)
{
    struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
    
    snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0),
                            priv->cpu_priv.sysclk_id,
                            priv->cpu_priv.sysclk_freq,
                            SND_SOC_CLOCK_IN);

    snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), priv->dai_fmt);
    
    return 0;
}

音频流启动流程

  1. aplay 触发 hw_params()
  2. hw_params() 配置 MCLK、I2S格式、TDM
  3. snd_pcm_ops->trigger() 启动音频流

5. 总结

  1. Machine Driver 解析设备树,绑定 SoC DAI 和 Codec DAI
  2. 设备树 sound-wm8960 指定 sai3 作为 SoC 端,wm8960@1a 作为 Codec 端
  3. DAI(Digital Audio Interface)是 SoC 和 Codec 的桥梁,用于 音频数据传输
  4. hw_params() 负责配置 DAI 的时钟、数据格式
  5. 最终,snd_soc_card 绑定 SoC 和 Codec,实现音频驱动

本博文详细解析了 WM8960 在 i.MX8MP 平台上的音频驱动实现,希望能帮助开发者深入理解 ASoC 框架与 DAI 机制! 🎯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值