天天看點

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,該節點用來描述單闆上聲霸卡裝置資訊,修改後的内容如下:

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

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 =  

        "headphone jack",       "hp_l",  

        "headphone jack",       "hp_r",  

        "linput1",              "line in";  

};  

含義解釋:

(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節點内添加如下資訊(類似上篇文章中觸摸裝置驅動節點):

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

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(TQ335x)學習筆記——WM8960聲霸卡驅動移植

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節點中修改,具體的修改如下:

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

&mcasp1 {  

        pinctrl-names = "default";  

        pinctrl-0 = <&am335x_evm_audio_pins>;  

        status = "okay";  

        op-mode = <0>;          /* mcasp_iis_mode */  

        tdm-slots = <2>;  

        /* 4 serializers */  

        serial-dir = <  /* 0: inactive, 1: tx, 2: rx */  

            1 2 0 0  

        >;  

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

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

static const struct of_device_id wm8960_of_match[] = {  

    { .compatible = "wlf,wm8960", },  

    { }  

module_device_table(of, wm8960_of_match);  

static struct i2c_driver wm8960_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進行額外的初始化,修改後的代碼片段如下:

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

static int wm8960_probe(struct snd_soc_codec *codec)  

{  

    struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);  

    struct wm8960_data *pdata = dev_get_platdata(codec->dev);  

    int ret;  

    wm8960->set_bias_level = wm8960_set_bias_level_out3;  

    if (!pdata) {  

        dev_warn(codec->dev, "no platform data supplied\n");  

    } else {  

        if (pdata->capless)  

            wm8960->set_bias_level = wm8960_set_bias_level_capless;  

    }  

    ret = wm8960_reset(codec);  

    if (ret < 0) {  

        dev_err(codec->dev, "failed to issue reset\n");  

        return ret;  

    wm8960->set_bias_level(codec, snd_soc_bias_standby);  

    /* latch the update bits */  

    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);  

    /* other configuration */  

    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);  

    return 0;  

}  

具體的含義可以參考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添加如下兩行資訊:

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

{ "left dac", null, "left input mixer" },  

{ "right dac", null, "right input mixer" },  

這樣在錄音時也會使能dac産生lrclk。

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

3. 編寫machine驅動

核心代碼有個很好的例子就是davinci-evm.c,這是am335x-evm評估闆的machine驅動,該評估采用的codec并不是wm8960,是以,我們在該檔案中添加wm8960資訊即可。具體的修改如下:

step1. 添加compatible資訊。修改後的内容如下:

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

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。需要添加如下代碼:

AM335x(TQ335x)學習筆記——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相關的設定,本人了解也不是非常深刻,直接貼上代碼,具體如下:

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

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 );  

step4. 實作evm_wm8960_ops及相關函數,需要添加如下代碼:

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

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)  

    /* set the cpu system clock */  

    ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, snd_soc_clock_in);  

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編譯選項,修改後的内容如下:

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

config snd_soc_wm8960  

    tristate "wolfson microelectronics wm8960 codec"  

    depends on i2c && input  

step2.  通過menuconfig配置核心

執行指令:

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

make arch=arm cross_compile=arm-linux-gnueabi- menuconfig  

進行如下修改:

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

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  

重新編譯核心:

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

make arch=arm cross_compile=arm-linux-gnueabi- -j8  

5. 效果

将編譯後的核心檔案zimage和tq335x.dtb檔案拷貝sd卡并啟動開發闆,按任意鍵進入uboot指令模式,輸入如下指令:

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

load mmc 0:1 0x88000000 /boot/tq335x.dtb  

load mmc 0:1 0x82000000 /boot/zimage  

bootz 0x82000000 - 0x88000000  

通過上面的三條指令可以啟動核心,完整的log資訊如下:

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

starting kernel ...  

[    0.000000] booting linux on physical cpu 0x0  

