zoukankan      html  css  js  c++  java
  • I.mx6s上移植wm8960驱动(基于linux3.0.101版本)

    I.mx6s上移植wm8960驱动

      此篇博文只记录移植的步骤,其他不做分析。首先上一张wm8960的硬件连接图:







































    1  上电操作
       配置wm8960的上电脚,文件位置:arch/arm/mach-mx6/board-mx6q_sabresd.c

    [html] view plain copy
     
     print?
    1.         #define SABRESD_CODEC_PWR_EN    IMX_GPIO_NR(7, 12)  
    2. 440     /* Enable wm8960 power supply */  
    3. 441     gpio_request(SABRESD_CODEC_PWR_EN, "audio-power");  
    4. 442     gpio_direction_output(SABRESD_CODEC_PWR_EN, 1);  
    5. 443     msleep(1);  
    6. 444     gpio_set_value(SABRESD_CODEC_PWR_EN, 1);  
    7. 445     printk("Power up wm8960 successful %s ", __FUNCTION__);  

    另外,根据原理图可知上电脚为GPIO17,所以相关配置头文件里需将其配置为gpio口,文件位置:arch/arm/mach-mx6/board-mx6dl_sabresd.h

    [html] view plain copy
     
     print?
    1. 236     /* CODEC_PWR_EN */  
    2. 237     MX6DL_PAD_GPIO_17__GPIO_7_12,  

    2:配置I2C,用于client的生成,文件位置:arch/arm/mach-mx6/board-mx6q_sabresd.c 需确认你的i2c是接的哪个控制器。

    [html] view plain copy
     
     print?
    1.  805 static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {  
    2.  806     {  
    3.  807         I2C_BOARD_INFO("wm8960", 0x1a),  
    4.  808     },  
    5. };  

    3: 修改wm8960  codec相关的数据结构,此处根据wm8962修改而来,文件位置:arch/arm/mach-mx6/board-mx6q_sabresd.c
    以下是修改的地方

    [html] view plain copy
     
     print?
    1.  57 #include <sound/wm8962.h>  
    2.  58 #include <sound/wm8960.h>  
    3.   
    4.         ...省略部分内容...  
    5.   
    6.  410 static struct platform_device mx6_sabresd_audio_wm8960_device = {  
    7.  411     .name = "imx-wm8960",  
    8.  412 };  
    9.  413   
    10.  414 static struct mxc_audio_platform_data wm8960_data;  
    11.  415   
    12.  416 static int wm8960_clk_enable(int enable)  
    13.  417 {  
    14.  418     if (enable) {  
    15.  419         clk_enable(clko);  
    16.  420         printk("%s:wm clk enable ", __FUNCTION__);  
    17.  421     }  
    18.  422     else {  
    19.  423         clk_disable(clko);  
    20.  424         printk("%s:wm clk disable ", __FUNCTION__);  
    21.  425     }  
    22.  426     return 0;  
    23.  427 }  
    24.  428  
    25.  429 static int mxc_wm8960_init(void)  
    26.  430 {  
    27.  431     int rate;  
    28.  432   
    29.  433     clko = clk_get(NULL, "clko_clk");  
    30.  434     if (IS_ERR(clko)) {  
    31.  435         pr_err("can't get CLKO clock. ");  
    32.  436         return PTR_ERR(clko);  
    33.  437     }  
    34.  438     /* both audio codec and comera use CLKO clk*/  
    35.  439     rate = clk_round_rate(clko, 24000000);  
    36.  440     clk_set_rate(clko, rate);  
    37.  441   
    38.  442     wm8960_data.sysclk = rate;  
    39.  443   
    40.  444     /* Enable wm8960 power supply */  
    41.  445     gpio_request(SABRESD_CODEC_PWR_EN, "audio-power");  
    42.  446     gpio_direction_output(SABRESD_CODEC_PWR_EN, 1);  
    43.  447     msleep(1);  
    44.  448     gpio_set_value(SABRESD_CODEC_PWR_EN, 1);  
    45.  449     printk("%s:Power up wm8960 successful ", __FUNCTION__);  
    46.  450   
    47.  451     return 0;  
    48.  452 }  
    49.  453   
    50.  454 /* Note: we use struct wm8962_pdata for wm8960_config_data */  
    51.  455 /* struct wm8962_pdata defind at linux/wm8962.h */  
    52.  456 static struct wm8962_pdata wm8960_config_data = {  
    53.  457     .gpio_init = {  
    54.  458         [2] = WM8960_GPIO_FN_DMICCLK,  
    55.  459         [4] = 0x8000 | WM8960_GPIO_FN_DMICDAT,  
    56.  460     },  
    57.  461     .clock_enable = wm8960_clk_enable,  
    58.  462 };  
    59.  463   
    60.  464 static struct mxc_audio_platform_data wm8960_data = {  
    61.  465     .ssi_num = 1,  
    62.  466     .src_port = 2,  
    63.  467     .ext_port = 3,  
    64.  468     .hp_gpio = -1,                  //SABRESD_HEADPHONE_DET,  
    65.  469 //  .hp_active_low = 1,  
    66.  470     .mic_gpio = -1,                 //SABRESD_MICROPHONE_DET,  
    67.  471 //  .mic_active_low = 1,  
    68.  472     .init = mxc_wm8960_init,  
    69.  473     .clock_enable = wm8960_clk_enable,  
    70.  474 };  
    71.  475   
    72.  476 static struct regulator_consumer_supply sabresd_vwm8960_consumers[] = {  
    73.  477     REGULATOR_SUPPLY("SPKVDD1", "0-001a"),  
    74.  478     REGULATOR_SUPPLY("SPKVDD2", "0-001a"),  
    75.  479 };  
    76.  480   
    77.  481 static struct regulator_init_data sabresd_vwm8960_init = {  
    78.  482     .constraints = {  
    79.  483         .name = "SPKVDD",  
    80.  484         .valid_ops_mask =  REGULATOR_CHANGE_STATUS,  
    81.  485         .boot_on = 1,  
    82.  486     },  
    83.  487     .num_consumer_supplies = ARRAY_SIZE(sabresd_vwm8960_consumers),  
    84.  488     .consumer_supplies = sabresd_vwm8960_consumers,  
    85.  489 };  
    86.  490   
    87.  491 static struct fixed_voltage_config sabresd_vwm8960_reg_config = {  
    88.  492     .supply_name    = "SPKVDD",  
    89.  493     .microvolts     = 4200000,  
    90.  494     .gpio           = SABRESD_CODEC_PWR_EN,  
    91.  495     .enable_high    = 1,  
    92.  496     .enabled_at_boot = 1,  
    93.  497     .init_data      = &sabresd_vwm8960_init,  
    94.  498 };  
    95.  499   
    96.  500 static struct platform_device sabresd_vwm8960_reg_devices = {  
    97.  501     .name   = "reg-fixed-voltage",  
    98.  502     .id     = 4,  
    99.  503     .dev    = {  
    100.  504         .platform_data = &sabresd_vwm8960_reg_config,  
    101.  505     },  
    102.  506 };  
    103.         ...省略部分内容...  
    104.   
    105.  811 static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {  
    106.  812     {  
    107.  813         I2C_BOARD_INFO("wm8960", 0x1a),  
    108.  814     },  
    109.  815     {  
    110.  816         I2C_BOARD_INFO("ov564x", 0x3c),  
    111.  817         .platform_data = (void *)&camera_data,  
    112.  818     },  
    113.  819     {  
    114.  820         I2C_BOARD_INFO("mma8451", 0x1c),  
    115.  821         .platform_data = (void *)&mma8451_position,  
    116.  822     },  
    117.  823 };  
    118.  824   
    119.          ...省略部分内容...  
    120.   
    121. 1535 static int __init imx6q_init_audio(void)  
    122. 1536 {  
    123. 1537     if (board_is_mx6_reva()) {  
    124. 1538         mxc_register_device(&mx6_sabresd_audio_wm8958_device,  
    125. 1539                     &wm8958_data);  
    126. 1540         imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata);  
    127. 1541   
    128. 1542         mxc_wm8958_init();  
    129. 1543     } else {  
    130. 1544         platform_device_register(&sabresd_vwm8960_reg_devices);  
    131. 1545         mxc_register_device(&mx6_sabresd_audio_wm8960_device,  
    132. 1546                     &wm8960_data);  
    133. 1547         imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata);  
    134. 1548   
    135. 1549         mxc_wm8960_init();  
    136. 1550         printk("%s ", __FUNCTION__);  
    137. 1551     }  
    138. 1552   
    139. 1553     return 0;  
    140. 1554 }  
    141.   
    142.          ...省略部分内容...  
    143.   
    144. 1859     if (board_is_mx6_reva()) {  
    145. 1860         strcpy(mxc_i2c0_board_info[0].type, "wm8958");  
    146. 1861         mxc_i2c0_board_info[0].platform_data = &wm8958_config_data;  
    147. 1862     } else {  
    148. 1863         strcpy(mxc_i2c0_board_info[0].type, "wm8960");  
    149. 1864         mxc_i2c0_board_info[0].platform_data = &wm8960_config_data;  
    150. 1865     }  

    4 修改wm8960.h:include/sound/wm8960.h

    [html] view plain copy
     
     print?
    1. 9 #ifndef _WM8960_PDATA_H  
    2. 10 #define _WM8960_PDATA_H  
    3. 11   
    4. 12 #define WM8960_DRES_400R 0  
    5. 13 #define WM8960_DRES_200R 1  
    6. 14 #define WM8960_DRES_600R 2  
    7. 15 #define WM8960_DRES_150R 3  
    8. 16 #define WM8960_MAX_GPIO  6  
    9. 17   
    10. 18 #define WM8960_GPIO_FN_DMICCLK  19  
    11. 19 #define WM8960_GPIO_FN_DMICDAT  20  
    12. 20   
    13. 21   
    14. 22 struct wm8960_data {  
    15. 23     bool capless;  /* Headphone outputs configured in capless mode */  
    16. 24       
    17. 25     int dres;  /* Discharge resistance for headphone outputs */  
    18. 26     
    19. 27     int gpio_base;  
    20. 28     u32 gpio_init[WM8960_MAX_GPIO];  
    21. 29     
    22. 30     u32 mic_cfg;  
    23. 31     bool irq_active_low;  
    24. 32     bool spk_mono;  
    25. 33 };  
    26. 34   
    27. 35 #endif  

    5 拷贝imx-wm8960.c到sound/soc/imx/目录下(获取地址:https://github.com/PDi-Communication-Systems-Inc/kernel-imx/blob/6bfe025386e4419a50b1b1d5a847a1329d1745cd/sound/soc/imx/imx-wm8960.c)

    修改同目录下Kconfig,添加如下:
    [html] view plain copy
     
     print?
    1. 80 config SND_SOC_IMX_WM8960  
    2. 81     tristate "SoC Audio support for IMX boards with WM8960"  
    3. 82     select SND_MXC_SOC_MX2  
    4. 83     select SND_SOC_WM8960  
    5. 84     help  
    6. 85       Say Y if you want to add support for SoC audio on an i.MX board with  
    7. 86       a WM8960 codec.  

    修改同目录下Makefile:

    [html] view plain copy
     
     print?
    1. 18 snd-soc-imx-wm8960-objs := imx-wm8960.o  
    2. 30 obj-$(CONFIG_SND_SOC_IMX_WM8960) += snd-soc-imx-wm8960.o  

    用make menuconfig配置上wm8960,编译下载至开发板即可进行验证。

     Ps :一些调试命令及输出log:
    [html] view plain copy
     
     print?
    1. root@imx6solo ~$ cat /proc/asound/cards   
    2.  0 [wm8960audio    ]: wm8960-audio - wm8960-audio  
    3.                       wm8960-audio  

    还可以用  ls /dev/snd 看是否有相关节点,如有,则声卡驱动大致ok。下面接着介绍测试的先关方法

    6  移植alsa-lib

     从官网(http://www.alsa-project.org/main/index.php/Download)下载 alsa-lib-1.0.29.tar.bz2包,
     6.1解压执行:
    [html] view plain copy
     
     print?
    1. $ cd alsa-lib-1.0.29  
    2. $./configure --host=arm-none-linux-gnueabi --prefix=/home/***/alsa/alsa-lib  
    6.2 编译:
    [html] view plain copy
     
     print?
    1. $ make  

    6.3 安装(需要root权限)
    [html] view plain copy
     
     print?
    1. sudo make install  

    7 移植alsa-utils
    从官网(http://www.alsa-project.org/main/index.php/Download)下载 alsa-utils-1.0.29.tar.bz2包,
    7.1解压执行:
    [html] view plain copy
     
     print?
    1. ./configure --host=arm-none-linux-gnueabi --prefix=/home/**/alsa/alsa-utils --with-alsa-inc-prefix=/home/**/alsa/alsa-lib/include --with-alsa-prefix=/home/**/alsa/alsa-lib/lib --disable-alsamixer  



    注意上面最后的参数:--disable-alsamixer 若不加此参数编译会报错:configure error required courses helper header not found 具体原因不清楚!!

    7.2 编译
    [html] view plain copy
     
     print?
    1. make  

    7.3安装(需要root权限)
    [html] view plain copy
     
     print?
    1. sudo make install  

    8 开发板配置:
    8.1 库的拷贝:
    [html] view plain copy
     
     print?
    1. sudo cp alsa-lib/lib/libasound.* /home/**/rootfs/lib/  

    8.2  alsa-utils拷贝
    将alsa-utils/bin目录小的内容拷贝到目标板根文件系统中的bin下
    [html] view plain copy
     
     print?
    1. sudo cp alsa-utils/bin/* /home/**/rootfs/bin  

    8.3 alsa的配置文件拷贝
     除了库之外alsa的配置文件也需要拷贝到目标板根文件系统中,这里需要注意的是share目录在目标板的存放位置必须和在主机的存放路径一致!!
    [html] view plain copy
     
     print?
    1. sudo cp -R **/alsa/alsa-lib/share/ /home/**/rootfs/**/alsa/alsa-lib/  
    重新挂载文件系统到目标板,通过 aplay  -l可以查看我们的音频设备。
    [html] view plain copy
     
     print?
    1. root@imx6solo ~$ aplay -L  
    2. null  
    3.     Discard all samples (playback) or generate zero samples (capture)  
    4. root@imx6solo ~$ aplay -l  
    5. **** List of PLAYBACK Hardware Devices ****  
    6. card 0: wm8960audio [wm8960-audio], device 0: HiFi wm8960-hifi-0 []  
    7.   Subdevices: 1/1  
    8.   Subdevice #0: subdevice #0  

    播放声音文件:
    [html] view plain copy
     
     print?
    1. aplay **.wav  

    最开始一直没有声音,后来发现是wm8960没有初始化的原因,所以要对其进行初始化:

    初始化步骤:

    第1步 设置power1 2 3;
    第2步 设置时钟;
    第3步 设置ADC-DAC,注意设置非静音;
    第4步 设置audio interface;
    第5步 设置volume;
    第6步 设置mixer;

    可参考如下代码(init at imx-wm8960.c:imx_hifi_hw_params function):
    [html] view plain copy
     
     print?
    1. void wm8960_init(struct snd_soc_dai *codec_dai)  
    2. {  
    3. struct snd_soc_codec *codec = codec_dai->codec;  
    4.   
    5. snd_soc_write(codec, 0x19, 0xc0); /* power1, ok*/  
    6. snd_soc_write(codec, 0x1a, 0x199); /* power2, ok*/  
    7.   
    8. snd_soc_write(codec, 0x31, 0xf7); /* classd1 : enable L&R, ok */  
    9. snd_soc_write(codec, 0x33, 0x11b); /* classd3 : volume max, ok */  
    10.   
    11. snd_soc_write(codec, 0x28, 0x179); /* ok */  
    12. snd_soc_write(codec, 0x29, 0x179); /* ok */  
    13.   
    14. snd_soc_write(codec, 0x22, 0x100); /* dac to mixer, ok */  
    15. snd_soc_write(codec, 0x25, 0x100); /* dac to mixer, ok */  
    16.   
    17. snd_soc_write(codec, 0x2f, 0x0c); /* left & right output mixer enable, ok */  
    18. snd_soc_write(codec, 0x05, 0x00); /* ok */  
    19. }  
  • 相关阅读:
    Linux命令之查看cpu个数_核数_内存总数
    Python文件操作大全,随机删除文件夹内的任意文件
    Python文件操作:同一个文件进行内容替换
    异步请求Python库 grequests的应用和与requests库的响应速度的比较
    查询MySQL某字段相同值得重复数据
    /var/redis/run/redis_6379.pid exists, process is already running or crashed的解决办法
    人工智能----TensorFlow开篇简介
    Centos6.5+Python2.7 +ffmpeg+opencv2自动安装脚本
    决策统计---指标六要素
    大数据应用分类
  • 原文地址:https://www.cnblogs.com/subo_peng/p/5195249.html
Copyright © 2011-2022 走看看