AM335x(TQ335x)学习笔记——WM8960声卡驱动移植--2

2019-07-15 15:16发布

本帖最后由 qwe890asd 于 2017-10-3 16:02 编辑

AM335x(TQ335x)学习笔记——WM8960声卡驱动移植


3. 编写Machine驱动
内核代码有个很好的例子就是davinci-evm.c,这是am335x-evm评估板的Machine驱动,该评估采用的Codec并不是WM8960,因此,我们在该文件中添加WM8960信息即可。具体的修改如下:
Step1. 添加compatible信息。修改后的内容如下:
  • static const struct of_device_id davinci_evm_dt_ids[] = {  
  •     {  
  •         .compatible = "ti,tq-evm-audio",  
  •         .data = (void *) &evm_dai_wm8960,  
  •     },  
  •     {  
  •         .compatible = "ti,da830-evm-audio",  
  •         .data = (void *) &evm_dai_tlv320aic3x,  
  •     },  
  •     { /* sentinel */ }  
  • };  

复制代码
Step2. 实现em_dai_wm8960。需要添加如下代码:
  • static struct snd_soc_dai_link evm_dai_wm8960 = {  
  •     .name       = "wm8960",  
  •     .stream_name    = "wm8960-hifi",  
  •     .codec_dai_name = "wm8960-hifi",  
  •     .ops            = &evm_wm8960_ops,  
  •     .init           = evm_wm8960_init,  
  •     .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM |  
  •         SND_SOC_DAIFMT_NB_NF,  
  • };  

复制代码
含义:
(1) codec_dai_name = "wm8960-hifi" --> 指定codec设备名称,与wm8960.c中指定的相同即可。(2) ops --> 指定wm8960的各种操作函数,本文仅实现了hw_params函数。(3) init --> 指定wm8960的初始化函数,主要是完成dapm相关的初始化。(4) dai_fmt --> 指定音频的接口方式、主从关系和时钟翻转信息。SND_SOC_DAIFMT_I2S表示音频接口采用I2S协议;SND_SOC_DAIFMT_CBM_CFM表示Codec的BCLK为Master,LRCLK为Master,即wm8960为主,AM335x为从;SND_SOC_DAIFMT_NB_NF表示BCLK和LRCLK都不需要翻转。Step3.实现evm_wm8960_init这一部分主要是dapm相关的设置,本人理解也不是非常深刻,直接贴上代码,具体如下:
  • static const struct snd_soc_dapm_widget evm_wm8960_dapm_widgets[] = {  
  •     SND_SOC_DAPM_SPK("Audio Out1", NULL),  
  •     SND_SOC_DAPM_MIC("my Mic", NULL),  
  •     SND_SOC_DAPM_MIC("my Line IN", NULL),  
  • };  
  •   
  • static const struct snd_kcontrol_new evm_wm8960_controls[] = {  
  •     SOC_DAPM_PIN_SWITCH("Audio Out1"),  
  •     SOC_DAPM_PIN_SWITCH("my Mic"),  
  •     SOC_DAPM_PIN_SWITCH("my Line IN"),  
  • };  
  •   
  • static const struct snd_soc_dapm_route evm_wm8960_audio_map[] = {  
  •     /* Connections to the ... */  
  •     {"Audio Out1", NULL, "HP_L"},  
  •     {"Audio Out1", NULL, "HP_R"},  
  •   
  •     /* Mic */  
  •     {"LINPUT1", NULL, "MICB"},  
  •     {"MICB", NULL, "my Mic"},  
  •   
  •     /* Line in */  
  •     {"LINPUT3", NULL, "my Line IN"},  
  •     {"RINPUT3", NULL, "my Line IN"},  
  • };  
  •   
  • static int evm_wm8960_init(struct snd_soc_pcm_runtime *rtd)  
  • {  
  •     int err;  
  •     struct snd_soc_codec *codec = rtd->codec;  
  •     struct snd_soc_dapm_context *dapm = &codec->dapm;  
  •   
  •     snd_soc_dapm_new_controls(dapm, evm_wm8960_dapm_widgets,  
  •             ARRAY_SIZE(evm_wm8960_dapm_widgets ) );  
  •   
  •     err = snd_soc_add_codec_controls(codec, evm_wm8960_controls,  
  •             ARRAY_SIZE(evm_wm8960_controls));  
  •   
  •     if (err < 0)  
  •         return err;  
  •   
  •     snd_soc_dapm_add_routes(dapm, evm_wm8960_audio_map,  
  •             ARRAY_SIZE(evm_wm8960_audio_map));  
  •   
  •     snd_soc_dapm_enable_pin(dapm, "Audio Out1");  
  •     snd_soc_dapm_enable_pin(dapm, "my Mic");  
  •   
  •     snd_soc_dapm_sync( dapm );  
  •   
  •     return 0;  
  • }  

复制代码
Step4. 实现evm_wm8960_ops及相关函数,需要添加如下代码:
  • static int evm_wm8960_hw_params(struct snd_pcm_substream *substream,  
  •              struct snd_pcm_hw_params *params)  
  • {  
  •     struct snd_soc_pcm_runtime *rtd = substream->private_data;  
  •     struct snd_soc_dai *codec_dai = rtd->codec_dai;  
  •     struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  
  •     struct snd_soc_card *soc_card = rtd->card;  
  •     int ret = 0;  
  •     unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)  
  •                snd_soc_card_get_drvdata(soc_card))->sysclk;  
  •   
  •     /* set the codec system clock */  
  •     ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_IN);  
  •     if (ret < 0)  
  •         return ret;  
  •   
  •     /* set the CPU system clock */  
  •     ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_IN);  
  •     if (ret < 0)  
  •         return ret;  
  •   
  •     return 0;  
  • }  
  •   
  • static struct snd_soc_ops evm_wm8960_ops = {  
  •     .startup = evm_startup,  
  •     .shutdown = evm_shutdown,  
  •     .hw_params = evm_wm8960_hw_params,  
  • };  

复制代码
至此,就完成了代码移植的全部工作,修改涉及到的三个文件是:tq335x.dts、davinci-evm.c和wm8960.c,修改后的这三个文件我会上传到我的资源,如有需要,请去我的资源中下载。
4. 配置内核完成了代码的移植工作之后还需要对内核进一步配置。默认的内核将ALSA作为module加载,本文将编译进内核。具体步骤如下:Step1. 修改sound/soc/codecs/Kconfig,添加wm8960编译选项,修改后的内容如下:
  • config SND_SOC_WM8960  
  •     tristate "Wolfson Microelectronics WM8960 CODEC"  
  •     depends on I2C && INPUT  

复制代码
Step2.  通过menuconfig配置内核
执行指令:
  • make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig  

复制代码
进行如下修改:
  • Device Drivers  --->  
  •     <*> Sound card support  --->   
  •         <*>   Advanced Linux Sound Architecture  --->  
  •             <*>   ALSA for SoC audio support  --->  
  •                 <*>   SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)  
  •                 -*-   Multichannel Audio Serial Port (McASP) support  
  •                 <*>   SoC Audio for the AM33XX chip based boards  
  •                 CODEC drivers  --->  
  •                     <*> Wolfson Microelectronics WM8960 CODEC  

复制代码
重新编译内核:
  • make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8  






0条回答

一周热门 更多>