Android - Audio - Qcom平台 - QM215耳机常见修改和粗略识别流程
- 背景
- 耳机的分类
- 调试Qcom耳机功能时常用修改
- (1)qcom,msm-mbhc-hphl-swh = <1>;
- (2)qcom,msm-hs-micbias-type=”internal”;
- (3)耳机的micbias(常用micbias2)是否有外部电容
- (4)耳机是否支持欧美标转换
- (5)更改micbias电压
- (6)修改识别耳机时候的阻抗
- (7)Lineout设备
- (8)如果没有兼容欧标美标开关,但是想播放音乐(不能通话),可以做如下修改
- (9)对耳机按键阻值等调控
- 软件逻辑
- 在哪儿识别
- 在哪儿上报
- 按键识别
- 综述
背景
耳机部分也是在工作范围内,所以有必要整理,方便回顾和查找。
耳机的分类
3.5mm耳机接口分为三段式和四段式, 三段式耳机即”左右地”,四段式则带麦分为”左右地麦”(美标)和”左右麦地”(欧标)。
type c和usb耳机则另算。我这边还没有研究,暂时就不写了。
调试Qcom耳机功能时常用修改
这一部分既是为了方便回顾和查询,也可以列举debug点。
先说dtsi的位置,常见配置都在dtsi里:
kernel/msm-4.9/arch/arm64/boot/dts/qcom/qm215-audio.dtsi
/*begin mod by fuhua for task: 8668750 on 2019-12-03 task id :8668750 */qcom,msm-hac-pa = <&tlmm 127 0>;qcom,msm-hac-pa-gpio = <&cdc_hac_pa_gpio>; /*end mod by fuhua for task: 8668750 on 2019-12-03 task id :8668750 */qcom,msm-mclk-freq = <9600000>;qcom,msm-mbhc-hphl-swh = <1>; /*Begin Modified by fuhua.wang for defect_id: 8751408 on 2019 02.25 */qcom,msm-mbhc-gnd-swh = <0>; /*End Modified by fuhua.wang for defect_id: 8751408 on 2019 02.25 */ /*begin mod by fuhua for 4-plog headset on 2019-08-30 task id :8293309 */qcom,msm-hs-micbias-type = "internal"; /*end mod by fuhua for 4-plog headset on 2019-08-30 task id :8293309 */ |
(1)qcom,msm-mbhc-hphl-swh=<1>;
//0是NC,1是NO
NO是指耳机的accdet脚默认上拉到1.8v,插入耳机后,accdet脚跟左声道短接到一块,不插入耳机的时候左声道和det就是断开的,电平拉低。而NC是指耳机的accdet脚默认和左声道短接到一块,为低电平,插入耳机后,accdet脚与左声道断开,accdet脚变为高电平。
seoul项目就是不接的时候断开的,也可以设置为0做实验,发现开机就有耳机图标。
(2)qcom,msm-hs-micbias-type=”internal”;
这个是设置Handset/Headset micbias有没有外接电容。
seoul原理图画的是个电阻,但是却没贴。
如果micbias电压是内部接过去的:
qcom,msm-hs-micbias-type = “internal”;
“MIC BIAS Internal2”, “Headset Mic”,
“AMIC2”, “MIC BIAS Internal2”,
如果micbias电压是外部接过去的:
qcom,msm-hs-micbias-type = “external”;
“MIC BIAS External2”, “Headset Mic”,
“AMIC2”, “MIC BIAS External2”,
但是也有针对Handset进行设置的。
如果Handset用的是外部micbias,使用如下配置:
“MIC BIAS External”,”Handset Mic”,
“AMIC1”,”MIC BIAS External”,
如果Handset用的是内部Micbias,使用如下配置:
“MIC BIAS Internal”,”Handset Mic”,
“AMIC1”,”MIC BIAS Internal”,
上述应该是说的手持模式和耳机模式,针对这一块,seoul设置是对的。
106 qcom,audio-routing = 107 "RX_BIAS", "MCLK", 108 "SPK_RX_BIAS", "MCLK", 109 "INT_LDO_H", "MCLK", 110 "RX_I2S_CLK", "MCLK", 111 "TX_I2S_CLK", "MCLK", 112 "MIC BIAS External", "Handset Mic", 113 /*begin mod by fuhua for 4-plog headset on 2019-08-30 task id :8293309 */ 114 "MIC BIAS Internal2", "Headset Mic", 115 /*end mod by fuhua for 4-plog headset on 2019-08-30 task id :8293309 */ 116 "MIC BIAS External", "Secondary Mic", 117 "AMIC1", "MIC BIAS External", 118 /*begin mod by fuhua for 4-plog headset on 2019-08-30 task id :8293309 */ 119 "AMIC2", "MIC BIAS Internal2", 120 /*end mod by fuhua for 4-plog headset on 2019-08-30 task id :8293309 */ 121 "AMIC3", "MIC BIAS External", 122 "ADC1_IN", "ADC1_OUT", 123 "ADC2_IN", "ADC2_OUT", 124 "ADC3_IN", "ADC3_OUT", 125 "PDM_IN_RX1", "PDM_OUT_RX1", 126 "PDM_IN_RX2", "PDM_OUT_RX2", 127 "PDM_IN_RX3", "PDM_OUT_RX3"; |
(3)耳机的micbias(常用micbias2)是否有外部电容
如果有,需添加,而seoul是没有的
qcom,msm-micbias2-ext-cap
针对micbias1也可以检查是否连有外部电容,seoul是有的。
qcom,msm-micbias1-ext-cap;
(4)耳机是否支持欧美标转换
欧标耳机绝缘环是白色的,美标一般为黑色。
如果要支持转换,一般硬件要额外添加开关。
另外要注意如下pinctrl的GPIO口。
cross-conn-det { qcom,pins = <&gp 97>; qcom,num-grp-pins = <1>; qcom,pin-func = <0>; label = "cross-conn-det-sw";cross_conn_det_act: lines_on {drive-strength = <8>;output-low;bias-pull-down;};cross_conn_det_sus: lines_off {drive-strength = <2>;bias-disable;}; }; |
如果不支持,最好删除对pinctrl的引用。
pinctrl-names = "cdc_lines_act", "cdc_lines_sus", //"cross_conn_det_act", //"cross_conn_det_sus", "vdd_spkdrv_act", "vdd_spkdrv_sus"; pinctrl-0 = <&cdc_pdm_lines_act &vdd_spkdrv_act>; pinctrl-1 = <&cdc_pdm_lines_sus &vdd_spkdrv_sus>; // pinctrl-2 = <&cross_conn_det_act>; // pinctrl-3 = <&cross_conn_det_sus>; // qcom,cdc-us-euro-gpios = <&msm_gpio 97 0>; |
(5)更改micbias电压
如苹果耳机,它的mic的工作电压是大于1.8v,所以为了能正常使用苹果耳机,需要增加micbias电压。
qcom,cdc-micbias-cfilt-mv = <2700>;
seoul项目上没有这个属性,但是代码中有去读的代码。
或者更改代码: kernel/sound/soc/codecs/msm8x16-wcd.c #define MICBIAS_DEFAULT_VAL 2700000
seoul项目上路径是: vendor/qcom/opensource/audio-kernel/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
(6)修改识别耳机时候的阻抗
kernel/sound/soc/codecs/wcd-mbhc-v2.c #define HS_VREF_MIN_VAL 1400
1.4v,最大只能识别7700欧阻抗的耳机, 这个阻抗指的是mic对地的阻抗,耳机的后两节之间的阻抗
1.5v,最大能识别11k
1.6v,最大能识别17.6k
1.7v,最大能识别37.4k
seoul项目是在vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-v2.h
这个文件里面。
(7)Lineout设备
Qcom平台会上报SND_JACK_LINEOUR设备,但是Android层是不支持LINEOUT设备的,不会对事件做出任何响应,如果非要支持,那么就需要做如下修改:
kernel/sound/soc/msm/msm8x16.c .linein_th = 5000,改为 .linein_th = 0,
seoul项目对应如下修改位置:
/vendor/qcom/opensource/audio-kernel/asoc/msm8952.c .linein_th = 5000,
(8)如果没有兼容欧标美标开关,但是想播放音乐(不能通话),可以做如下修改
595 static void wcd_correct_swch_plug(struct work_struct *work) 596 {......745 if ((pt_gnd_mic_swap_cnt == mbhc->swap_thr) && 746 (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) { 747 /* 748 * if switch is toggled, check again, 749 * otherwise report unsupported plug 750 */ +++ plug_type = MBHC_PLUG_TYPE_HEADPHONE; 751 if (mbhc->mbhc_cfg->swap_gnd_mic && 752 mbhc->mbhc_cfg->swap_gnd_mic(codec, 753 true)) { 754 pr_debug("%s: US_EU gpio present,flip switch\n" 755 , __func__); 756 continue; 757 } 758 } |
(9)对耳机按键阻值等调控
耳机上报的键值定义(和(7)linein_th定义在一个文件中的):
88 .key_code[0] = KEY_MEDIA, 89 .key_code[1] = KEY_VOICECOMMAND, 90 .key_code[2] = KEY_VOLUMEUP, 91 .key_code[3] = KEY_VOLUMEDOWN, 92 .key_code[4] = 0, 93 .key_code[5] = 0, 94 .key_code[6] = 0, 95 .key_code[7] = 0, |
#define WCD_MBHC_DEF_BUTTONS 8
seoul项目耳机按键的数量定义在vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-v2.h
这个文件里面。
耳机按键的阈值定义在:static void *def_msm8x16_wcd_mbhc_cal(void)
seoul项目则是定义在vendor/qcom/opensource/audio-kernel/asoc/msm8952.c
目录,static void *def_msm8952_wcd_mbhc_cal(void)
函数当中。
1588 /* 1589 * In SW we are maintaining two sets of threshold register 1590 * one for current source and another for Micbias. 1591 * all btn_low corresponds to threshold for current source 1592 * all bt_high corresponds to threshold for Micbias 1593 * Below thresholds are based on following resistances 1594 * 0-70 == Button 0 1595 * 110-180 == Button 1 1596 * 210-290 == Button 2 1597 * 360-680 == Button 3 1598 */ 1599 btn_low[0] = 75; 1600 btn_high[0] = 75; 1601 /*Begin Modified by fuhua.wang for defect_id: 8697471 on 2019 12.19 */ 1602 btn_low[1] = 120; 1603 btn_high[1] = 120; 1604 /*End Modified by fuhua.wang for defect_id: 8697471 on 2019 12.19 */ 1605 btn_low[2] = 225; 1606 btn_high[2] = 225; 1607 btn_low[3] = 450; 1608 btn_high[3] = 450; 1609 btn_low[4] = 500; 1610 btn_high[4] = 500; 1611 1612 return msm8952_wcd_cal; |
如果想调试按键的阈值:
分别配置MBHC为CS(Current Source)和MB(MIC BIAS)模式:
CS mode : 0x144 = 0x00, 0x151 = 0xB0
MB mode : 0x144 = 0x80, 0x151 = 0x80
adb root
cd sys/kernel/debug/soc//msm8x16_wcd_codec/
echo “” > codec_reg
类如: echo “0x121 0xA0” > codec_reg
按下耳机按键,分别测量两个模式下的耳机mic上的电压值,把测量的值分别填入高通提供的表格,或者按照80-NK808-15的Table3-3和Table3-4计算出最后的阀值。
以上信息可以参考其他的blog,但是我认为写得有点啰嗦。
软件逻辑
识别,按键,上报等关键细节
接下来都以Seoul项目为模板
目录位置:vendor/qcom/opensource/audio-kernel/asoc/codecs
耳机操作主要是带MBHC(Multibutton headset control)字样的文件。
在哪儿识别
vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-v2.c
wcd_mbhc_mech_plug_detect_irq
这个函数作为入口,其中的wcd_mbhc_swch_irq_handler
作为实现。
根据mbhc->current_plug
和detection_type
判断耳机当前状态。
以插入耳机为例,正常流程则会进入到调用mbhc->mbhc_fn->wcd_mbhc_detect_plug_type(mbhc);
函数,到wcd-mbhc-adc.c
的wcd_mbhc_adc_detect_plug_type
函数中。
/* called under codec_resource_lock acquisition */ static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc) {struct snd_soc_codec *codec = mbhc->codec;pr_debug("%s: enter\n", __func__);WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);if (mbhc->mbhc_cb->hph_pull_down_ctrl)mbhc->mbhc_cb->hph_pull_down_ctrl(codec, false);WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);if (mbhc->mbhc_cb->mbhc_micbias_control) {mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,MICB_ENABLE);} else {pr_err("%s: Mic Bias is not enabled\n", __func__);return;}/* Re-initialize button press completion object */reinit_completion(&mbhc->btn_press_compl);wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);pr_debug("%s: leave\n", __func__); } |
正常情况下就能走到wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
开始执行wcd_correct_swch_plug
。这个函数就是识别设备的主要逻辑了,详细可以看源码。
在哪儿上报
上述的wcd_correct_swch_plug
函数就是上报之前的临门一脚。
其中可以看到有多次检测是否欧美标转换,
static void wcd_correct_swch_plug(struct work_struct *work) {......do {cross_conn = wcd_check_cross_conn(mbhc);try++;} while (try < mbhc->swap_thr);if (cross_conn > 0) {plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;pr_debug("%s: cross connection found, Plug type %d\n",__func__, plug_type);goto correct_plug_type;}//如果设置了交叉检测,即欧美标转换,那么则进入继续确认的步骤,否则直接通过`wcd_mbhc_find_plug_and_report`上报耳机type了。 ....../** Report plug type if it is either headset or headphone* else start the 3 sec loop*/if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&(!wcd_swch_level_remove(mbhc))) {WCD_MBHC_RSC_LOCK(mbhc);wcd_mbhc_find_plug_and_report(mbhc, plug_type);//直接通过`wcd_mbhc_find_plug_and_report`上报耳机typeWCD_MBHC_RSC_UNLOCK(mbhc);}......//进入继续确认的步 correct_plug_type:timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);while (!time_after(jiffies, timeout)) { |
继续确认主要是针对欧美标转换设置的,为了兼容更多的耳机,即使硬件没有转换开关,多半还是选择识别成三段式耳机,不过耳机状态基本都给到了wcd_mbhc_find_plug_and_report
函数接口,通过它给wcd_mbhc_report_plug
函数做逻辑判断,然后上报,上报类型为SND_JACK_UNSUPPORTED
等。
//wcd-mbhc-v2.c void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,enum snd_jack_types jack_type) {......else{jack_type = SND_JACK_LINEOUT;mbhc->force_linein = true;mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;if (mbhc->hph_status) {mbhc->hph_status &= ~(SND_JACK_HEADSET |SND_JACK_LINEOUT |SND_JACK_UNSUPPORTED);wcd_mbhc_jack_report(mbhc,&mbhc->headset_jack,mbhc->hph_status,WCD_MBHC_JACK_MASK);} |
按键识别
中断的注册是在init函数中的wcd_mbhc_btn_press_handler
。
int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,const struct wcd_mbhc_cb *mbhc_cb,const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,struct wcd_mbhc_register *wcd_mbhc_regs,bool impedance_det_en) {......ret = mbhc->mbhc_cb->request_irq(codec,mbhc->intr_ids->mbhc_btn_press_intr,wcd_mbhc_btn_press_handler,"Button Press detect", mbhc); |
进入static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
函数之前,中断已经触发了,其中的
mbhc->is_btn_press = true; msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);....../* If switch interrupt already kicked in, ignore button press */ if (mbhc->in_swch_irq_handler) {pr_debug("%s: Swtich level changed, ignore button press\n",__func__);goto done; } mask = wcd_mbhc_get_button_mask(mbhc); if (mask == SND_JACK_BTN_0)mbhc->btn_press_intr = true;//Begin-modify-by-fuhua.wang-for-task 8384912 on 20190926//if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) {if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET && !mbhc->is_selfie_stick_insert) { //End-add-by-fuhua.wang-for-task 8384912 on 20190926pr_err("%s: Plug isn't headset, ignore button press\n",__func__);goto done; } |
作为开始处理按键的标志。
mask = wcd_mbhc_get_button_mask(mbhc);
则是哪个按键的标志。深究可以发现是调用msm-analog-cdc.c
中的msm_anlg_cdc_mbhc_map_btn_code_to_num
函数,其中的snd_soc_read
则是读取codec的寄存器了,这个接口是kernel/msm-4.9/sound/soc/soc-io.c
中定义。
当放开按键的时候,则会调用wcd_mbhc_release_handler
上报jack。
static irqreturn_t wcd_mbhc_release_handler(int irq, void *data) {......wcd_mbhc_jack_report(mbhc, &mbhc->button_jack,0, mbhc->buttons_pressed);} else {if (mbhc->in_swch_irq_handler) {pr_debug("%s: Switch irq kicked in, ignore\n",__func__);} else {pr_debug("%s: Reporting btn press\n",__func__);wcd_mbhc_jack_report(mbhc,&mbhc->button_jack,mbhc->buttons_pressed,mbhc->buttons_pressed);pr_debug("%s: Reporting btn release\n",__func__);wcd_mbhc_jack_report(mbhc,&mbhc->button_jack,0, mbhc->buttons_pressed); |
短按都在这里了,长按则会进入wcd_btn_lpress_fn:
static void wcd_btn_lpress_fn(struct work_struct *work) {struct delayed_work *dwork;struct wcd_mbhc *mbhc;s16 btn_result = 0;pr_debug("%s: Enter\n", __func__);dwork = to_delayed_work(work);mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result);if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {pr_debug("%s: Reporting long button press event, btn_result: %d\n",__func__, btn_result);wcd_mbhc_jack_report(mbhc, &mbhc->button_jack,mbhc->buttons_pressed, mbhc->buttons_pressed);}pr_debug("%s: leave\n", __func__);mbhc->mbhc_cb->lock_sleep(mbhc, false); } |
综述
如果只是为了应付项目里常见修改,文章开头列举的足矣。
但有可能会遇到更难的情况,或者更棘手的需求,或者需要创新,这个时候就需要深入了解软件接口和框架了,而且具体问题具体分析,本文仅仅针对了重要的接口,详细问题,比如增加自拍杆等重新定义一个特征按键等,需要另起分析,否则篇幅过长,不利于把握。
Android - Audio - Qcom平台 - QM215耳机常见修改和粗略识别流程相关推荐
- Android - Audio - Qcom平台 - hac器件bring up
背景 正文 助听器构造 使用方式 HAC部分硬件原理图 硬件调试需求 软件平台及框架 a:mixer_path.xml中添加hac path b:alsa用户空间,tinyalsa中注册HAC控件 c ...
- Qcom平台 Camera 之常见错误和问题
本文主要记载了一些在调试过程中遇到的错误和问题,及相关的设置.log.解决方法等.如有错误,请交流指正. 目录 调试 帧冻结错误 调试 相机 App 闪退错误 调试 cam banding 现象 调试 ...
- 那些年踩过的坑-之《Android Q-高通平台UAC(USB Audio Class)调试记录》
uac分为UAC1.0和UAC2.0,由于UAC2.0,在windows上兼容性不好,在产品中,会带来各种坑,所以选择UAC1.0 平台:高通 SDA660,android Q,kernel4.4 一 ...
- Android Audio - 支持多应用同时录音_Android8.1修改方法
支持多应用同时录音_Android8.1修改方法 修改方法 与之相关 修改方法 源码路径: sdk\frameworks\av\services\audiopolicy\managerdefault\ ...
- Android Audio和耳机,蓝牙耳机等音频外设
文章目录 Android Audio和耳机,蓝牙耳机等音频外设 蓝牙连接处理 广播接收 AudioManager接口 Listener监听 蓝牙耳机和AudioService的交互 蓝牙的状态 A2D ...
- android camera2 qcom,Qcom平台 Camera的一些知识点 之MCLK
前言 MCLK 是平台 baseband 提供给 cam sensor的正常工作的频率, Qcom 平台一般未24MHz,由其他时钟源分频而来,实测在23.8MHz左右. 在打开相机的时候,才可以测到 ...
- Android 8.1 中Systemui中的常见修改(六)NavigationBar加载流程
本文主要分为两个部分 一.NavigationBar的加载流程 二.Android P上如何去除NavigationBar 一 NavigationBar的加载流程 NavigationBar就是我们 ...
- Android audio音频流数据异常问题分析
一.背景 在 Android 系统的开发过程当中,音频异常问题通常有如下几类,无声,调节不了声音,爆音,声音卡顿,声音效果异常(忽大忽小,低音缺失等)等.尤其声音效果这部分问题通常从日志上信息量较少, ...
- Android 4.0 平台特性
Android 4.0 平台特性 API等级:14 Android4.0 是一次重要的平台发布版,为用户和应用程序开发者增加了大量的新特性.在下面我们将讨论的所有新特性和API中,因为它将 Andr ...
最新文章
- Swift 中使用 SQLite——批量更新(事务处理)
- Arbitrage--POJ 2240
- oracle 优化逻辑读过高,详述逻辑读与arraysize的关系
- SQL Sever 基本命令案例
- c语言中的所有关键字,C语言中的32个关键字
- 基于顺序存储结构的图书信息表的图书去重(C++)
- 滴滴否认柳青计划卸任:目前正积极全面配合网络安全审查
- mysql 数据库的安装与配置 有关msi文件start service 停滞不前的问题及其解决办法
- ctf是用Windows还是Linux,CTF中zip总结
- c语言第三章重点知识点总结,c语言重点知识点总结
- RGB,CMYK,HSB,LAB颜色空间定义
- 控制器分析-绘制伯德图
- MVX-Net论文解读
- TI 927 928 947 948 940串行器解串器系列
- JT/T808消息体转义
- 【干货】长达4万字的Java知识点!
- C#WinForm二维码编码解码器
- java--两个巨大素数(质数)的乘积
- eNSP构建企业私有网络
- 一本图书的信息包括:图书编号(BookNo),书名(BookName),总册数(Total),借出数(Lend),价格(Value),利用结构体实现以下要求: