Linux 音频(四) Platform 驱动

本文详细解释了Linux音频系统中的Platform驱动,特别是Rockchip平台的I2S和PCMDMA部分,介绍了I2S模块的原理,以及如何通过DeviceTree管理和DMA引擎优化音频数据传输。重点讲解了snd_soc_platform和snd_pcm_ops结构在驱动中的应用。
摘要由CSDN通过智能技术生成

1.简介

        注意不要跟 Linux设备驱动模型的Platform混为一谈,前面的文章有提到 ALSA把音频分为了三大块 machine codec platform。

        Platform 是指对应得soc得音频这边得驱动,列如Samsung,rockchip都会有自己相应得platform驱动,其中platform驱动主要包含两块。

        cpu的dai驱动:

                      驱动实现音频数字接口控制器的描述和配置。

        pcm_dma驱动:

                     驱动实现音频 dma 操作,具体见 snd_pcm_ops 结构体定义。

2 cpu dai:

        I2S的模块框图

        IPSR:双模分频率器:一路作为I2S的主时钟,一路给外置codec作时钟。

        SFTR:位移寄存器,个人理解就是串行数据与并行数据相互转化用的。

I2S时序图:

            BCLK(=SCLK):位时钟对应每一位数据;BCLK = 声道数 * 采样频率 * 采样位数;

            LRCLK:帧时钟,构成一个完整的声音单元,也就是我们常说的一个采样点,LRCLK=采样频率。

            ADCDAT/DACDAT:上行下行数据线。

            上面是传输所需要的线

             I2S还有一个MCLK ,系统时钟,主要用于同步的。一般是采样频率的整数倍。

以下为kernel\sound\soc\rockchip\rockchip_i2s_tdm.c 这个文件来看dai相关代码。
        用的是平台总线框架来注册的,一般对应SOC厂商都会提供定义好的设备树,把状态设置为enable就行,如果默认定义的一些引脚跟板子不符合,或者一些clock不是自己想要的,再进行修改就行,跟需要的compatible属性对应上就能调用到probe。

调用到probe 函数后 会 调用到 rockchip_i2s_tdm_dai_prepare 生成 rockchip_i2s_tdm_dai实例

        在往下会调用devm_snd_soc_register_component 来实例化一个带有上面初始化好的cpu_dai驱动的component。

        rk的平台做一个对设备树这个字段的解析,来看要不要去用pcm_dma。

 3.pcm_dma

 以放音举例  pcm数据管理会做以下两个事情:

        1.把用户台的音频数据拷贝到dma buffer中。

        2.启动dma设备 直接访问dma buffer 并且把数据传到I2S tx FIFO。

 为什么需要dma呢?因为对于arm这种架构的cpu来说 不能把内存上的数据直接从A地址搬运到B地址,过程一般是 把A地址的数据挪到CPU的寄存器,在从寄存器放到B地址。 dma具有Burst传输能力,一次可以传输几个或者十几个字节的数据,非常适合大数据的传输。dma的存在 在有大数据传输的情况下,可以让cpu的开销大大减少

        后续注册调用  devm_snd_dmaengine_pcm_register->snd_dmaengine_pcm_register(kernel\sound\soc\soc-generic-dmaengine-pcm.c) 在这个函数中来实现pcm_dma相关的一些方法。

下面介绍两个结构体;

        snd_soc_platform:

 需要给snd_soc_platform 赋予snd_soc_platform_driver,rk使用的如下。

3.1 snd_pcm_ops

       其中ops 对应的函数如下

hw_params:设置硬件参数,回调此函数初始化dma资源,包括通道号、传输单元、缓冲信息、IO设备等等。

open:回调该函数设定 dma 设备的硬件约束;并申请一个私有结构,保存 dma 设备资源如通道号、传输单元、缓冲区信息、IO 信息等,保存在 runtime->private_data

trigger:启动/停止调用 上层调用pcm_stop() 或 pcm_drop() 就会调用到trigger做相应操作。

pointer:dma传输完成一次就调用一次此函数,来获得当传输数据指向的buffer位置。

dmaengine_pcm_new:会调用到snd_pcm_lib_preallocate_pages最后调用preallocate_pcm_pages 来申请内存空间。

  • 29
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值