经过一段时间的调试,总算调好了TQ335x的声卡驱动。TQ335x选用的Codec是WM8960,本文来总结下WM8960驱动在AM335x渠道上的移植办法。Linux声卡驱动架构有OSS和ALSA两种架构,现在最常用的架构是ALSA,本文也运用ALSA架构对WM8960驱动进行移植。
ASoC是对ALSA驱动架构的进一步封装。ASoC将ALSA驱动中的各模块笼统为三部分:Platform、Codec和Machine。Platform主要是渠道硬件驱动,包含SoC的IIS模块、DMA等,在本文中便是指AM335x的McASP模块及AM335x用于音频读写操作的EDMA。Codec是编解码芯片驱动,在本文中便是WM8960。Machine是用来描绘单板音频系统衔接联系的驱动,在本文中其作用是将WM8960与McASP绑定起来,注册声卡设备节点。因为3.17版别的内核现已带有TI保护的McASP驱动和Wolf公司保护的WM8960驱动,因而,原理上讲,咱们只需求编写Machine部分,树立WM8960与McASP的衔接联系即可。不幸的是Wolf对WM8960的保护不是太完善,还需求咱们进一步修正。下面咱们来看下WM8960在TQ335x上的移植办法。
1. 在DTS中增加声卡信息
Step1. 完善sound信息
在DTS有一个节点名为sound,该节点用来描绘单板上声卡设备信息,修正后的内容如下:
- sound{
- compatible=”ti,tq-evm-audio”;
- ti,model=”AM335x-EVM”;
- ti,audio-codec=<&wm8960>;
- ti,mcasp-controller=<&mcasp1>;
- ti,codec-clock-rate=<24576000>;
- ti,audio-routing=
- “HeadphoneJack”,”HP_L”,
- “HeadphoneJack”,”HP_R”,
- “LINPUT1″,”LineIn”;
- };
意义解说:
(1)compatible = “ti,tq-evm-audio” –> 指定声卡兼容的设备,与Machine驱动中的compatible匹配。
(2)ti,model = “AM335x-EVM” –> 声卡的称号,原则上讲能够随意指定,但最好具有必定的可读性,这儿没有修正。
(3)ti,audio-codec = <&wm8960> –> 指定单板运用的Codec,详细的Codec信息由其指向的节点wm8960描绘。
(4)ti,mcasp-controller = <&mcasp1> –> 指定单板运用的Codec衔接到AM335x的McASP1上,McASP1的详细信息由其指向的节点mcasp1描绘。
(5)ti,codec-clock-rate = <24576000> –> 指定Codec的MCLK时钟频率,单位是HZ。TQ335x的Codec运用24.576MHZ的有源晶振供给MCLK,故设置为24576000。
(6)ti,audio-routing –> DAPM信息描绘,用来指定Codec与McASP的衔接联系。此处若不设置,则需求在Machine驱动中进行设置。本文在这儿做了修正。
Step2. 完善Codec信息
经过阅览TQ335x的原理图可知,WM8960的操控端口衔接到了AM335x的I2C0端口上,因而,能够i2c0节点内增加如下信息(相似上篇文章中接触设备驱动节点):
- wm8960:wm8960@1a{
- compatible=”wlf,wm8960″;
- reg=<0x1a>;
- };
意义解说:
(1)compatible = “wlf,wm8960” –> 指定Codec兼容设备,与Codec驱动中的compatible匹配。
(2) reg = <0x1a> –> WM8960的I2C地址是1A,故设置为0x1a。
Step3. 完善Platform信息
AM335x的Platform信息主要指McASP和EMDA设置信息。因为默许的DTS现已装备好了McASP及EDMA的大部分信息,需求咱们装备的是McASP的pinmux和i2s信息。
(1) 修正pinmux信息需求详细参阅TQ335x的原理图,下面是依据原理图中的引脚衔接办法修正的pinmux信息,如果有啥不明白的能够留言评论:
- am335x_evm_audio_pins:am335x_evm_audio_pins{
- pinctrl-single,pins=<
- 0x1A0(PIN_INPUT_PULLDOWN|MUX_MODE3)/*mcasp0_aclkr.mcasp1_aclkx*/
- 0x1A4(PIN_INPUT_PULLDOWN|MUX_MODE3)/*mcasp0_fsr.mcasp1_fsx*/
- 0x1A8(PIN_OUTPUT_PULLDOWN|MUX_MODE3)/*mcasp0_axr1.mcasp1_axr0*/
- 0x1AC(PIN_INPUT_PULLDOWN|MUX_MODE3)/*mcasp0_ahclkx.mcasp1_axr1*/
- >;
- };
(2) i2s的装备信息需求在mcasp1节点中修正,详细的修正如下:
- &mcasp1{
- pinctrl-names=”default”;
- pinctrl-0=<&am335x_evm_audio_pins>;
- status=”okay”;
- op-mode=<0>;/*MCASP_IIS_MODE*/
- tdm-slots=<2>;
- /*4serializers*/
- serial-dir=*0:INACTIVE,1:TX,2:RX*/
- 1200
- >;
- tx-num-evt=<1>;
- rx-num-evt=<1>;
- };
意义:
(1)pinctrl-0 = <&am335x_evm_audio_pins> –> 指定mcasp1的pinmux信息。
(2)op-mode = <0> –> 指定McASP为I2S作业形式。
(3)tdm-slots = <2> –> 指定通道数。AM335x的手册以更广泛意义的单词slot命名,详细到I2S接口,其意义便是Channel。
(4)serial-dir –> 指定serializer的方向。AM335x的手册中说到每个McASP有16个serializer,但AM335x这款芯片的McAPS只要4个serializer,别离用于AXR0、AXR1、AXR2和ARX3。因为TQ335x中将AXR0作为发送(输出)、ARX1作为接纳(输入)且没有ARX2和ARX3,故设置4个serial-dir为1、2、0、0(0表明没有运用,1表明发送,2表明接纳)。
(5)tx-num-evt = <1> –> 指定发送FIFO巨细,本文设置为1。
(6)rx-num-evt = <1> –> 指定接纳FIFO巨细,本文设置为1。
至此,就完成了DTS的悉数装备,后边我会将完好的DTS文件上传到我的资源。
2. Codec驱动完善
Step1. 修正Codec驱动,使其支撑DTS
因为咱们在DTS中指定了Codec的compatible为”wlf,wm8960″,而Linux内核自带的WM8960驱动并没有支撑新式的DTS形式相关。修正办法很简单,增加i2c_driver的.driver中指定of_match_table即可,修正后的代码片段如下:
- staticconststructof_device_idwm8960_of_match[]={
- {.compatible=”wlf,wm8960″,},
- {}
- };
- MODULE_DEVICE_TABLE(of,wm8960_of_match);
- staticstructi2c_driverwm8960_i2c_driver={
- .driver={
- .name=”wm8960″,
- .owner=THIS_MODULE,
- .of_match_table=wm8960_of_match,
- },
- .probe=wm8960_i2c_probe,
- .remove=wm8960_i2c_remove,
- .id_table=wm8960_i2c_id,
- };
Step2. 完善WM8960的初始化信息
默许的WM8960驱动初始化信息不行完好,还需求对WM8960进行额定的初始化,修正后的代码片段如下:
- staticintwm8960_probe(structsnd_soc_codec*codec)
- {
- structwm8960_priv*wm8960=snd_soc_codec_get_drvdata(codec);
- structwm8960_data*pdata=dev_get_platdata(codec->dev);
- intret;
- wm8960->set_bias_level=wm8960_set_bias_level_out3;
- if(!pdata){
- dev_warn(codec->dev,”Noplatformdatasupplied”);
- }else{
- if(pdata->capless)
- wm8960->set_bias_level=wm8960_set_bias_level_capless;
- }
- ret=wm8960_reset(codec);
- if(ret<0){
- dev_err(codec->dev,”Failedtoissuereset”);
- returnret;
- }
- wm8960->set_bias_level(codec,SND_SOC_BIAS_STANDBY);
- /*Latchtheupdatebits*/
- snd_soc_update_bits(codec,WM8960_LINVOL,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_RINVOL,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_LADC,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_RADC,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_LDAC,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_RDAC,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_LOUT1,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_ROUT1,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_LOUT2,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_ROUT2,0x100,0x100);
- /*otherconfiguration*/
- snd_soc_update_bits(codec,WM8960_POWER1,0x1ea,0x1ea);
- snd_soc_update_bits(codec,WM8960_POWER2,0x1f8,0x1f8);
- snd_soc_update_bits(codec,WM8960_POWER3,0xcc,0xcc);
- snd_soc_update_bits(codec,WM8960_LOUTMIX,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_ROUTMIX,0x100,0x100);
- snd_soc_update_bits(codec,WM8960_POWER3,0xc,0xc);
- snd_soc_update_bits(codec,WM8960_LOUT1,0x7f,0x7f);
- snd_soc_update_bits(codec,WM8960_ROUT1,0x7f,0x7f);
- snd_soc_update_bits(codec,WM8960_IFACE2,0x40,0x40);
- snd_soc_update_bits(codec,WM8960_MONOMIX2,0x120,0x120);
- snd_soc_update_bits(codec,WM8960_LINPATH,0x1f8,0x138);
- snd_soc_update_bits(codec,WM8960_LINVOL,0x19f,0x11f);
- snd_soc_update_bits(codec,WM8960_RINVOL,0x19f,0x11f);
- snd_soc_update_bits(codec,WM8960_LOUT2,0x1ff,0x1ff);
- snd_soc_update_bits(codec,WM8960_ROUT2,0x1ff,0x1ff);
- snd_soc_update_bits(codec,WM8960_CLASSD3,0x1a,0x12);
- snd_soc_update_bits(codec,WM8960_CLASSD1,0xc0,0xc0);
- snd_soc_add_codec_controls(codec,wm8960_snd_controls,
- ARRAY_SIZE(wm8960_snd_controls));
- wm8960_add_widgets(codec);
- return0;
- }
详细的意义能够参阅WM8960的芯片手册,这儿我就不逐个介绍了。