[    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  

[    0.000000] cpu: armv7 processor [413fc082] revision 2 (armv7), cr=10c5387d  

[    0.000000] cpu: pipt / vipt nonaliasing data cache, vipt aliasing instruction cache  

[    0.000000] machine model: ti am335x evm  

[    0.000000] cma: reserved 16 mib at 9e800000  

[    0.000000] memory policy: data cache writeback  

[    0.000000]   highmem zone: 1048574 pages exceeds freesize 0  

[    0.000000] cpu: all cpu(s) started in svc mode.  

[    0.000000] am335x es2.1 (sgx neon )  

[    0.000000] percpu: embedded 9 pages/cpu @dfa99000 s14336 r8192 d14336 u36864  

[    0.000000] built 1 zonelists in zone order, mobility grouping on.  total pages: 129792  

[    0.000000] kernel command line: console=ttyo0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext3 rootwait  

[    0.000000] pid hash table entries: 2048 (order: 1, 8192 bytes)  

[    0.000000] dentry cache hash table entries: 65536 (order: 6, 262144 bytes)  

[    0.000000] inode-cache hash table entries: 32768 (order: 5, 131072 bytes)  

[    0.000000] memory: 484124k/523264k available (6070k kernel code, 666k rwdata, 2444k rodata, 410k init, 8214k bss, 39140k reserved, 0k highmem)  

[    0.000000] virtual kernel memory layout:  

[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kb)  

[    0.000000]     fixmap  : 0xffc00000 - 0xffe00000   (2048 kb)  

[    0.000000]     vmalloc : 0xe0800000 - 0xff000000   ( 488 mb)  

[    0.000000]     lowmem  : 0xc0000000 - 0xe0000000   ( 512 mb)  

[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 mb)  

[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 mb)  

[    0.000000]       .text : 0xc0008000 - 0xc0858bc0   (8515 kb)  

[    0.000000]       .init : 0xc0859000 - 0xc08bf800   ( 410 kb)  

[    0.000000]       .data : 0xc08c0000 - 0xc0966b50   ( 667 kb)  

[    0.000000]        .bss : 0xc0966b50 - 0xc116c6e0   (8215 kb)  

[    0.000000] hierarchical rcu implementation.  

[    0.000000]  rcu restricting cpus from nr_cpus=2 to nr_cpu_ids=1.  

[    0.000000] rcu: adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1  

[    0.000000] nr_irqs:16 nr_irqs:16 16  

[    0.000000] irq: found an intc at 0xfa200000 (revision 5.0) with 128 interrupts  

[    0.000000] total of 128 interrupts on 1 active controller  

[    0.000000] omap clockevent source: timer2 at 24000000 hz  

[    0.000015] sched_clock: 32 bits at 24mhz, resolution 41ns, wraps every 178956969942ns  

[    0.000061] omap clocksource: timer1 at 24000000 hz  

[    0.000798] console: colour dummy device 80x30  

[    0.000849] lock dependency validator: copyright (c) 2006 red hat, inc., ingo molnar  

[    0.000858] ... max_lockdep_subclasses:  8  

[    0.000865] ... max_lock_depth:          48  

[    0.000873] ... max_lockdep_keys:        8191  

[    0.000880] ... classhash_size:          4096  

[    0.000887] ... max_lockdep_entries:     32768  

[    0.000894] ... max_lockdep_chains:      65536  

[    0.000901] ... chainhash_size:          32768  

[    0.000909]  memory used by lock dependency info: 5167 kb  

[    0.000916]  per task-struct memory footprint: 1152 bytes  

[    0.000956] calibrating delay loop... 996.14 bogomips (lpj=4980736)  

[    0.079039] pid_max: default: 32768 minimum: 301  

[    0.079431] security framework initialized  

[    0.079555] mount-cache hash table entries: 1024 (order: 0, 4096 bytes)  

[    0.079568] mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)  

[    0.081736] cpu: testing write buffer coherency: ok  

[    0.082916] cpu0: thread -1, cpu 0, socket -1, mpidr 0  

[    0.083033] setting up static identity map for 0x805bf4f0 - 0x805bf560  

[    0.086259] brought up 1 cpus  

[    0.086278] smp: total of 1 processors activated.  

[    0.086288] cpu: all cpu(s) started in svc mode.  

[    0.088875] devtmpfs: initialized  

[    0.097689] vfp support v0.3: implementor 41 architecture 3 part 30 variant c rev 3  

