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 来申请内存空间。