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,該節點用來描述單板上聲卡設備信息,修改後的內容如下:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  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節點內添加如下信息(類似上篇文章中觸摸設備驅動節點):

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  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信息,如果有啥不懂的可以留言討論:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  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節點中修改,具體的修改如下:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. &mcasp1 {  
  2.         pinctrl-names = "default";  
  3.         pinctrl-0 = <&am335x_evm_audio_pins>;  
  4.   
  5.         status = "okay";  
  6.   
  7.         op-mode = <0>;          /* MCASP_IIS_MODE */  
  8.         tdm-slots = <2>;  
  9.         /* 4 serializers */  
  10.         serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */  
  11.             1 2 0 0  
  12.         >;  
  13.         tx-num-evt = <1>;  
  14.         rx-num-evt = <1>;  
  15. };  
含義:

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

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static const struct of_device_id wm8960_of_match[] = {  
  2.     { .compatible = "wlf,wm8960", },  
  3.     { }  
  4. };  
  5. MODULE_DEVICE_TABLE(of, wm8960_of_match);  
  6.   
  7. static struct i2c_driver wm8960_i2c_driver = {  
  8.     .driver = {  
  9.         .name = "wm8960",  
  10.         .owner = THIS_MODULE,  
  11.         .of_match_table = wm8960_of_match,  
  12.     },  
  13.     .probe =    wm8960_i2c_probe,  
  14.     .remove =   wm8960_i2c_remove,  
  15.     .id_table = wm8960_i2c_id,  
  16. };  
Step2. 完善WM8960的初始化信息

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

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int 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.   
  7.     wm8960->set_bias_level = wm8960_set_bias_level_out3;  
  8.   
  9.     if (!pdata) {  
  10.         dev_warn(codec->dev, "No platform data supplied\n");  
  11.     } else {  
  12.         if (pdata->capless)  
  13.             wm8960->set_bias_level = wm8960_set_bias_level_capless;  
  14.     }  
  15.   
  16.     ret = wm8960_reset(codec);  
  17.     if (ret < 0) {  
  18.         dev_err(codec->dev, "Failed to issue reset\n");  
  19.         return ret;  
  20.     }  
  21.   
  22.     wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);  
  23.   
  24.     /* Latch the update bits */  
  25.     snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100);  
  26.     snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100);  
  27.     snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100);  
  28.     snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100);  
  29.     snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100);  
  30.     snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100);  
  31.     snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100);  
  32.     snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100);  
  33.     snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100);  
  34.     snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100);  
  35.   
  36.     /* other configuration */  
  37.     snd_soc_update_bits(codec, WM8960_POWER1, 0x1ea, 0x1ea);  
  38.     snd_soc_update_bits(codec, WM8960_POWER2, 0x1f8, 0x1f8);  
  39.     snd_soc_update_bits(codec, WM8960_POWER3, 0xcc, 0xcc);  
  40.     snd_soc_update_bits(codec, WM8960_LOUTMIX, 0x100, 0x100);  
  41.     snd_soc_update_bits(codec, WM8960_ROUTMIX, 0x100, 0x100);  
  42.     snd_soc_update_bits(codec, WM8960_POWER3, 0xc, 0xc);  
  43.     snd_soc_update_bits(codec, WM8960_LOUT1, 0x7f, 0x7f);  
  44.     snd_soc_update_bits(codec, WM8960_ROUT1, 0x7f, 0x7f);  
  45.     snd_soc_update_bits(codec, WM8960_IFACE2, 0x40, 0x40);  
  46.     snd_soc_update_bits(codec, WM8960_MONOMIX2, 0x120, 0x120);  
  47.     snd_soc_update_bits(codec, WM8960_LINPATH, 0x1f8, 0x138);  
  48.     snd_soc_update_bits(codec, WM8960_LINVOL, 0x19f, 0x11f);  
  49.     snd_soc_update_bits(codec, WM8960_RINVOL, 0x19f, 0x11f);  
  50.     snd_soc_update_bits(codec, WM8960_LOUT2, 0x1ff, 0x1ff);  
  51.     snd_soc_update_bits(codec, WM8960_ROUT2, 0x1ff, 0x1ff);  
  52.     snd_soc_update_bits(codec, WM8960_CLASSD3, 0x1a, 0x12);  
  53.     snd_soc_update_bits(codec, WM8960_CLASSD1, 0xc0, 0xc0);  
  54.   
  55.     snd_soc_add_codec_controls(codec, wm8960_snd_controls,  
  56.                      ARRAY_SIZE(wm8960_snd_controls));  
  57.     wm8960_add_widgets(codec);  
  58.   
  59.     return 0;  
  60. }  