[    0.133508] omap_hwmod: tptc0 using broken dt data from edma  

[    0.133865] omap_hwmod: tptc1 using broken dt data from edma  

[    0.134203] omap_hwmod: tptc2 using broken dt data from edma  

[    0.142102] omap_hwmod: debugss: _wait_target_disable failed  

[    0.200093] pinctrl core: initialized pinctrl subsystem  

[    0.202608] regulator-dummy: no parameters  

[    0.232298] net: registered protocol family 16  

[    0.240800] dma: preallocated 256 kib pool for atomic coherent allocations  

[    0.243054] cpuidle: using governor ladder  

[    0.243083] cpuidle: using governor menu  

[    0.255025] omap gpio hardware version 0.1  

[    0.270226] omap-gpmc 50000000.gpmc: could not find pctldev for node /pinmux@44e10800/nandflash_pins_s0, deferring probe  

[    0.270268] platform 50000000.gpmc: driver omap-gpmc requests probe deferral  

[    0.274762] hw-breakpoint: debug architecture 0x4 unsupported.  

[    0.319722] edma-dma-engine edma-dma-engine.0: ti edma dma engine driver  

[    0.321054] vbat: 5000 mv   

[    0.321851] lis3_reg: no parameters  

[    0.325260] scsi subsystem initialized  

[    0.326060] usbcore: registered new interface driver usbfs  

[    0.326235] usbcore: registered new interface driver hub  

[    0.330180] usbcore: registered new device driver usb  

[    0.331021] omap_i2c 44e0b000.i2c: could not find pctldev for node /pinmux@44e10800/pinmux_i2c0_pins, deferring probe  

[    0.331059] platform 44e0b000.i2c: driver omap_i2c requests probe deferral  

[    0.331115] omap_i2c 4802a000.i2c: could not find pctldev for node /pinmux@44e10800/pinmux_i2c1_pins, deferring probe  

[    0.331139] platform 4802a000.i2c: driver omap_i2c requests probe deferral  

[    0.332318] advanced linux sound architecture driver initialized.  

[    0.335684] switched to clocksource timer1  

[    0.486994] net: registered protocol family 2  

[    0.488860] tcp established hash table entries: 4096 (order: 2, 16384 bytes)  

[    0.489040] tcp bind hash table entries: 4096 (order: 5, 147456 bytes)  

[    0.490403] tcp: hash tables configured (established 4096 bind 4096)  

[    0.490593] tcp: reno registered  

[    0.490617] udp hash table entries: 256 (order: 2, 20480 bytes)  

[    0.490807] udp-lite hash table entries: 256 (order: 2, 20480 bytes)  

[    0.491827] net: registered protocol family 1  

[    0.493704] rpc: registered named unix socket transport module.  

[    0.493729] rpc: registered udp transport module.  

[    0.493738] rpc: registered tcp transport module.  

[    0.493747] rpc: registered tcp nfsv4.1 backchannel transport module.  

[    0.495022] hw perfevents: enabled with armv7_cortex_a8 pmu driver, 5 counters available  

[    0.499438] futex hash table entries: 256 (order: 2, 16384 bytes)  

[    0.504727] vfs: disk quotas dquot_6.5.2  

[    0.504882] dquot-cache hash table entries: 1024 (order 0, 4096 bytes)  

[    0.507359] nfs: registering the id_resolver key type  

[    0.507727] key type id_resolver registered  

[    0.507743] key type id_legacy registered  

[    0.507886] jffs2: version 2.2. (nand) (summary)  漏 2001-2006 red hat, inc.  

[    0.508320] msgmni has been set to 977  

[    0.513238] io scheduler noop registered  

[    0.513269] io scheduler deadline registered  

[    0.513341] io scheduler cfq registered (default)  

[    0.515815] pinctrl-single 44e10800.pinmux: 142 pins at pa f9e10800 size 568  

[    0.520975] backlight supply power not found, using dummy regulator  

[    0.524309] serial: 8250/16550 driver, 4 ports, irq sharing enabled  

[    0.530939] omap_uart 44e09000.serial: no wakeirq for uart0  

[    0.531575] 44e09000.serial: ttyo0 at mmio 0x44e09000 (irq = 88, base_baud = 3000000) is a omap uart0  

