I.mx6s上移植wm8960驱动(基于linux3.0.101版本)
I.mx6s上移植wm8960驱动
1 上电操作
配置wm8960的上电脚,文件位置:arch/arm/mach-mx6/board-mx6q_sabresd.c
- #define SABRESD_CODEC_PWR_EN IMX_GPIO_NR(7, 12)
- 440 /* Enable wm8960 power supply */
- 441 gpio_request(SABRESD_CODEC_PWR_EN, "audio-power");
- 442 gpio_direction_output(SABRESD_CODEC_PWR_EN, 1);
- 443 msleep(1);
- 444 gpio_set_value(SABRESD_CODEC_PWR_EN, 1);
- 445 printk("Power up wm8960 successful %s\n", __FUNCTION__);
另外,根据原理图可知上电脚为GPIO17,所以相关配置头文件里需将其配置为gpio口,文件位置:arch/arm/mach-mx6/board-mx6dl_sabresd.h
- 236 /* CODEC_PWR_EN */
- 237 MX6DL_PAD_GPIO_17__GPIO_7_12,
2:配置I2C,用于client的生成,文件位置:arch/arm/mach-mx6/board-mx6q_sabresd.c 需确认你的i2c是接的哪个控制器。
- 805 static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
- 806 {
- 807 I2C_BOARD_INFO("wm8960", 0x1a),
- 808 },
- };
3: 修改wm8960 codec相关的数据结构,此处根据wm8962修改而来,文件位置:arch/arm/mach-mx6/board-mx6q_sabresd.c
以下是修改的地方
- 57 #include <sound/wm8962.h>
- 58 #include <sound/wm8960.h>
- ...省略部分内容...
- 410 static struct platform_device mx6_sabresd_audio_wm8960_device = {
- 411 .name = "imx-wm8960",
- 412 };
- 413
- 414 static struct mxc_audio_platform_data wm8960_data;
- 415
- 416 static int wm8960_clk_enable(int enable)
- 417 {
- 418 if (enable) {
- 419 clk_enable(clko);
- 420 printk("%s:wm clk enable\n", __FUNCTION__);
- 421 }
- 422 else {
- 423 clk_disable(clko);
- 424 printk("%s:wm clk disable\n", __FUNCTION__);
- 425 }
- 426 return 0;
- 427 }
- 428
- 429 static int mxc_wm8960_init(void)
- 430 {
- 431 int rate;
- 432
- 433 clko = clk_get(NULL, "clko_clk");
- 434 if (IS_ERR(clko)) {
- 435 pr_err("can't get CLKO clock.\n");
- 436 return PTR_ERR(clko);
- 437 }
- 438 /* both audio codec and comera use CLKO clk*/
- 439 rate = clk_round_rate(clko, 24000000);
- 440 clk_set_rate(clko, rate);
- 441
- 442 wm8960_data.sysclk = rate;
- 443
- 444 /* Enable wm8960 power supply */
- 445 gpio_request(SABRESD_CODEC_PWR_EN, "audio-power");
- 446 gpio_direction_output(SABRESD_CODEC_PWR_EN, 1);
- 447 msleep(1);
- 448 gpio_set_value(SABRESD_CODEC_PWR_EN, 1);
- 449 printk("%s:Power up wm8960 successful\n", __FUNCTION__);
- 450
- 451 return 0;
- 452 }
- 453
- 454 /* Note: we use struct wm8962_pdata for wm8960_config_data */
- 455 /* struct wm8962_pdata defind at linux/wm8962.h */
- 456 static struct wm8962_pdata wm8960_config_data = {
- 457 .gpio_init = {
- 458 [2] = WM8960_GPIO_FN_DMICCLK,
- 459 [4] = 0x8000 | WM8960_GPIO_FN_DMICDAT,
- 460 },
- 461 .clock_enable = wm8960_clk_enable,
- 462 };
- 463
- 464 static struct mxc_audio_platform_data wm8960_data = {
- 465 .ssi_num = 1,
- 466 .src_port = 2,
- 467 .ext_port = 3,
- 468 .hp_gpio = -1, //SABRESD_HEADPHONE_DET,
- 469 // .hp_active_low = 1,
- 470 .mic_gpio = -1, //SABRESD_MICROPHONE_DET,
- 471 // .mic_active_low = 1,
- 472 .init = mxc_wm8960_init,
- 473 .clock_enable = wm8960_clk_enable,
- 474 };
- 475
- 476 static struct regulator_consumer_supply sabresd_vwm8960_consumers[] = {
- 477 REGULATOR_SUPPLY("SPKVDD1", "0-001a"),
- 478 REGULATOR_SUPPLY("SPKVDD2", "0-001a"),
- 479 };
- 480
- 481 static struct regulator_init_data sabresd_vwm8960_init = {
- 482 .constraints = {
- 483 .name = "SPKVDD",
- 484 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- 485 .boot_on = 1,
- 486 },
- 487 .num_consumer_supplies = ARRAY_SIZE(sabresd_vwm8960_consumers),
- 488 .consumer_supplies = sabresd_vwm8960_consumers,
- 489 };
- 490
- 491 static struct fixed_voltage_config sabresd_vwm8960_reg_config = {
- 492 .supply_name = "SPKVDD",
- 493 .microvolts = 4200000,
- 494 .gpio = SABRESD_CODEC_PWR_EN,
- 495 .enable_high = 1,
- 496 .enabled_at_boot = 1,
- 497 .init_data = &sabresd_vwm8960_init,
- 498 };
- 499
- 500 static struct platform_device sabresd_vwm8960_reg_devices = {
- 501 .name = "reg-fixed-voltage",
- 502 .id = 4,
- 503 .dev = {
- 504 .platform_data = &sabresd_vwm8960_reg_config,
- 505 },
- 506 };
- ...省略部分内容...
- 811 static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
- 812 {
- 813 I2C_BOARD_INFO("wm8960", 0x1a),
- 814 },
- 815 {
- 816 I2C_BOARD_INFO("ov564x", 0x3c),
- 817 .platform_data = (void *)&camera_data,
- 818 },
- 819 {
- 820 I2C_BOARD_INFO("mma8451", 0x1c),
- 821 .platform_data = (void *)&mma8451_position,
- 822 },
- 823 };
- 824
- ...省略部分内容...
- 1535 static int __init imx6q_init_audio(void)
- 1536 {
- 1537 if (board_is_mx6_reva()) {
- 1538 mxc_register_device(&mx6_sabresd_audio_wm8958_device,
- 1539 &wm8958_data);
- 1540 imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata);
- 1541
- 1542 mxc_wm8958_init();
- 1543 } else {
- 1544 platform_device_register(&sabresd_vwm8960_reg_devices);
- 1545 mxc_register_device(&mx6_sabresd_audio_wm8960_device,
- 1546 &wm8960_data);
- 1547 imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata);
- 1548
- 1549 mxc_wm8960_init();
- 1550 printk("%s\n", __FUNCTION__);
- 1551 }
- 1552
- 1553 return 0;
- 1554 }
- ...省略部分内容...
- 1859 if (board_is_mx6_reva()) {
- 1860 strcpy(mxc_i2c0_board_info[0].type, "wm8958");
- 1861 mxc_i2c0_board_info[0].platform_data = &wm8958_config_data;
- 1862 } else {
- 1863 strcpy(mxc_i2c0_board_info[0].type, "wm8960");
- 1864 mxc_i2c0_board_info[0].platform_data = &wm8960_config_data;
- 1865 }
4 修改wm8960.h:include/sound/wm8960.h
- 9 #ifndef _WM8960_PDATA_H
- 10 #define _WM8960_PDATA_H
- 11
- 12 #define WM8960_DRES_400R 0
- 13 #define WM8960_DRES_200R 1
- 14 #define WM8960_DRES_600R 2
- 15 #define WM8960_DRES_150R 3
- 16 #define WM8960_MAX_GPIO 6
- 17
- 18 #define WM8960_GPIO_FN_DMICCLK 19
- 19 #define WM8960_GPIO_FN_DMICDAT 20
- 20
- 21
- 22 struct wm8960_data {
- 23 bool capless; /* Headphone outputs configured in capless mode */
- 24
- 25 int dres; /* Discharge resistance for headphone outputs */
- 26
- 27 int gpio_base;
- 28 u32 gpio_init[WM8960_MAX_GPIO];
- 29
- 30 u32 mic_cfg;
- 31 bool irq_active_low;
- 32 bool spk_mono;
- 33 };
- 34
- 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,添加如下:
- 80 config SND_SOC_IMX_WM8960
- 81 tristate "SoC Audio support for IMX boards with WM8960"
- 82 select SND_MXC_SOC_MX2
- 83 select SND_SOC_WM8960
- 84 help
- 85 Say Y if you want to add support for SoC audio on an i.MX board with
- 86 a WM8960 codec.
修改同目录下Makefile:
- 18 snd-soc-imx-wm8960-objs := imx-wm8960.o
- 30 obj-$(CONFIG_SND_SOC_IMX_WM8960) += snd-soc-imx-wm8960.o
用make menuconfig配置上wm8960,编译下载至开发板即可进行验证。
Ps :一些调试命令及输出log:
- root@imx6solo ~$ cat /proc/asound/cards
- 0 [wm8960audio ]: wm8960-audio - wm8960-audio
- wm8960-audio
还可以用 ls /dev/snd 看是否有相关节点,如有,则声卡驱动大致ok。下面接着介绍测试的先关方法
6 移植alsa-lib
- $ cd alsa-lib-1.0.29
- $./configure --host=arm-none-linux-gnueabi --prefix=/home/***/alsa/alsa-lib
6.2 编译:
- $ make
6.3 安装(需要root权限)
- sudo make install
7 移植alsa-utils
- ./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
若不加此参数编译会报错:configure
error required courses helper header not found 具体原因不清楚!!
7.2 编译
- make
7.3安装(需要root权限)
- sudo make install
- sudo cp alsa-lib/lib/libasound.* /home/**/rootfs/lib/
- sudo cp alsa-utils/bin/* /home/**/rootfs/bin
- sudo cp -R **/alsa/alsa-lib/share/ /home/**/rootfs/**/alsa/alsa-lib/
重新挂载文件系统到目标板,通过 aplay -l可以查看我们的音频设备。
- root@imx6solo ~$ aplay -L
- null
- Discard all samples (playback) or generate zero samples (capture)
- root@imx6solo ~$ aplay -l
- **** List of PLAYBACK Hardware Devices ****
- card 0: wm8960audio [wm8960-audio], device 0: HiFi wm8960-hifi-0 []
- Subdevices: 1/1
- Subdevice #0: subdevice #0
播放声音文件:
- aplay **.wav
最开始一直没有声音,后来发现是wm8960没有初始化的原因,所以要对其进行初始化:
第2步 设置时钟;
第3步 设置ADC-DAC,注意设置非静音;
第4步 设置audio interface;
第5步 设置volume;
第6步 设置mixer;
可参考如下代码(init at imx-wm8960.c:imx_hifi_hw_params function):
- void wm8960_init(struct snd_soc_dai *codec_dai)
- {
- struct snd_soc_codec *codec = codec_dai->codec;
- snd_soc_write(codec, 0x19, 0xc0); /* power1, ok*/
- snd_soc_write(codec, 0x1a, 0x199); /* power2, ok*/
- snd_soc_write(codec, 0x31, 0xf7); /* classd1 : enable L&R, ok */
- snd_soc_write(codec, 0x33, 0x11b); /* classd3 : volume max, ok */
- snd_soc_write(codec, 0x28, 0x179); /* ok */
- snd_soc_write(codec, 0x29, 0x179); /* ok */
- snd_soc_write(codec, 0x22, 0x100); /* dac to mixer, ok */
- snd_soc_write(codec, 0x25, 0x100); /* dac to mixer, ok */
- snd_soc_write(codec, 0x2f, 0x0c); /* left & right output mixer enable, ok */
- snd_soc_write(codec, 0x05, 0x00); /* ok */
- }
I.mx6s上移植wm8960驱动(基于linux3.0.101版本)的更多相关文章
- 移植触摸屏驱动到linux3.4.2
1. 修改drivers/input/touchscreen/下的Makefile #obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(C ...
- 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- 第一章 Android系统移植与驱动开发概述
本书第一章首先简单概要地介绍了关于Android系统移植和驱动开发的相关内容. 所谓“移植”是指为特定的自己的设备,如手机定制Android的过程.自己开发一些程序(移植)装载在设备上,使得Andro ...
- backports移植rtlwifi驱动
/************************************************************************ * backports移植rtlwifi驱动 * 说 ...
- iOS_SN_基于AFNetworking3.0网络封装
转发文章,原地址:http://www.henishuo.com/base-on-afnetworking3-0-wrapper/?utm_source=tuicool&utm_medium= ...
- 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- Android深度探索HAL和驱动开发(卷1) 第一章 Android系统移植和驱动开发
由于Android是基于Linux内核的,因此,Android和其他Linux系统的核心部分差异非常小.然而不同版本的Android使用的Linux内核的版本有细微的差异,所以不同Android驱动可 ...
- 第一章 Andorid系统移植与驱动开发概述 - 读书笔记
Android驱动月考1 第一章 Andorid系统移植与驱动开发概述 - 读书笔记 1.Android系统的架构: (1)Linux内核,Android是基于Linux内核的操作系统,并且开源,所以 ...
- 1Android系统移植与驱动开发概述
1.Android系统架构分为四层,从下至上依次为Linux内核层,C/C++代码库.Android SDK API.应用程序,要熟悉每一层的内容以及功能: 2.Android移植分为应用移植和系统移 ...
随机推荐
- X264参考手册
艺搜简介 基本语法: x264 [options]-o outfile infile 注意与ffmpeg的输入输出文件位置恰好相反: ffmpeg[options][[infile options]- ...
- OC 字符串出来
//1.获取字符串的长度 NSString * str = @"abcd"; NSUInteger length = [str length]; //str.length; NSL ...
- Fibonacci series(斐波纳契数列)的几种常见实现方式
费波那契数列的定义: 费波那契数列(意大利语:Successione di Fibonacci),又译费波拿契数.斐波那契数列.斐波那契数列.黄金切割数列. 在数学上,费波那契数列是以递归的方法来定义 ...
- ChemDraw破解版真的不大好用
一直以来都有很多的用户朋友在网上找ChemDraw破解版使用,但是现在厂商清理的厉害,还有国家对知识产权的保护越来越严格,破解版ChemDraw越来越难找了.大家与其花那么多的时候找破解版的,不如买个 ...
- PRINTDLG 打印对话框操作
typedef struct tagPD { DWORD lStructSize; HWND hwndOwner; HGLOBAL hDevMode; HGLOBAL hDevNames; HDC h ...
- PHP中通过数组遍历找出最小值
举例: $a = array(1,2,4,0,9,8,6);//定义一个数组 $len = count($a);//获取数组的长度 $min = $a[0];//默认情况下数组的第一个值是最小的 fo ...
- JSON查看小工具
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写.同时也易于机器解析和生成.它基于JavaScript Programming Langu ...
- Uvalive6885(最短路)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=129723 题目大意:n个点,m条边,求出从0到n的最短距离,输出途 ...
- bfs_迷宫求最短路径
宽度优先搜索按照距离开始状态由近及远的顺序进行搜索,可以很容易用来求解最短路径或者最少操作等问题. 将已经访问过的状态用标记管理起来,便可以很好地做到由近及远的搜索. import java.util ...
- 如何生成动态库 .dll 的符号 .lib 文件?
在知道拥有动态库和头文件的情况下,但没有动态库符号文件的情况下,如何静态链接动态库? 1.使用 Microsoft Visual Studio Tools 命令行命令生成 xxx.def 文件,进而使 ...