具體的含義可以參考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添加如下兩行信息:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. "Left DAC", NULL, "Left Input Mixer" },  
  2. "Right DAC", NULL, "Right Input Mixer" },  
這樣在錄音時也會使能DAC產生LRCLK。

由於調試時間比較長,可能有些修改我沒有描述到,完整的wm8960.c文件我會一併上傳到我的資源,可以下載參考。

3. 編寫Machine驅動
內核代碼有個很好的例子就是davinci-evm.c,這是am335x-evm評估板的Machine驅動,該評估採用的Codec並不是WM8960,因此,我們在該文件中添加WM8960信息即可。具體的修改如下:

Step1. 添加compatible信息。修改後的內容如下:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static const struct of_device_id davinci_evm_dt_ids[] = {  
  2.     {  
  3.         .compatible = "ti,tq-evm-audio",  
  4.         .data = (void *) &evm_dai_wm8960,  
  5.     },  
  6.     {  
  7.         .compatible = "ti,da830-evm-audio",  
  8.         .data = (void *) &evm_dai_tlv320aic3x,  
  9.     },  
  10.     { /* sentinel */ }  
  11. };  
Step2. 實現em_dai_wm8960。需要添加如下代碼:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static struct snd_soc_dai_link evm_dai_wm8960 = {  
  2.     .name       = "wm8960",  
  3.     .stream_name    = "wm8960-hifi",  
  4.     .codec_dai_name = "wm8960-hifi",  
  5.     .ops            = &evm_wm8960_ops,  
  6.     .init           = evm_wm8960_init,  
  7.     .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM |  
  8.         SND_SOC_DAIFMT_NB_NF,  
  9. };  
含義:

(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相關的設置,本人理解也不是非常深刻,直接貼上代碼,具體如下:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static const struct snd_soc_dapm_widget evm_wm8960_dapm_widgets[] = {  
  2.     SND_SOC_DAPM_SPK("Audio Out1", NULL),  
  3.     SND_SOC_DAPM_MIC("my Mic", NULL),  
  4.     SND_SOC_DAPM_MIC("my Line IN", NULL),  
  5. };  
  6.   
  7. static const struct snd_kcontrol_new evm_wm8960_controls[] = {  
  8.     SOC_DAPM_PIN_SWITCH("Audio Out1"),  
  9.     SOC_DAPM_PIN_SWITCH("my Mic"),  
  10.     SOC_DAPM_PIN_SWITCH("my Line IN"),  
  11. };  
  12.   
  13. static const struct snd_soc_dapm_route evm_wm8960_audio_map[] = {  
  14.     /* Connections to the ... */  
  15.     {"Audio Out1", NULL, "HP_L"},  
  16.     {"Audio Out1", NULL, "HP_R"},  
  17.   
  18.     /* Mic */  
  19.     {"LINPUT1", NULL, "MICB"},  
  20.     {"MICB", NULL, "my Mic"},  
  21.   
  22.     /* Line in */  
  23.     {"LINPUT3", NULL, "my Line IN"},  
  24.     {"RINPUT3", NULL, "my Line IN"},  
  25. };  
  26.   
  27. static int evm_wm8960_init(struct snd_soc_pcm_runtime *rtd)  
  28. {  
  29.     int err;  
  30.     struct snd_soc_codec *codec = rtd->codec;  
  31.     struct snd_soc_dapm_context *dapm = &codec->dapm;  
  32.   
  33.     snd_soc_dapm_new_controls(dapm, evm_wm8960_dapm_widgets,  
  34.             ARRAY_SIZE(evm_wm8960_dapm_widgets ) );  
  35.   
  36.     err = snd_soc_add_codec_controls(codec, evm_wm8960_controls,  
  37.             ARRAY_SIZE(evm_wm8960_controls));  
  38.   
  39.     if (err < 0)  
  40.         return err;  
  41.   
  42.     snd_soc_dapm_add_routes(dapm, evm_wm8960_audio_map,  
  43.             ARRAY_SIZE(evm_wm8960_audio_map));  
  44.   
  45.     snd_soc_dapm_enable_pin(dapm, "Audio Out1");  
  46.     snd_soc_dapm_enable_pin(dapm, "my Mic");  
  47.   
  48.     snd_soc_dapm_sync( dapm );  
  49.   
  50.     return 0;  
  51. }  
Step4. 實現evm_wm8960_ops及相關函數,需要添加如下代碼:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int evm_wm8960_hw_params(struct snd_pcm_substream *substream,  
  2.              struct snd_pcm_hw_params *params)  
  3. {  
  4.     struct snd_soc_pcm_runtime *rtd = substream->private_data;  
  5.     struct snd_soc_dai *codec_dai = rtd->codec_dai;  
  6.     struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  
  7.     struct snd_soc_card *soc_card = rtd->card;  
  8.     int ret = 0;  
  9.     unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)  
  10.                snd_soc_card_get_drvdata(soc_card))->sysclk;  
  11.   
  12.     /* set the codec system clock */  
  13.     ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_IN);  
  14.     if (ret < 0)  
  15.         return ret;  
  16.   
  17.     /* set the CPU system clock */  
  18.     ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_IN);  
  19.     if (ret < 0)  
  20.         return ret;  
  21.   
  22.     return 0;  
  23. }  
  24.   
  25. static struct snd_soc_ops evm_wm8960_ops = {  
  26.     .startup = evm_startup,  
  27.     .shutdown = evm_shutdown,  
  28.     .hw_params = evm_wm8960_hw_params,  
  29. };  
至此,就完成了代碼移植的全部工作,修改涉及到的三個文件是:tq335x.dts、davinci-evm.c和wm8960.c,修改後的這三個文件我會上傳到我的資源,如有需要,請去我的資源中下載。

4. 配置內核

完成了代碼的移植工作之後還需要對內核進一步配置。默認的內核將ALSA作爲module加載,本文將編譯進內核。具體步驟如下:

Step1. 修改sound/soc/codecs/Kconfig,添加wm8960編譯選項,修改後的內容如下:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. config SND_SOC_WM8960  
  2.     tristate "Wolfson Microelectronics WM8960 CODEC"  
  3.     depends on I2C && INPUT  
Step2.  通過menuconfig配置內核

執行指令:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig  
進行如下修改:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. Device Drivers  --->  
  2.     <*> Sound card support  --->   
  3.         <*>   Advanced Linux Sound Architecture  --->  
  4.             <*>   ALSA for SoC audio support  --->  
  5.                 <*>   SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)  
  6.                 -*-   Multichannel Audio Serial Port (McASP) support  
  7.                 <*>   SoC Audio for the AM33XX chip based boards  
  8.                 CODEC drivers  --->  
  9.                     <*> Wolfson Microelectronics WM8960 CODEC  
重新編譯內核:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8  

5. 效果

將編譯後的內核文件zImage和tq335x.dtb文件拷貝SD卡並啓動開發板,按任意鍵進入uboot命令模式,輸入如下指令:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. load mmc 0:1 0x88000000 /boot/tq335x.dtb  
  2. load mmc 0:1 0x82000000 /boot/zImage  
  3. bootz 0x82000000 - 0x88000000  