[    1.231857] console [ttyo0] enabled  

[    1.241315] omap_rng 48310000.rng: omap random number generator ver. 20  

[    1.248987] [drm] initialized drm 1.1.0 20060810  

[    1.261218] [drm] supports vblank timestamp caching rev 2 (21.10.2013).  

[    1.268316] [drm] no driver support for vblank timestamp query.  

[    1.320991] console: switching to colour frame buffer device 100x30  

[    1.332042] tilcdc 4830e000.lcdc: fb0:  frame buffer device  

[    1.337919] tilcdc 4830e000.lcdc: registered panic notifier  

[    1.343814] [drm] initialized tilcdc 1.0.0 20121205 on minor 0  

[    1.380804] brd: module loaded  

[    1.398539] loop: module loaded  

[    1.404724] mtdoops: mtd device (mtddev=name/number) must be supplied  

[    1.414737] usbcore: registered new interface driver asix  

[    1.420619] usbcore: registered new interface driver ax88179_178a  

[    1.427154] usbcore: registered new interface driver cdc_ether  

[    1.433416] usbcore: registered new interface driver smsc95xx  

[    1.439572] usbcore: registered new interface driver net1080  

[    1.445625] usbcore: registered new interface driver cdc_subset  

[    1.451932] usbcore: registered new interface driver zaurus  

[    1.457997] usbcore: registered new interface driver cdc_ncm  

[    1.465136] usbcore: registered new interface driver cdc_wdm  

[    1.471412] usbcore: registered new interface driver usb-storage  

[    1.477942] usbcore: registered new interface driver usbtest  

[    1.486105] mousedev: ps/2 mouse device common for all mice  

[    1.496690] omap_rtc 44e3e000.rtc: rtc core: registered 44e3e000.rtc as rtc0  

[    1.504827] i2c /dev entries driver  

[    1.508655] driver for 1-wire dallas network protocol.  

[    1.517293] omap_wdt: omap watchdog timer rev 0x01: initial timeout 60 sec  

[    1.527282] omap_hsmmc 48060000.mmc: unable to get vmmc regulator -517  

[    1.534612] platform 48060000.mmc: driver omap_hsmmc requests probe deferral  

[    1.544215] ledtrig-cpu: registered to indicate activity on cpus  

[    1.551195] usbcore: registered new interface driver usbhid  

[    1.557065] usbhid: usb hid core driver  

[    1.575960] davinci_evm sound: asoc: codec (null) not registered  

[    1.582524] davinci_evm sound: snd_soc_register_card failed (-517)  

[    1.589121] platform sound: driver davinci_evm requests probe deferral  

[    1.596830] oprofile: using arm/armv7  

[    1.601311] tcp: cubic registered  

[    1.604789] initializing xfrm netlink socket  

[    1.609445] net: registered protocol family 17  

[    1.614179] net: registered protocol family 15  

[    1.619196] key type dns_resolver registered  

[    1.623867] omap_voltage_late_init: voltage driver support not added  

[    1.630565] sr_dev_init: no voltage domain specified for smartreflex0. cannot initialize  

[    1.639038] sr_dev_init: no voltage domain specified for smartreflex1. cannot initialize  

[    1.648614] thumbee cpu extension supported.  

[    1.653130] registering swp/swpb emulation handler  

[    1.658211] smartreflex class3 initialized  

[    1.667886] omap-gpmc 50000000.gpmc: gpmc revision 6.0  

[    1.674877] nand: device found, manufacturer id: 0xec, chip id: 0xd3  

[    1.681647] nand: samsung nand 1gib 3,3v 8-bit  

[    1.686312] nand: 1024mib, slc, page size: 2048, oob size: 64  

[    1.692312] nand: error: config_mtd_nand_omap_bch not enabled  

[    1.698428] omap2-nand: probe of omap2-nand.0 failed with error -22  

[    1.790962] tps65910 0-002d: no interrupt support, no core irq  

[    1.807488] vrtc: 1800 mv   

[    1.810865] vrtc: supplied by vbat  

[    1.818190] vio: at 1500 mv   

