1. 程式人生 > >AM335x(TQ335x)學習筆記——WM8960音效卡驅動移植

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

經過一段時間的除錯,終於調好了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,該節點用來描述單板上音效卡裝置資訊,修改後的內容如下:

  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.         "Headphone Jack",       "HP_L",  
  9.         "Headphone Jack",       "HP_R",  
  10.         "LINPUT1",              "Line In";  
  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: [email protected] {  
  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.         /* 4 serializers */
  8.         serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
  9.             1 2 0 0  
  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. staticconststruct of_device_id wm8960_of_match[] = {  
  2.     { .compatible = "wlf,wm8960", },  
  3.     { }  
  4. };  
  5. MODULE_DEVICE_TABLE(of, wm8960_of_match);  
  6. staticstruct i2c_driver wm8960_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. staticint wm8960_probe(struct snd_soc_codec *codec)  
  2. {  
  3.     struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);  
  4.     struct wm8960_data *pdata = dev_get_platdata(codec->dev);  
  5.     int ret;  
  6.     wm8960->set_bias_level = wm8960_set_bias_level_out3;  
  7.     if (!pdata) {  
  8.         dev_warn(codec->dev, "No platform data supplied\n");  
  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, "Failed to issue reset\n");  
  16.         return ret;  
  17.     }  
  18.     wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);  
  19.     /* Latch the update bits */
  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.     /* other configuration */
  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.     return 0;  
  52. }  
具體的含義可以參考WM8960的晶片手冊,這裡我就不一一介紹了。

Step3. 調整WM8960驅動結構

核心中自帶的WM8960驅動結構很舊,編寫Machine是需要過多的瞭解Codec晶片內部細節,本文對WM8960的驅動結構進行了調整,可以使Machine忽略Codec的內部細節。

修改的大體內容如下:

(1) 新增set_sysclk函式,接收Machine設定的sysclk時鐘頻率。具體本文就是DTS中設定的24576000。

(2) 在hw_params中新增BCLK、DACCLK、ADCCLK的配置操作。hw_params可以根據引數和sysclk對以上引數進行設定,放在這裡很合適。

(3) 去除函式wm8960_set_dai_clkdiv,並將wm8960_set_dai_pll設定為驅動內部函式,不作為set_pll介面提供給核心驅動(實際上核心驅動也不呼叫這個函式)。

Step4. 修改WM8960的route資訊

