目录
- 前言
- 一、ES7210 简介
- 二、ES7210 Driver Porting
- 1. Broadcom 平台 集成 ES7210
- 2. Broadcom 平台定制化参数
- 3. 排查 ES7210 无法正常工作
- 4. ES7210 Gain Channels Adjust
- 总结
前言
项目开发过程中,由于Broadcom平台音频数字接口比较少,所以采用模拟麦克风作为输入端,经顺芯ES7210 ADC 转换送至Broadcom PCM 数字音频接口。
提示:本文记录了调试ES7210 Driver 过程中的问题与收获。
一、ES7210 简介
ES7210 是一款高性能四通道音频ADC,支持I2S / PCM / TDM 模式,可支持多个ES7210级连模式。常用于智能音箱领域。
二、ES7210 Driver Porting
1. Broadcom 平台 集成 ES7210
ES7210 Driver 需要顺芯原厂提供,虽然Linux 先的音频框架是一样的,但是芯片内部会有一系列寄存器需要设置。
- 将ES7210.c和ES7210.h复制到src/kernel/linux/v4.4/sound/soc/codecs/路径下
- 修改src/kernel/linux/v4.4/sound/soc/codecs/Makefile,
#obj-$(CONFIG_SND_SOC_ES7243) += es7243.o
obj-$(CONFIG_SND_SOC_ES7210) += es7210.o
默认驱动ees7210.c中采用过的是I2C_detect方式注册,
如有需要用dts方式注册,请将ES7210_MATCH_DTS_EN赋值为1.
#define ES7210_MATCH_DTS_EN 1
//ES7210 match method select: 0: i2c_detect, 1:of_device_id
2. Broadcom 平台定制化参数
/* to set internal mclk and adclrclk ratio */#define RATIO_768 0xC3
#define RATIO_256 0xC1
#define RATIO_128 0x01
#define RATIO_64 0x41 /* mclk from bclk pin */#define ES7210_MCLK_LRCK_RATIO RATIO_128
Broadcom 平台 LRCK 默认是16KHz , 通过逻辑仪看到LRCK的频率为2.04MHz。故ES7210_MCLK_LRCK_RATIO 需要设置为RATIO_128
3. 排查 ES7210 无法正常工作
通过逻辑分析仪观察到波形,PCM In 一直没有数据,相当于ES7210 没有正常工作。
根据 调试笔记 — 使用ADC芯片ES7243遇到的问题 的分析,快速验证了I2C , 可以正常工作。
参考数字音频接口
找到ES7210 Datasheet ,TDM参考设计。MCLK 需要连接
而Broadcom 中的ES7210 中的MCLK 是悬空的, 这个时候找顺芯FAE 咨询了下,MCLK 不能悬空,一般是LRCLK的256倍。如果没有MCLK,需要将BCLK短接到MCLK。
通过飞线将MCLK与BCLK连接在一起, 通过逻辑分析仪抓取波形,发现PCM Data 一直都是某个bit持续为高电平,其它为低电平。感觉ES7210 还是没有工作起来。跟顺芯FAE沟通了解. 驱动中不需要更改。
想起来之前,驱动代码中一旦使能 clk_prepare_enable(es7210->mclk),kernel 会立即发生崩溃。顺芯FAE 解释说 本身提供的是的RK 平台的驱动代码,针对博通平台,需要去掉该操作,只要主控能送出BCLK 就可以,其他不会有影响,代码只是使能MCLK
ssoc-audio soc-audio: ASoC: machine MapleTree should use snd_soc_register_card()
########### debug 1es7210_probe!
Unable to handle kernel paging request at virtual address fffffffe
pgd = c0014000
[fffffffe] *pgd=1fffd821, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.1.52 #8
Hardware name: Generic DT based system
task: df422c00 ti: df43a000 task.ti: df43a000
PC is at clk_prepare+0x14/0x2c
LR is at clk_prepare_lock+0x10/0xf8
pc : [<c02721b8>] lr : [<c02710f8>] psr: 60000113
sp : df43bdb0 ip : 00000000 fp : 00000000
r10: df4c4e20 r9 : df4c4c58 r8 : fffffffe
r7 : df4c4c00 r6 : df4c3d90 r5 : c07b6ca0 r4 : fffffffe
r3 : df422c00 r2 : 00000001 r1 : 00000000 r0 : 00000001
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c5387d Table: 0001404a DAC: 00000015
Process swapper/0 (pid: 1, stack limit = 0xdf43a210)
Stack: (0xdf43bdb0 to 0xdf43c000)
bda0: df4c4c10 c02bb894 df4c4c10 df4c4c28
.....
[<c02721b8>] (clk_prepare) from [<c02bb894>] (es7210_probe+0x58/0x110)
[<c02bb894>] (es7210_probe) from [<c028d3bc>] (soc_probe_component+0x1f0/0x320)
[<c028d3bc>] (soc_probe_component) from [<c028ff7c>] (snd_soc_register_card+0x8b0/0xfc0)
[<c028ff7c>] (snd_soc_register_card) from [<c02186fc>] (platform_drv_probe+0x2c/0x60)
[<c02186fc>] (platform_drv_probe) from [<c02172a0>] (really_probe+0x190/0x290)
[<c02172a0>] (really_probe) from [<c0215a0c>] (bus_for_each_drv+0x60/0x94)
[<c0215a0c>] (bus_for_each_drv) from [<c0217108>] (device_attach+0x84/0x8c)
[<c0217108>] (device_attach) from [<c02167f8>] (bus_probe_device+0x84/0xa8)
[<c02167f8>] (bus_probe_device) from [<c0214b30>] (device_add+0x358/0x544)
[<c0214b30>] (device_add) from [<c02184c8>] (platform_device_add+0x110/0x220)
[<c02184c8>] (platform_device_add) from [<c05c3a6c>] (bcm63xx_audio_init+0x38/0x60)
[<c05c3a6c>] (bcm63xx_audio_init) from [<c001973c>] (do_one_initcall+0x8c/0x1d4)
[<c001973c>] (do_one_initcall) from [<c05a9dcc>] (kernel_init_freeable+0x148/0x1e8)
[<c05a9dcc>] (kernel_init_freeable) from [<c0446484>] (kernel_init+0x8/0xe8)
[<c0446484>] (kernel_init) from [<c001f4e8>] (ret_from_fork+0x14/0x2c)
Code: 012fff1e e92d4010 e1a04000 ebfffbcb (e5940000)
---[ end trace 0daed059f560601b ]---
Kernel panic - not syncing: Fatal exception
CPU3: stopping
CPU: 3 PID: 0 Comm: swapper/3 Tainted: G D 4.1.52 #8
Hardware name: Generic DT based system
[<c0026be0>] (unwind_backtrace) from [<c00229c8>] (show_stack+0x10/0x14)
[<c00229c8>] (show_stack) from [<c044a57c>] (dump_stack+0x8c/0xa0)
[<c044a57c>] (dump_stack) from [<c00253a4>] (handle_IPI+0x148/0x158)
[<c00253a4>] (handle_IPI) from [<c001941c>] (gic_handle_irq+0x5c/0x60)
[<c001941c>] (gic_handle_irq) from [<c00234c0>] (__irq_svc+0x40/0x74)
Exception stack(0xdf45ff88 to 0xdf45ffd0)
ff80: 00000001 00000000 00000000 c002bd00 df45e000 c05dc4b0
ffa0: c0450704 00000000 df45ffd8 c05d7200 00000000 00000001 01000000 df45ffd0
ffc0: c00205f0 c00205f4 60000113 ffffffff
[<c00234c0>] (__irq_svc) from [<c00205f4>] (arch_cpu_idle+0x38/0x3c)
[<c00205f4>] (arch_cpu_idle) from [<c005ce60>] (cpu_startup_entry+0x15c/0x264)
[<c005ce60>] (cpu_startup_entry) from [<000194ac>] (0x194ac)
CPU0: stopping
CPU: 0 PID: 0 Comm: swapper/0 Tainted: G D 4.1.52 #8
Hardware name: Generic DT based system
[<c0026be0>] (unwind_backtrace) from [<c00229c8>] (show_stack+0x10/0x14)
[<c00229c8>] (show_stack) from [<c044a57c>] (dump_stack+0x8c/0xa0)
[<c044a57c>] (dump_stack) from [<c00253a4>] (handle_IPI+0x148/0x158)
[<c00253a4>] (handle_IPI) from [<c001941c>] (gic_handle_irq+0x5c/0x60)
[<c001941c>] (gic_handle_irq) from [<c00234c0>] (__irq_svc+0x40/0x74)
Exception stack(0xc05dbf28 to 0xc05dbf70)
bf20: c05dbf70 00000018 312acb4c 00000000 dfbc9910 00000001
bf40: 3124e81c 00000000 312acb4c 00000000 c0602f54 c05d9200 14000000 c05dbf70
bf60: fffffff8 c0267dac 00000113 ffffffff
[<c00234c0>] (__irq_svc) from [<c0267dac>] (cpuidle_enter_state+0xd8/0x20c)
[<c0267dac>] (cpuidle_enter_state) from [<c005cf08>] (cpu_startup_entry+0x204/0x264)
[<c005cf08>] (cpu_startup_entry) from [<c05a9c78>] (start_kernel+0x3a8/0x3b4)
[<c05a9c78>] (start_kernel) from [<0001807c>] (0x1807c)
CPU2: stopping
CPU: 2 PID: 371 Comm: ubi_bgt0d Tainted: G D 4.1.52 #8
Hardware name: Generic DT based system
[<c0026be0>] (unwind_backtrace) from [<c00229c8>] (show_stack+0x10/0x14)
[<c00229c8>] (show_stack) from [<c044a57c>] (dump_stack+0x8c/0xa0)
[<c044a57c>] (dump_stack) from [<c00253a4>] (handle_IPI+0x148/0x158)
[<c00253a4>] (handle_IPI) from [<c001941c>] (gic_handle_irq+0x5c/0x60)
[<c001941c>] (gic_handle_irq) from [<c00234c0>] (__irq_svc+0x40/0x74)
Exception stack(0xd965fe20 to 0xd965fe68)
fe20: c07aeafc 80000193 00000001 20000113 dfbc3f08 00000005 00000035 c07906b8
fe40: 00000000 00000006 00000000 00000100 00000002 d965fe68 c0061710 c0062310
fe60: 60000113 ffffffff
[<c00234c0>] (__irq_svc) from [<c0062310>] (console_unlock+0x33c/0x4f8)
[<c0062310>] (console_unlock) from [<c0062814>] (vprintk_emit+0x348/0x5a0)
[<c0062814>] (vprintk_emit) from [<c0062b8c>] (vprintk_default+0x20/0x28)
[<c0062b8c>] (vprintk_default) from [<c0448810>] (printk+0x6c/0x7c)
[<c0448810>] (printk) from [<c02495c4>] (ubi_thread+0x40/0x174)
[<c02495c4>] (ubi_thread) from [<c0046da8>] (kthread+0xdc/0xf4)
[<c0046da8>] (kthread) from [<c001f4e8>] (ret_from_fork+0x14/0x2c)
Rebooting in 5 seconds..
然后查看原理图,发现有MIC_EN引脚,连接的是ES7210中断引脚,咨询TP硬件之后,发现这个脚目前是悬空状态,因此排除中断引脚的问题。
发现该排查的问题已经排查完成,先和FAE沟通,看还有哪些忽略的点,FAE说打开调试信息,查看Reg的值,沟通之后,了解方法之后,查看代码。通过应用层操作可以看出全部寄存器的数值。
1721 static struct attribute_group es7210_debug_attr_group = {
1722 .name = "es7210_debug",
1723 .attrs = es7210_debug_attrs,
1724 };
static DEVICE_ATTR(es7210, 0644, es7210_show, es7210_store);06 static ssize_t es7210_show(struct device *dev, struct device_attribute *attr, char *buf)
1707 {
1708 printk("echo flag|reg|val > es7210\n");
1709 printk("eg read star address=0x06,count 0x10:echo 0610 >es7210\n");
1710 printk("eg write star address=0x90,value=0x3c,count=4:echo 4903c >es7210\n");
1711 return 0;
1712 }
/由于echo flag打印的寄存器不全,需要用 echo 0x47可以打印出全部寄存器
echo 0x4f > /sys/devices/platform/ubus@ff800000/ff802100.i2c/i2c-0/0-0040/es7210_debug/es7210Read: start REG:0x00,count:0x4f
REG[0x00]: 0x41; REG[0x01]: 0x20; REG[0x02]: 0xc3; REG[0x03]: 0x04;
REG[0x04]: 0x01; REG[0x05]: 0x00; REG[0x06]: 0x00; REG[0x07]: 0x20;
REG[0x08]: 0x20; REG[0x09]: 0x30; REG[0x0a]: 0x30; REG[0x0b]: 0x02;
REG[0x0c]: 0x00; REG[0x0d]: 0x09; REG[0x0e]: 0xff; REG[0x0f]: 0xff;
REG[0x10]: 0x00; REG[0x11]: 0x63; REG[0x12]: 0x07; REG[0x13]: 0x00;
REG[0x14]: 0x03; REG[0x15]: 0x03; REG[0x16]: 0x00; REG[0x17]: 0x00;
REG[0x18]: 0xf7; REG[0x19]: 0xf7; REG[0x1a]: 0x00; REG[0x1b]: 0xbf;
REG[0x1c]: 0xbf; REG[0x1d]: 0xbf; REG[0x1e]: 0xbf; REG[0x1f]: 0xff;
REG[0x20]: 0x0a; REG[0x21]: 0x2a; REG[0x22]: 0x0a; REG[0x23]: 0x2a;
REG[0x24]: 0x11; REG[0x25]: 0xff; REG[0x26]: 0xff; REG[0x27]: 0x0a;
REG[0x28]: 0xff; REG[0x29]: 0xff; REG[0x2a]: 0xff; REG[0x2b]: 0x2a;
REG[0x2c]: 0xff; REG[0x2d]: 0xff; REG[0x2e]: 0xff; REG[0x2f]: 0x2a;
REG[0x30]: 0xff; REG[0x31]: 0xff; REG[0x32]: 0xff; REG[0x33]: 0x2a;
REG[0x34]: 0xff; REG[0x35]: 0xff; REG[0x36]: 0xff; REG[0x37]: 0x2a;
REG[0x38]: 0xff; REG[0x39]: 0xff; REG[0x3a]: 0xff; REG[0x3b]: 0xff;
REG[0x3c]: 0xff; REG[0x3d]: 0x72; REG[0x3e]: 0x10; REG[0x3f]: 0x01;
REG[0x40]: 0x42; REG[0x41]: 0x70; REG[0x42]: 0x70; REG[0x43]: 0x1c;
REG[0x44]: 0x1c; REG[0x45]: 0x1c; REG[0x46]: 0x1c; REG[0x47]: 0x08;
REG[0x48]: 0x08; REG[0x49]: 0x08; REG[0x4a]: 0x08; REG[0x4b]: 0x00;
REG[0x4c]: 0x00; REG[0x4d]: 0xff; REG[0x4e]: 0xff;
根据寄存器的值判断ES7210的工作状态,这个时候想到确实应该这样操作,FAE确实从其中发现了问题:
通过寄存器0x14和0x15发现处于Mute状态。
同时0x02寄存器值不对,没匹配到没有mclk的值。这才真正的问题所在,这个时候思考为什么会导致这样的情况发生?
FAE推测到 说明没执行到es7210_pcm_startup()或者录音没有跑这个7210的声卡。这个时候最终明白问题所在了。
目前ES7210只走初始化流程,并不走es7210_pcm_startup() 这个时候明白了问题所在。
当初最初设计的方案 :
● ES7210 只需要走初始化流程,不需要完全对接Alsa的应用层,因为ES7210 SOC 是被动的,最终是Broadcom SOC PCM 接口去ES7210 获取数据的。
● Broadcom SOC 不需要通过Alsa 应用层,可以先通过bhDsphal.c应用程序调试看PCM是否又音频数据。
而ES7210中是对接的Alsa Lib接口,当通过arecord 录音的时候,Alsa Driver 是需要调用
es7210_pcm_startup(),而该函数的功能是启动延迟队列,执行 umute 操作。
通过这样的分析,解释了为什么ES7210 没数据的问题,主要是驱动初始化执行了mute操作,当arecoed的时候执行umut操作。而BCM6755 PCM 并没有走Alsa流程,导致一直处于mute状态。
831 static struct snd_soc_dai_ops es7210_ops = {832 .startup = es7210_pcm_startup,833 .hw_params = es7210_pcm_hw_params,834 .set_fmt = es7210_set_dai_fmt,835 .set_sysclk = es7210_set_dai_sysclk,836 .digital_mute = es7210_mute,837 };static int es7210_pcm_startup(struct snd_pcm_substream *substream,struct snd_soc_dai *dai)
{struct snd_soc_codec *codec = dai->codec;struct es7210_priv *es7210 = snd_soc_codec_get_drvdata(codec);if (es7210_init_reg == 0) {schedule_delayed_work(&es7210->pcm_pop_work, msecs_to_jiffies(100));}return 0;
}
// 延迟队列执行函数747 static void pcm_pop_work_events(struct work_struct *work)748 {749 printk("enter into %s\n", __func__);750 es7210_unmute();751 es7210_init_reg = 1;752 }
4. ES7210 Gain Channels Adjust
// 由于echo flag打印的寄存器不全,需要用 echo 0x47可以打印出全部寄存器
echo 0x4f > /sys/devices/platform/ubus@ff800000/ff802100.i2c/i2c-0/
0-0040/es7210_debug/es7210
//寄存器列表如下图
//需要调整ES7210 通道的GAIN数值#define ES7210_MIC1_GAIN_REG43 0x43
#define ES7210_MIC2_GAIN_REG44 0x44
#define ES7210_MIC3_GAIN_REG45 0x45
#define ES7210_MIC4_GAIN_REG46 0x46#define ES7210_MIC_GAIN 0x1c // need check hw design and channel
#define ES7210_AEC_GAIN 0x13 // need check hw design and channeles7210_write(ES7210_MIC1_GAIN_REG43, ES7210_MIC_GAIN, i2c_clt1[i]);
es7210_write(ES7210_MIC2_GAIN_REG44, ES7210_MIC_GAIN, i2c_clt1[i]);
es7210_write(ES7210_MIC3_GAIN_REG45, ES7210_MIC_GAIN, i2c_clt1[i]);
es7210_write(ES7210_MIC4_GAIN_REG46, ES7210_MIC_GAIN, i2c_clt1[i]);// 根据寄存器可以分析出,增益值现在为34.5dB, 根据算法的要求,麦克风的录音数据应该是不需要添加任何增益的,需要改为0
i2cset -f -y 0 0x40 0x43 0x10
i2cset -f -y 0 0x40 0x44 0x10
i2cset -f -y 0 0x40 0x45 0x10
i2cset -f -y 0 0x40 0x46 0x10
总结
调试ES7210 Driver 前后花费了一周的时间,过程中遇到的很多问题,所以每次交付的时间都Delay。主要这个Broadcom平台对接的是TDM接口以及走的ALSA 接口有区别,很多东西不是很熟悉,解决问题过程中需要去弄明白才能快速的解决问题。