花了大概40天时间从零开始调音频驱动到目前的基本成功,中间也走了不少弯路,今天抽点时间把整个流程走下来,希望以后能作为参考。
1.dm6467平台sdk_3_10版本中使用到的audio模块框架采用asoc模式,asoc框架主要包含4部分内容:
(1) codec模块驱动:如,visiondigi板子上采用tlv320aic23芯片,代码中文件tlv320aic23.c提供了该部分驱动。主要实现了codec部分的digital audio interface部分代码。
(2)平台驱动:如,dm6467平台中采用mcasp模块进行音频功能实现,代码中文件davinci_mcasp.c、 davinci_pcm.c以及soc-dapm.c文件提供了该部分代码,其中文件davinci_mcasp.c
部分实现了dm6467平台中digital audio interface(DAI)相关代码,与codec中digital audio interface部分匹配使用。文件davinci_pcm.c部分主要通过substream建立DMA通道。 文件soc-dapm.c主要是动态音频电源管理,用于切换各种需要的音频路径。
3.各模块启动流程:
kernel启动时,
(1) 执行了文件 board-dm646x-evm.c 。
-------a.进入evm_init()函数进行各模块硬件初始化。其中音频相关的函数dm646x_init_mcasp0(&dm646x_evm_snd_data[0])主要完成名字为“davinci-mcasp”device的注册,以及dm646x_evm_snd_data参数的初始化。
-------b.进入evm_init_i2c()函数,注册device为"i2c_davinci"的I2C总线,并把名字“tlv320aic23”挂在总线上,为后续配置codec芯片的寄存器做准备。
(2)执行了文件soc-core.c中snd_soc_init函数。
-----a.在platform平台上注册了名字为"soc-audio"的driver,并把类型为platform_driver的参数soc-driver填充进此driver。
-----b.在变量soc-driver中的成员函数指针probe和remove是分别将soc-audio的声卡注册和注销。
-----c.在变量soc-driver中有一个重要的成员为函数指针pm指向soc-pm-ops。而soc-pm-ops同时又指向三个函数。
I 函数 soc_suspend:执行了snd_power_wait来对声卡电源进行管理,同时执行digital_mute对DAC声音进行关闭,并挂起所有PCM流,关闭所有等待的流并保存其当前状态。
II 函数 soc_resume:判断CPU dai是否是ac97接口,如果是ac97接口就会对其处理执行soc_resume_deferred函数。(目前我做的是I2S接口,所以ac97没做详细研究)
III 函数 soc_poweroff:关闭声卡电源,关闭之前会取消所有等待队列的任务,如果有任务在执行则等待其执行完毕再关闭电源。
(3)执行了文件tlv320aic23.c中tlv320aic23_modinit函数。
-----a.该函数注册了名字为“tlv320aic23”的driver在card平台上, 并把结构体变量tlv320aic23_dai加入在dai->list的链表上。
-----b. 接着执行结构体变量tlv320aic23_dai的填充,其中一个比较重要的成员是tlv320aic23_dai_ops,它是由一系列的函数指针组成,这些函数指针指向的函数即是配置tlv320aic23工作的寄存器,这里就不一一具体列出来了,不过要注意这里的配置要跟CPU dm6467要一致才能正常工作。