根據TQ335x的原理圖可知,使用WM8960進行錄音或放音時使用的LRCLK是同一個,都是DACCLK,故在snd_soc_dapm_route新增如下兩行資訊:

  1. "Left DAC", NULL, "Left Input Mixer"

    相關推薦

    AM335x(TQ335x)學習筆記——WM8960音效驅動移植

    經過一段時間的除錯,終於調好了TQ335x的音效卡驅動。TQ335x採用的Codec是WM8960,本文來總結下WM8960驅動在AM335x平臺上的移植方法。Linux音效卡驅動架構有OSS和ALSA兩種架構,目前最常用的架構是ALSA,本文也使用ALSA架構對WM

    AM335xWM8960音效驅動移植

    經過一段時間的除錯,終於調好了TQ335x的音效卡驅動。TQ335x採用的Codec是WM8960,本文來總結下WM8960驅動在AM335x平臺上的移植方法。Linux音效卡驅動架構有OSS和ALSA兩種架構,目前最常用的架構是ALSA,本文也使用ALSA架構對WM896

    AM335x(TQ335x)學習筆記——u-boot-2014.10移植

    最近移植了下u-boot-2014.10到TQ335x,如果基於am335x evm進行移植,需要修改的地方並不多。 由於TI的am335x evm開發使用了一個eeprom儲存了板載配置資訊,用來區分不同板子的型號的,而TQ335x沒有這個eeprom,因此,需要修改ee

    AM335x(TQ335x)學習筆記——LCD驅動移植

    TI的LCD控制器驅動是非常完善的,共通的地方已經由驅動封裝好了,與按鍵一樣,我們可以通過DTS配置完成LCD的顯示。下面,我們來討論下使用DTS方式配置核心完成LCD驅動的思路。 (1)初步分析 由於TQ335x使用的晶片是AM335x,故仍然可以參考am335x-evm

    AM335x(TQ335x)學習筆記——USB驅動移植

    對於AM335x來講,TI維護的USB驅動已經非常完善了,本文稱之為移植,實際上僅僅是配置核心選項使能USB HOST/OTG功能。廢話少說,直接動手開啟AM335x的USB驅動配置項。 Step1. 配置核心支援USB 預設的配置項沒有配置USB相關的選項,但是DTS已

    AM335x(TQ335x)學習筆記——觸控式螢幕驅動編寫

    前面幾篇文章已經通過配置DTS的方式完成了多個驅動的移植,接下來我們解決TQ335x的觸控驅動問題。由於種種原因,TQ335x的觸控式螢幕驅動是以模組方式提供的,且Linux官方核心中也沒有帶該觸控式螢幕的驅動原始碼,單純的配置DTS是無法完成TQ335x的觸控驅動移植工作

    AM335x(TQ335x)學習筆記——GPIO按鍵驅動移植

    還是按照S5PV210的學習順序來,我們首先解決按鍵問題。TQ335x有六個使用者按鍵,分別是上、下、左、右、Enter和ESC。開始我想到的是跟學習S5PV210時一樣,編寫輸入子系統驅動解決按鍵問題,但是瀏覽driver/input/keyboard目錄時意外的發現了g

    alsa音效驅動移植

    1 配置核心支援UDA1341:  /* 下面是需要配置的巨集,後面函式的編譯取決這些巨集 */CONFIG_SND_S3C24XX_I2S  // s3c24xx-i2s.c CONFIG_SND_

    Linux音效驅動移植和測試

    一、分析驅動程式,根據開發板修改程式碼 程式碼太長,就不貼了,幾個注意點: 1、 檢視開發板原理圖和S3C2410的datasheet,UDA1341的L3MODE、L3DATA、L3CLOCK分別與S3C2410的GPB2、GPB3、GPB4相連,IISLRCK=GPE0

    android下除錯音效驅動wm8960介紹二

    三、LINPUT輸入通道介紹             有關LINPUT的主要配置如下:            R32的bit8(LMN1)置1:LINPUT1連線PGA;            R0

    android下除錯音效驅動wm8960介紹一

           經過了一段時間的Android下wm8960驅動的除錯,終於實現錄音和播放功能了,在除錯過程中有了一些心得,與大家分享一 下,由於能力有限,錯誤之處還望海涵和指教。 一、總述      

    iOS學習筆記23-音效與音樂

    nslog ini post jpg outer 震動 ucc aml iboutlet 一、音頻 在iOS中,音頻播放從形式上能夠分為音效播放和音樂播放。 * 音效: * 主要指一些短音頻的播放,這類音頻一般不須要進行進度、循環等控制。 *

    學習筆記】盧斯定理

    namespace style pan set thml color 怎麽辦 alt fontsize 洛谷 P3807 【模板】盧卡斯定理 題目背景 這是一道模板題。 題目描述 給定n,m,p(1\le n,m,p\le 10^51≤n,m,p≤10?5??) 求 C_{

    解決win10音效驅動不相容問題和成功安裝戰神k650-i5-d2上的Sound Blaster Cinema2在win10系統上

    安裝win10後,偶爾會出現藍屏,經過我的發現,每次聽歌用揚聲器並且長時間。都會發生藍屏 1 . 所以懷疑音效卡驅動VIA HD Audio(Win 8.1)與系統不相容。 2 .乾脆重新安裝音效卡驅動。在網上找到與win10相容的VIAHDAud_v11_1100e_01

    嵌入式核心及驅動開發之學習筆記(六) 驅動層中斷實現

    由於中斷訊號的突發性,CPU要捕獲中斷訊號,有兩種方式。一是不斷輪詢是否有中斷髮生,這樣有點傻;二是通過中斷機制,過程如下: 中斷源 ---> 中斷訊號  --->  中斷控制器 --->  CPU  中斷源有很多,CPU拿

    Linux ALSA音效驅動之六:ASoC架構中的Machine

    前面一節的內容我們提到,ASoC被分為Machine、Platform和Codec三大部分,其中的Machine驅動負責Platform和Codec之間的耦合以及部分和裝置或板子特定的程式碼,再次引用上一節的內容:Machine驅動負責處理機器特有的一些控制元件和音訊

    ALSA音效驅動中的DAPM詳解之二:widget-具備路徑和電源管理資訊的kcontrol

    上一篇文章中,我們介紹了音訊驅動中對基本控制單元的封裝:kcontrol。利用kcontrol,我們可以完成對音訊系統中的mixer,mux,音量控制,音效控制,以及各種開關量的控制,通過對各種kcontrol的控制,使得音訊硬體能夠按照我們預想的結果進行工作。同時我

    ALSA音效驅動中的DAPM詳解之七:dapm事件機制(dapm event)

    前面的六篇文章,我們已經討論了dapm關於動態電源管理的有關知識,包括widget的建立和初始化,widget之間的連線以及widget的上下電順序等等。本章我們準備討論dapm框架中的另一個機制:事件機制。通過dapm事件機制,widget可以對它所關心的dapm事

    關於音效驅動後的madplay安裝問題以及解決

    安裝madplay所需要的庫檔案的時候 遇到了zlib.h找不到的原因 按照上面的內容執行會出現libz找不到的問題 後經過網上的查詢發現是Makefile中編譯器名字出現的問題 //////////////////////////////////////////////////////

    音效驅動除錯過程

     ALSA音效卡驅動 https://blog.csdn.net/droidphone/article/category/1118446 PCM(Pulse-code modulation)脈衝編碼調製,把聲音從模擬轉換成數字訊號的一種技術 https://blog.csdn.