I.mx6s上移植wm8960驱动

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

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

  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\n", __FUNCTION__);

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

  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是接的哪个控制器。

  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
以下是修改的地方

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

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

  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,添加如下:

  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:

  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:

  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解压执行:
  1. $ cd alsa-lib-1.0.29
  2. $./configure --host=arm-none-linux-gnueabi --prefix=/home/***/alsa/alsa-lib

6.2 编译:

  1. $ make

6.3 安装(需要root权限)

  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解压执行:
  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 编译

  1. make

7.3安装(需要root权限)

  1. sudo make install
8 开发板配置:
8.1 库的拷贝:
  1. sudo cp alsa-lib/lib/libasound.* /home/**/rootfs/lib/
8.2  alsa-utils拷贝
将alsa-utils/bin目录小的内容拷贝到目标板根文件系统中的bin下
  1. sudo cp alsa-utils/bin/* /home/**/rootfs/bin
8.3 alsa的配置文件拷贝
 除了库之外alsa的配置文件也需要拷贝到目标板根文件系统中,这里需要注意的是share目录在目标板的存放位置必须和在主机的存放路径一致!!
  1. sudo cp -R **/alsa/alsa-lib/share/ /home/**/rootfs/**/alsa/alsa-lib/

重新挂载文件系统到目标板,通过 aplay  -l可以查看我们的音频设备。

  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

播放声音文件:

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

  1. void wm8960_init(struct snd_soc_dai *codec_dai)
  2. {
  3. struct snd_soc_codec *codec = codec_dai->codec;
  4. snd_soc_write(codec, 0x19, 0xc0); /* power1, ok*/
  5. snd_soc_write(codec, 0x1a, 0x199); /* power2, ok*/
  6. snd_soc_write(codec, 0x31, 0xf7); /* classd1 : enable L&R, ok */
  7. snd_soc_write(codec, 0x33, 0x11b); /* classd3 : volume max, ok */
  8. snd_soc_write(codec, 0x28, 0x179); /* ok */
  9. snd_soc_write(codec, 0x29, 0x179); /* ok */
  10. snd_soc_write(codec, 0x22, 0x100); /* dac to mixer, ok */
  11. snd_soc_write(codec, 0x25, 0x100); /* dac to mixer, ok */
  12. snd_soc_write(codec, 0x2f, 0x0c); /* left & right output mixer enable, ok */
  13. snd_soc_write(codec, 0x05, 0x00); /* ok */
  14. }

I.mx6s上移植wm8960驱动(基于linux3.0.101版本)的更多相关文章

  1. 移植触摸屏驱动到linux3.4.2

    1. 修改drivers/input/touchscreen/下的Makefile #obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(C ...

  2. 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  3. 第一章 Android系统移植与驱动开发概述

    本书第一章首先简单概要地介绍了关于Android系统移植和驱动开发的相关内容. 所谓“移植”是指为特定的自己的设备,如手机定制Android的过程.自己开发一些程序(移植)装载在设备上,使得Andro ...

  4. backports移植rtlwifi驱动

    /************************************************************************ * backports移植rtlwifi驱动 * 说 ...

  5. iOS_SN_基于AFNetworking3.0网络封装

    转发文章,原地址:http://www.henishuo.com/base-on-afnetworking3-0-wrapper/?utm_source=tuicool&utm_medium= ...

  6. 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  7. Android深度探索HAL和驱动开发(卷1) 第一章 Android系统移植和驱动开发

    由于Android是基于Linux内核的,因此,Android和其他Linux系统的核心部分差异非常小.然而不同版本的Android使用的Linux内核的版本有细微的差异,所以不同Android驱动可 ...

  8. 第一章 Andorid系统移植与驱动开发概述 - 读书笔记

    Android驱动月考1 第一章 Andorid系统移植与驱动开发概述 - 读书笔记 1.Android系统的架构: (1)Linux内核,Android是基于Linux内核的操作系统,并且开源,所以 ...

  9. 1Android系统移植与驱动开发概述

    1.Android系统架构分为四层,从下至上依次为Linux内核层,C/C++代码库.Android SDK API.应用程序,要熟悉每一层的内容以及功能: 2.Android移植分为应用移植和系统移 ...

随机推荐

  1. ORACLE函数之日期时间转换函数

     1.          TO_CHAR 语法:TO_CHAR(X [,format]) 说明:将X按format格式转换成字符串.X是一个日期或者数字.format是一个规定了X採用何种格式转换 ...

  2. kdump 的使用在linux崩溃时

    Centos7/RHEL7 开启kdump 翻译 2017年12月18日 16:58:28 标签: kernel / kdump / crash / centos 437 原文链接<How to ...

  3. Vsphere笔记06 Vcenter 部署流程 1

    Vcenter 部署流程 1   一.环境需求   1.需要两台装着WIN2K8 R2 64X的服务器   2.启用一台要添加活动目录角色,并且配置DC,DC的参数如下: 域名:justech-dc. ...

  4. Scrapy爬虫入门系列3 将抓取到的数据存入数据库与验证数据有效性

    抓取到的item 会被发送到Item Pipeline进行处理 Item Pipeline常用于 cleansing HTML data validating scraped data (checki ...

  5. Spring MVC 分离了控制器、模型对象、过滤器以及处理程序对象的角色

    通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术.Velocity.Tiles.iText和POI.Spring MVC 框架 ...

  6. 如何获取继承中泛型T的类型

    @SuppressWarnings("unchecked") public void testT() { clazz = (Class<T>)( (Parameteri ...

  7. 《从零开始学Swift》学习笔记(Day 16)——字典集合

    原创文章,欢迎转载.转载请注明:关东升的博客        Swift字典表示一种非常复杂的集合,允许按照某个键来访问元素.字典是由两部分集合构成的,一个是键(key)集合,一个是值(value)集合 ...

  8. java内部类详细介绍

    0.内部类与一般类有所不同,它是放在外部类的内部即可作为外部类的成员变量,也可放在方法内部作为局部变量,既然是变量,那么它可以用 private static 修饰符修饰,而外部类则不能,这也是内部类 ...

  9. Xamarin.Forms学习之初

    微软的Build 2016结束的有段时间了,对于一个简单的小屌丝程序员--我来说,关注最大的无疑是Xamarin的免费(开源什么的让大神们上吧),内心激动啊.大会结束的周末我就迫不及待的安装了,然后. ...

  10. _ 下划线 Underscores __init__

    Underscores in Python https://shahriar.svbtle.com/underscores-in-python Underscores in Python This p ...