一 嵌入式音频系统介绍
上图是音频系统的硬件模拟图,声卡通过I2S接口与cpu进行音频数据传输,通过I2C接口与cpu进行控制通讯。
录音数据通路:麦克风---->声卡------I2S------>DMA---->内存;
播放数据通路:内存------->DMA-----I2S------>声卡----->扬声器;
注意:
可以推测 cpu部分的代码包括DMA控制器部分 和 I2S控制器接口 两个部分的代码;
声卡部分的代码包括声卡寄存器控制(I2C)和 I2S接口数据传输 两个部分的代码;
根据上图 信息,可以很容易的理解在嵌入式设备的音频系统(ASoC)所抽象出来的三部分:
Machine 理解为板载硬件如开发板
Platform 理解为 CPU
Codec 声卡
在ASoC软件中 cpu部分称作platform,声卡部分被称作codec,两者通过machine进行匹配连接;machine可以理解为对开发板的抽象。
二 ASOC 驱动
ASoC(Alsa System on Chip),称为移动设备中的ALSA。是建立在标准ALSA驱动层上,将声卡和cpu两部分的控制代码分离开来,更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。ASoC不能单独存在,他只是建立在标准ALSA驱动上的一个它必须和标准的ALSA驱动框架相结合才能工作。
对应于硬件,软件驱动上也分Machine驱动、Platform驱动、Codec驱动三大部分,其中Platform驱动用于驱动Soc端的音频相关模块,Codec驱动用于驱动音频编解码器,Machine驱动负责Platform驱动和Codec驱动之间的耦合以及部分和设备或板子特定的代码。
Platform驱动:
只与特定的Soc有关,实现Soc的音频DMA驱动和Soc端的dai接口驱动,注册的所有platform驱动都会挂载在全局platform_list链表上。注册的Soc端的cpu_dai接口驱动挂载在全局dai_list上。只要指定了SoC,就会有一个对应的Platform,它只与SoC相关,与Machine无关,这样我们就可以把Platform抽象出来,使得同一款SoC不用做任何的改动,就可以用在不同的Machine中。
单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。Platform驱动向ASoC注册snd_soc_platform和snd_soc_dai设备
Codec驱动:
只与Codec编解码器驱动有关,与Soc和Machine无关。所有注册的Codec驱动都会挂载在全局codec_list链表上,注册的Codec端的dai接口驱动挂载在全局dai_list上。Codec和Platform一样,要实现为可重用的部件,同一个Codec可以被不同的Machine使用。嵌入式Codec驱动通常通过I2C对编解码芯片进行控制。
Machine驱动:
驱动主要是针对设备的,实现Codec和Platform耦合,Machine驱动是实现板级上的Codec 和SoC中间的桥梁。描述两者如何连接。一般的板卡设计者只需要实现这部分的驱动。Machine驱动的开发主要工作是向内核注册一个snd_soc_card声卡实体。
具体工作将Platform驱动和Codec驱动关联在一起,通过snd_soc_dai_link中的名字指定使用哪个Platform驱动,使用哪个Soc端的dai接口,使用哪个Codec驱动,使用Codec上的哪个dai接口。同时也做一些特定于单板的操作。只要是与Soc和Codec驱动无关的操作,都应该放在Machine驱动中。Machine驱动中注册的and_codec_card放在全局card_list链表上。ASoC的一切都从Machine驱动开始,包括声卡的注册,绑定Platform和Codec驱动等等。
注意:
涉及的三个驱动中涉及的全局链表
soc-core.c中
struct list_head card_list; /*Machine驱动注册的snd_codec_card放在这个链表上*/
struct list_head dai_list; /*soundsocsamsungI2s.c中使用snd_soc_register_dai注册的cpu_dai会放在这上面,codec中注册的codec端的dai也会挂在这上面*/
struct list_head platform_list; /*注册的Soc的platform驱动在这个链表上*/
struct list_head codec_list; /*音频编解码芯片驱动注册的codec挂载在这个链表上*/
snd_soc_card代表着Machine驱动
snd_soc_platform则代表着Platform驱动
snd_soc_codec则代表了Codec驱动
而snd_soc_dai_link则负责连接Platform和Codec。
snd_soc_dai是snd_soc_platform和snd_soc_codec的数字音频接口。
snd_soc_codec的dai是codec_dai
snd_soc_platform的dai为cpu_dai,
snd_pcm是snd_soc_card实例化后注册的声卡类型.
注意 snd_soc_dai_link结构就指明了该Machine所使用的Platform和Codec。在Codec这边通过codec_dai和Platform侧的cpu_dai相互通信,既然相互通信,就需要遵守一定的规则,其中codec_dai和cpu_dai统一抽象为struct snd_soc_dai结构,而将dai的相关操作使用snd_soc_dai_driver抽象。同时也需要对所有的codec设备进行抽象封装,linux使用snd_soc_codec进行所有codec设备的抽象,而将codec的驱动抽象为snd_soc_codec_driver结构。