通過上面的三條指令可以啓動內核,完整的Log信息如下:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. Starting kernel ...  
  2.   
  3. [    0.000000] Booting Linux on physical CPU 0x0  
  4. [    0.000000] Linux version 3.17.2 (lilianrong@smarter) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-12ubuntu1) ) #68 SMP Sat Dec 20 00:03:09 CST 2014  
  5. [    0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c5387d  
  6. [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache  
  7. [    0.000000] Machine model: TI AM335x EVM  
  8. [    0.000000] cma: Reserved 16 MiB at 9e800000  
  9. [    0.000000] Memory policy: Data cache writeback  
  10. [    0.000000]   HighMem zone: 1048574 pages exceeds freesize 0  
  11. [    0.000000] CPU: All CPU(s) started in SVC mode.  
  12. [    0.000000] AM335X ES2.1 (sgx neon )  
  13. [    0.000000] PERCPU: Embedded 9 pages/cpu @dfa99000 s14336 r8192 d14336 u36864  
  14. [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 129792  
  15. [    0.000000] Kernel command line: console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext3 rootwait  
  16. [    0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)  
  17. [    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)  
  18. [    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)  
  19. [    0.000000] Memory: 484124K/523264K available (6070K kernel code, 666K rwdata, 2444K rodata, 410K init, 8214K bss, 39140K reserved, 0K highmem)  
  20. [    0.000000] Virtual kernel memory layout:  
  21. [    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)  
  22. [    0.000000]     fixmap  : 0xffc00000 - 0xffe00000   (2048 kB)  
  23. [    0.000000]     vmalloc : 0xe0800000 - 0xff000000   ( 488 MB)  
  24. [    0.000000]     lowmem  : 0xc0000000 - 0xe0000000   ( 512 MB)  
  25. [    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)  
  26. [    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)  
  27. [    0.000000]       .text : 0xc0008000 - 0xc0858bc0   (8515 kB)  
  28. [    0.000000]       .init : 0xc0859000 - 0xc08bf800   ( 410 kB)  
  29. [    0.000000]       .data : 0xc08c0000 - 0xc0966b50   ( 667 kB)  
  30. [    0.000000]        .bss : 0xc0966b50 - 0xc116c6e0   (8215 kB)  
  31. [    0.000000] Hierarchical RCU implementation.  
  32. [    0.000000]  RCU restricting CPUs from NR_CPUS=2 to nr_cpu_ids=1.  
  33. [    0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1  
  34. [    0.000000] NR_IRQS:16 nr_irqs:16 16  
  35. [    0.000000] IRQ: Found an INTC at 0xfa200000 (revision 5.0) with 128 interrupts  
  36. [    0.000000] Total of 128 interrupts on 1 active controller  
  37. [    0.000000] OMAP clockevent source: timer2 at 24000000 Hz  
  38. [    0.000015] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 178956969942ns  
  39. [    0.000061] OMAP clocksource: timer1 at 24000000 Hz  
  40. [    0.000798] Console: colour dummy device 80x30  
  41. [    0.000849] Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar  
  42. [    0.000858] ... MAX_LOCKDEP_SUBCLASSES:  8  
  43. [    0.000865] ... MAX_LOCK_DEPTH:          48  
  44. [    0.000873] ... MAX_LOCKDEP_KEYS:        8191  
  45. [    0.000880] ... CLASSHASH_SIZE:          4096  
  46. [    0.000887] ... MAX_LOCKDEP_ENTRIES:     32768  
  47. [    0.000894] ... MAX_LOCKDEP_CHAINS:      65536  
  48. [    0.000901] ... CHAINHASH_SIZE:          32768  
  49. [    0.000909]  memory used by lock dependency info: 5167 kB  
  50. [    0.000916]  per task-struct memory footprint: 1152 bytes  
  51. [    0.000956] Calibrating delay loop... 996.14 BogoMIPS (lpj=4980736)  
  52. [    0.079039] pid_max: default: 32768 minimum: 301  
  53. [    0.079431] Security Framework initialized  
  54. [    0.079555] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)  
  55. [    0.079568] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)  
  56. [    0.081736] CPU: Testing write buffer coherency: ok  
  57. [    0.082916] CPU0: thread -1, cpu 0, socket -1, mpidr 0  
  58. [    0.083033] Setting up static identity map for 0x805bf4f0 - 0x805bf560  
  59. [    0.086259] Brought up 1 CPUs  
  60. [    0.086278] SMP: Total of 1 processors activated.  
  61. [    0.086288] CPU: All CPU(s) started in SVC mode.  
  62. [    0.088875] devtmpfs: initialized  
  63. [    0.097689] VFP support v0.3: implementor 41 architecture 3 part 30 variant c rev 3  
  64. [    0.133508] omap_hwmod: tptc0 using broken dt data from edma  
  65. [    0.133865] omap_hwmod: tptc1 using broken dt data from edma  
  66. [    0.134203] omap_hwmod: tptc2 using broken dt data from edma  
  67. [    0.142102] omap_hwmod: debugss: _wait_target_disable failed  
  68. [    0.200093] pinctrl core: initialized pinctrl subsystem  
  69. [    0.202608] regulator-dummy: no parameters  
  70. [    0.232298] NET: Registered protocol family 16  
  71. [    0.240800] DMA: preallocated 256 KiB pool for atomic coherent allocations  
  72. [    0.243054] cpuidle: using governor ladder  
  73. [    0.243083] cpuidle: using governor menu  
  74. [    0.255025] OMAP GPIO hardware version 0.1  
  75. [    0.270226] omap-gpmc 50000000.gpmc: could not find pctldev for node /pinmux@44e10800/nandflash_pins_s0, deferring probe  
  76. [    0.270268] platform 50000000.gpmc: Driver omap-gpmc requests probe deferral  
  77. [    0.274762] hw-breakpoint: debug architecture 0x4 unsupported.  
  78. [    0.319722] edma-dma-engine edma-dma-engine.0: TI EDMA DMA engine driver  
  79. [    0.321054] vbat: 5000 mV   
  80. [    0.321851] lis3_reg: no parameters  
  81. [    0.325260] SCSI subsystem initialized  
  82. [    0.326060] usbcore: registered new interface driver usbfs  
  83. [    0.326235] usbcore: registered new interface driver hub  
  84. [    0.330180] usbcore: registered new device driver usb  
  85. [    0.331021] omap_i2c 44e0b000.i2c: could not find pctldev for node /pinmux@44e10800/pinmux_i2c0_pins, deferring probe  
  86. [    0.331059] platform 44e0b000.i2c: Driver omap_i2c requests probe deferral  
  87. [    0.331115] omap_i2c 4802a000.i2c: could not find pctldev for node /pinmux@44e10800/pinmux_i2c1_pins, deferring probe  
  88. [    0.331139] platform 4802a000.i2c: Driver omap_i2c requests probe deferral  
  89. [    0.332318] Advanced Linux Sound Architecture Driver Initialized.  
  90. [    0.335684] Switched to clocksource timer1  
  91. [    0.486994] NET: Registered protocol family 2  
  92. [    0.488860] TCP established hash table entries: 4096 (order: 2, 16384 bytes)  
  93. [    0.489040] TCP bind hash table entries: 4096 (order: 5, 147456 bytes)  
  94. [    0.490403] TCP: Hash tables configured (established 4096 bind 4096)  
  95. [    0.490593] TCP: reno registered  
  96. [    0.490617] UDP hash table entries: 256 (order: 2, 20480 bytes)  
  97. [    0.490807] UDP-Lite hash table entries: 256 (order: 2, 20480 bytes)  
  98. [    0.491827] NET: Registered protocol family 1  
  99. [    0.493704] RPC: Registered named UNIX socket transport module.  
  100. [    0.493729] RPC: Registered udp transport module.  
  101. [    0.493738] RPC: Registered tcp transport module.  
  102. [    0.493747] RPC: Registered tcp NFSv4.1 backchannel transport module.  
  103. [    0.495022] hw perfevents: enabled with armv7_cortex_a8 PMU driver, 5 counters available  
  104. [    0.499438] futex hash table entries: 256 (order: 2, 16384 bytes)  
  105. [    0.504727] VFS: Disk quotas dquot_6.5.2  
  106. [    0.504882] Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)  
  107. [    0.507359] NFS: Registering the id_resolver key type  
  108. [    0.507727] Key type id_resolver registered  
  109. [    0.507743] Key type id_legacy registered  
  110. [    0.507886] jffs2: version 2.2. (NAND) (SUMMARY)  漏 2001-2006 Red Hat, Inc.  
  111. [    0.508320] msgmni has been set to 977  
  112. [    0.513238] io scheduler noop registered  
  113. [    0.513269] io scheduler deadline registered  
  114. [    0.513341] io scheduler cfq registered (default)  
  115. [    0.515815] pinctrl-single 44e10800.pinmux: 142 pins at pa f9e10800 size 568  
  116. [    0.520975] backlight supply power not found, using dummy regulator  
  117. [    0.524309] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled  
  118. [    0.530939] omap_uart 44e09000.serial: no wakeirq for uart0  
  119. [    0.531575] 44e09000.serial: ttyO0 at MMIO 0x44e09000 (irq = 88, base_baud = 3000000) is a OMAP UART0  
  120. [    1.231857] console [ttyO0] enabled  
  121. [    1.241315] omap_rng 48310000.rng: OMAP Random Number Generator ver. 20  
  122. [    1.248987] [drm] Initialized drm 1.1.0 20060810  
  123. [    1.261218] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).  
  124. [    1.268316] [drm] No driver support for vblank timestamp query.  
  125. [    1.320991] Console: switching to colour frame buffer device 100x30  
  126. [    1.332042] tilcdc 4830e000.lcdc: fb0:  frame buffer device  
  127. [    1.337919] tilcdc 4830e000.lcdc: registered panic notifier  
  128. [    1.343814] [drm] Initialized tilcdc 1.0.0 20121205 on minor 0  
  129. [    1.380804] brd: module loaded  
  130. [    1.398539] loop: module loaded  
  131. [    1.404724] mtdoops: mtd device (mtddev=name/number) must be supplied  
  132. [    1.414737] usbcore: registered new interface driver asix  
  133. [    1.420619] usbcore: registered new interface driver ax88179_178a  
  134. [    1.427154] usbcore: registered new interface driver cdc_ether  
  135. [    1.433416] usbcore: registered new interface driver smsc95xx  
  136. [    1.439572] usbcore: registered new interface driver net1080  
  137. [    1.445625] usbcore: registered new interface driver cdc_subset  
  138. [    1.451932] usbcore: registered new interface driver zaurus  
  139. [    1.457997] usbcore: registered new interface driver cdc_ncm  
  140. [    1.465136] usbcore: registered new interface driver cdc_wdm  
  141. [    1.471412] usbcore: registered new interface driver usb-storage  
  142. [    1.477942] usbcore: registered new interface driver usbtest  
  143. [    1.486105] mousedev: PS/2 mouse device common for all mice  
  144. [    1.496690] omap_rtc 44e3e000.rtc: rtc core: registered 44e3e000.rtc as rtc0  
  145. [    1.504827] i2c /dev entries driver  
  146. [    1.508655] Driver for 1-wire Dallas network protocol.  
  147. [    1.517293] omap_wdt: OMAP Watchdog Timer Rev 0x01: initial timeout 60 sec  
  148. [    1.527282] omap_hsmmc 48060000.mmc: unable to get vmmc regulator -517  
  149. [    1.534612] platform 48060000.mmc: Driver omap_hsmmc requests probe deferral  
  150. [    1.544215] ledtrig-cpu: registered to indicate activity on CPUs  
  151. [    1.551195] usbcore: registered new interface driver usbhid  
  152. [    1.557065] usbhid: USB HID core driver  
  153. [    1.575960] davinci_evm sound: ASoC: CODEC (null) not registered  
  154. [    1.582524] davinci_evm sound: snd_soc_register_card failed (-517)  
  155. [    1.589121] platform sound: Driver davinci_evm requests probe deferral  
  156. [    1.596830] oprofile: using arm/armv7  
  157. [    1.601311] TCP: cubic registered  
  158. [    1.604789] Initializing XFRM netlink socket  
  159. [    1.609445] NET: Registered protocol family 17  
  160. [    1.614179] NET: Registered protocol family 15  
  161. [    1.619196] Key type dns_resolver registered  
  162. [    1.623867] omap_voltage_late_init: Voltage driver support not added  
  163. [    1.630565] sr_dev_init: No voltage domain specified for smartreflex0. Cannot initialize  
  164. [    1.639038] sr_dev_init: No voltage domain specified for smartreflex1. Cannot initialize  
  165. [    1.648614] ThumbEE CPU extension supported.  
  166. [    1.653130] Registering SWP/SWPB emulation handler  
  167. [    1.658211] SmartReflex Class3 initialized  
  168. [    1.667886] omap-gpmc 50000000.gpmc: GPMC revision 6.0  
  169. [    1.674877] nand: device found, Manufacturer ID: 0xec, Chip ID: 0xd3  
  170. [    1.681647] nand: Samsung NAND 1GiB 3,3V 8-bit  
  171. [    1.686312] nand: 1024MiB, SLC, page size: 2048, OOB size: 64  
  172. [    1.692312] nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled  
  173. [    1.698428] omap2-nand: probe of omap2-nand.0 failed with error -22  
  174. [    1.790962] tps65910 0-002d: No interrupt support, no core IRQ  
  175. [    1.807488] vrtc: 1800 mV   
  176. [    1.810865] vrtc: supplied by vbat  
  177. [    1.818190] vio: at 1500 mV   
  178. [    1.821460] vio: supplied by vbat  
  179. [    1.828397] vdd_mpu: 912 <--> 1312 mV at 1325 mV   
  180. [    1.833532] vdd_mpu: supplied by vbat  
  181. [    1.840598] vdd_core: 912 <--> 1150 mV at 1137 mV   
  182. [    1.845924] vdd_core: supplied by vbat  
  183. [    1.852537] vdd3: 5000 mV   
  184. [    1.858001] vdig1: at 1800 mV   
  185. [    1.861420] vdig1: supplied by vbat  
  186. [    1.867904] vdig2: at 1800 mV   
  187. [    1.871302] vdig2: supplied by vbat  
  188. [    1.878529] vpll: at 1800 mV   
  189. [    1.881866] vpll: supplied by vbat  
  190. [    1.888426] vdac: at 1800 mV   
  191. [    1.891747] vdac: supplied by vbat  
  192. [    1.898169] vaux1: at 1800 mV   
  193. [    1.901568] vaux1: supplied by vbat  
  194. [    1.908027] vaux2: at 3300 mV   
  195. [    1.911421] vaux2: supplied by vbat  
  196. [    1.917833] vaux33: at 3300 mV   
  197. [    1.921323] vaux33: supplied by vbat  
  198. [    1.927806] vmmc: 1800 <--> 3300 mV at 3300 mV   
  199. [    1.932761] vmmc: supplied by vbat  
  200. [    1.938842] vbb: at 3000 mV   
  201. [    1.942302] vbb: supplied by vbat  
  202. [    1.949841] omap_i2c 44e0b000.i2c: bus 0 rev0.11 at 400 kHz  
  203. [    1.963667] omap_i2c 4802a000.i2c: bus 1 rev0.11 at 100 kHz  
  204. [    2.007363] wm8960 0-001a: No platform data supplied  
  205. [    2.084399] mmc0: host does not support reading read-only switch. assuming write-enable.  
  206. [    2.095817] mmc0: new high speed SDHC card at address aaaa  
  207. [    2.104312] mmcblk0: mmc0:aaaa SL16G 14.8 GiB   
  208. [    2.116665]  mmcblk0: p1 p2  
  209. [    2.131506] davinci_evm sound: wm8960-hifi <-> 4803c000.mcasp mapping ok  
  210. [    2.215823] davinci_mdio 4a101000.mdio: davinci mdio revision 1.6  
  211. [    2.222212] davinci_mdio 4a101000.mdio: detected phy mask ffffffde  
  212. [    2.232273] libphy: 4a101000.mdio: probed  
  213. [    2.236597] davinci_mdio 4a101000.mdio: phy[0]: device 4a101000.mdio:00, driver unknown  
  214. [    2.244957] davinci_mdio 4a101000.mdio: phy[5]: device 4a101000.mdio:05, driver unknown  
  215. [    2.254567] cpsw 4a100000.ethernet: Detected MACID = c4:ed:ba:88:b5:e4  
  216. [    2.266507] input: gpio_keyad@0 as /devices/gpio_keyad@0/input/input0  
  217. [    2.276227] omap_rtc 44e3e000.rtc: setting system clock to 2000-01-01 00:00:00 UTC (946684800)  
  218. [    2.285247] sr_init: No PMIC hook to init smartreflex  
  219. [    2.290884] sr_init: platform driver register failed for SR  
  220. [    2.313832] lis3_reg: disabling  
  221. [    2.317496] ALSA device list:  
  222. [    2.320598]   #0: AM335x-EVM  
  223. [    2.434398] kjournald starting.  Commit interval 5 seconds  
  224. [    2.444085] EXT3-fs (mmcblk0p2): using internal journal  
  225. [    2.452049] EXT3-fs (mmcblk0p2): recovery complete  
  226. [    2.457123] EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode  
  227. [    2.464445] VFS: Mounted root (ext3 filesystem) on device 179:2.  
  228. [    2.474111] devtmpfs: mounted  
  229. [    2.478057] Freeing unused kernel memory: 408K (c0859000 - c08bf000)  
  230. ----------mount all..........  
  231. ----------Starting mdev......  
  232.   
  233. Please press Enter to activate this console.   
  234. @tq335x #  