[    1.821460] vio: supplied by vbat  

[    1.828397] vdd_mpu: 912 <--> 1312 mv at 1325 mv   

[    1.833532] vdd_mpu: supplied by vbat  

[    1.840598] vdd_core: 912 <--> 1150 mv at 1137 mv   

[    1.845924] vdd_core: supplied by vbat  

[    1.852537] vdd3: 5000 mv   

[    1.858001] vdig1: at 1800 mv   

[    1.861420] vdig1: supplied by vbat  

[    1.867904] vdig2: at 1800 mv   

[    1.871302] vdig2: supplied by vbat  

[    1.878529] vpll: at 1800 mv   

[    1.881866] vpll: supplied by vbat  

[    1.888426] vdac: at 1800 mv   

[    1.891747] vdac: supplied by vbat  

[    1.898169] vaux1: at 1800 mv   

[    1.901568] vaux1: supplied by vbat  

[    1.908027] vaux2: at 3300 mv   

[    1.911421] vaux2: supplied by vbat  

[    1.917833] vaux33: at 3300 mv   

[    1.921323] vaux33: supplied by vbat  

[    1.927806] vmmc: 1800 <--> 3300 mv at 3300 mv   

[    1.932761] vmmc: supplied by vbat  

[    1.938842] vbb: at 3000 mv   

[    1.942302] vbb: supplied by vbat  

[    1.949841] omap_i2c 44e0b000.i2c: bus 0 rev0.11 at 400 khz  

[    1.963667] omap_i2c 4802a000.i2c: bus 1 rev0.11 at 100 khz  

[    2.007363] wm8960 0-001a: no platform data supplied  

[    2.084399] mmc0: host does not support reading read-only switch. assuming write-enable.  

[    2.095817] mmc0: new high speed sdhc card at address aaaa  

[    2.104312] mmcblk0: mmc0:aaaa sl16g 14.8 gib   

[    2.116665]  mmcblk0: p1 p2  

[    2.131506] davinci_evm sound: wm8960-hifi <-> 4803c000.mcasp mapping ok  

[    2.215823] davinci_mdio 4a101000.mdio: davinci mdio revision 1.6  

[    2.222212] davinci_mdio 4a101000.mdio: detected phy mask ffffffde  

[    2.232273] libphy: 4a101000.mdio: probed  

[    2.236597] davinci_mdio 4a101000.mdio: phy[0]: device 4a101000.mdio:00, driver unknown  

[    2.244957] davinci_mdio 4a101000.mdio: phy[5]: device 4a101000.mdio:05, driver unknown  

[    2.254567] cpsw 4a100000.ethernet: detected macid = c4:ed:ba:88:b5:e4  

[    2.266507] input: gpio_keyad@0 as /devices/gpio_keyad@0/input/input0  

[    2.276227] omap_rtc 44e3e000.rtc: setting system clock to 2000-01-01 00:00:00 utc (946684800)  

[    2.285247] sr_init: no pmic hook to init smartreflex  

[    2.290884] sr_init: platform driver register failed for sr  

[    2.313832] lis3_reg: disabling  

[    2.317496] alsa device list:  

[    2.320598]   #0: am335x-evm  

[    2.434398] kjournald starting.  commit interval 5 seconds  

[    2.444085] ext3-fs (mmcblk0p2): using internal journal  

[    2.452049] ext3-fs (mmcblk0p2): recovery complete  

[    2.457123] ext3-fs (mmcblk0p2): mounted filesystem with ordered data mode  

[    2.464445] vfs: mounted root (ext3 filesystem) on device 179:2.  

[    2.474111] devtmpfs: mounted  

[    2.478057] freeing unused kernel memory: 408k (c0859000 - c08bf000)  

----------mount all..........  

----------starting mdev......  

please press enter to activate this console.   

@tq335x #  

從log資訊中很容易看到alsa device list已經出現了am335x-evm項。到這裡tq335x已經能夠識别到聲霸卡了。

6. 測試

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

錄音測試:

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

arecord -f cd test.wav  

播放測試:

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

aplay test.wav  

播放時就可以聽到之前錄制的聲音的。

7. 總結

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

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

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

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

繼續閱讀