新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > AM335x(TQ335x)學習筆記——WM8960聲卡驅動移植

        AM335x(TQ335x)學習筆記——WM8960聲卡驅動移植

        作者: 時間:2016-11-28 來源:網絡 收藏
        經過一段時間的調試,終于調好了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上的移植方法。

        本文引用地址:http://www.104case.com/article/201611/322823.htm

        1. 在DTS中添加聲卡信息

        Step1. 完善sound信息

        在DTS有一個節點名為sound,該節點用來描述單板上聲卡設備信息,修改后的內容如下:

        1. sound{
        2. compatible="ti,tq-evm-audio";
        3. ti,model="AM335x-EVM";
        4. ti,audio-codec=<&wm8960>;
        5. ti,mcasp-controller=<&mcasp1>;
        6. ti,codec-clock-rate=<24576000>;
        7. ti,audio-routing=
        8. "HeadphoneJack","HP_L",
        9. "HeadphoneJack","HP_R",
        10. "LINPUT1","LineIn";
        11. };
        含義解釋:

        (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節點內添加如下信息(類似上篇文章中觸摸設備驅動節點):

        1. wm8960:wm8960@1a{
        2. compatible="wlf,wm8960";
        3. reg=<0x1a>;
        4. };
        含義解釋:

        (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信息,如果有啥不懂的可以留言討論:

        1. am335x_evm_audio_pins:am335x_evm_audio_pins{
        2. pinctrl-single,pins=<
        3. 0x1A0(PIN_INPUT_PULLDOWN|MUX_MODE3)/*mcasp0_aclkr.mcasp1_aclkx*/
        4. 0x1A4(PIN_INPUT_PULLDOWN|MUX_MODE3)/*mcasp0_fsr.mcasp1_fsx*/
        5. 0x1A8(PIN_OUTPUT_PULLDOWN|MUX_MODE3)/*mcasp0_axr1.mcasp1_axr0*/
        6. 0x1AC(PIN_INPUT_PULLDOWN|MUX_MODE3)/*mcasp0_ahclkx.mcasp1_axr1*/
        7. >;
        8. };
        (2) i2s的配置信息需要在mcasp1節點中修改,具體的修改如下:
        1. &mcasp1{
        2. pinctrl-names="default";
        3. pinctrl-0=<&am335x_evm_audio_pins>;
        4. status="okay";
        5. op-mode=<0>;/*MCASP_IIS_MODE*/
        6. tdm-slots=<2>;
        7. /*4serializers*/
        8. serial-dir=
        9. 1200
        10. >;
        11. tx-num-evt=<1>;
        12. rx-num-evt=<1>;
        13. };
        含義:

        (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即可,修改后的代碼片段如下:

        1. staticconststructof_device_idwm8960_of_match[]={
        2. {.compatible="wlf,wm8960",},
        3. {}
        4. };
        5. MODULE_DEVICE_TABLE(of,wm8960_of_match);
        6. staticstructi2c_driverwm8960_i2c_driver={
        7. .driver={
        8. .name="wm8960",
        9. .owner=THIS_MODULE,
        10. .of_match_table=wm8960_of_match,
        11. },
        12. .probe=wm8960_i2c_probe,
        13. .remove=wm8960_i2c_remove,
        14. .id_table=wm8960_i2c_id,
        15. };
        Step2. 完善WM8960的初始化信息

        默認的WM8960驅動初始化信息不夠完整,還需要對WM8960進行額外的初始化,修改后的代碼片段如下:

        1. staticintwm8960_probe(structsnd_soc_codec*codec)
        2. {
        3. structwm8960_priv*wm8960=snd_soc_codec_get_drvdata(codec);
        4. structwm8960_data*pdata=dev_get_platdata(codec->dev);
        5. intret;
        6. wm8960->set_bias_level=wm8960_set_bias_level_out3;
        7. if(!pdata){
        8. dev_warn(codec->dev,"Noplatformdatasupplied");
        9. }else{
        10. if(pdata->capless)
        11. wm8960->set_bias_level=wm8960_set_bias_level_capless;
        12. }
        13. ret=wm8960_reset(codec);
        14. if(ret<0){
        15. dev_err(codec->dev,"Failedtoissuereset");
        16. returnret;
        17. }
        18. wm8960->set_bias_level(codec,SND_SOC_BIAS_STANDBY);
        19. /*Latchtheupdatebits*/
        20. snd_soc_update_bits(codec,WM8960_LINVOL,0x100,0x100);
        21. snd_soc_update_bits(codec,WM8960_RINVOL,0x100,0x100);
        22. snd_soc_update_bits(codec,WM8960_LADC,0x100,0x100);
        23. snd_soc_update_bits(codec,WM8960_RADC,0x100,0x100);
        24. snd_soc_update_bits(codec,WM8960_LDAC,0x100,0x100);
        25. snd_soc_update_bits(codec,WM8960_RDAC,0x100,0x100);
        26. snd_soc_update_bits(codec,WM8960_LOUT1,0x100,0x100);
        27. snd_soc_update_bits(codec,WM8960_ROUT1,0x100,0x100);
        28. snd_soc_update_bits(codec,WM8960_LOUT2,0x100,0x100);
        29. snd_soc_update_bits(codec,WM8960_ROUT2,0x100,0x100);
        30. /*otherconfiguration*/
        31. snd_soc_update_bits(codec,WM8960_POWER1,0x1ea,0x1ea);
        32. snd_soc_update_bits(codec,WM8960_POWER2,0x1f8,0x1f8);
        33. snd_soc_update_bits(codec,WM8960_POWER3,0xcc,0xcc);
        34. snd_soc_update_bits(codec,WM8960_LOUTMIX,0x100,0x100);
        35. snd_soc_update_bits(codec,WM8960_ROUTMIX,0x100,0x100);
        36. snd_soc_update_bits(codec,WM8960_POWER3,0xc,0xc);
        37. snd_soc_update_bits(codec,WM8960_LOUT1,0x7f,0x7f);
        38. snd_soc_update_bits(codec,WM8960_ROUT1,0x7f,0x7f);
        39. snd_soc_update_bits(codec,WM8960_IFACE2,0x40,0x40);
        40. snd_soc_update_bits(codec,WM8960_MONOMIX2,0x120,0x120);
        41. snd_soc_update_bits(codec,WM8960_LINPATH,0x1f8,0x138);
        42. snd_soc_update_bits(codec,WM8960_LINVOL,0x19f,0x11f);
        43. snd_soc_update_bits(codec,WM8960_RINVOL,0x19f,0x11f);
        44. snd_soc_update_bits(codec,WM8960_LOUT2,0x1ff,0x1ff);
        45. snd_soc_update_bits(codec,WM8960_ROUT2,0x1ff,0x1ff);
        46. snd_soc_update_bits(codec,WM8960_CLASSD3,0x1a,0x12);
        47. snd_soc_update_bits(codec,WM8960_CLASSD1,0xc0,0xc0);
        48. snd_soc_add_codec_controls(codec,wm8960_snd_controls,
        49. ARRAY_SIZE(wm8960_snd_controls));
        50. wm8960_add_widgets(codec);
        51. return0;
        52. }
        具體的含義可以參考WM8960的芯片手冊,這里我就不一一介紹了。


        上一頁 1 2 3 下一頁

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 昌都县| 金华市| 万州区| 桦川县| 丰镇市| 永顺县| 山东| 招远市| 两当县| 靖宇县| 湖北省| 辽阳市| 济阳县| 新野县| 青川县| 安陆市| 方城县| 确山县| 固始县| 东乡县| 岢岚县| 天祝| 六枝特区| 丘北县| 济宁市| 马尔康县| 高要市| 宁都县| 乌鲁木齐市| 辽中县| 东光县| 建始县| 阿拉善右旗| 连州市| 库尔勒市| 康平县| 义乌市| 永安市| 肥东县| 安阳市| 德阳市|