從Log信息中很容易看到ALSA device list已經出現了AM335x-EVM項。到這裏TQ335x已經能夠識別到聲卡了。

6. 測試

測試ALSA聲卡驅動的常用方法是移植alsa-lib和alsa-utils,使用alsa-utils提供的arecord來測試聲卡的錄音,aplay來測試播放。alsa-lib和alsa-utils的移植教程有很多,這裏我就不多講了(如果有不明白這塊的可以留言)。

錄音測試:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. arecord -f cd test.wav  
播放測試:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. aplay test.wav  
播放時就可以聽到之前錄製的聲音的。

7. 總結

調試聲卡驅動大約進行了三週,也算是略有心得。

(1) 必要的工具:我調試的時候手頭上工具不夠齊全。我是在家裏調試的,沒有示波器,也就無法測量BCLK和LRCLK時鐘,調試了很久都不知道WM8960到底有沒有工作,因此,必要的工具可以有效的提高調試效率。

(2) 先調試放音,wm8960放音再調試錄音。放音可以很容易檢測效果,錄音則沒有方便的檢測手段。同時,放音的配置比錄音要簡單些,可以有效檢測驅動部分是否存在問題。


以上是完整的WM8960驅動移植過程,如果疑問歡迎留言討論。




本文作者:girlkoo

本文連接:http://blog.csdn.net/girlkoo/article/details/42042555

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章