#更新 2020.05.10

我觉得我这个标题取的不是很妥当,为了表达对技术的敬畏之心,我将原标题
《一文搞懂内部MIC_BIAS》修改为《高通平台内部MIC_BIAS简介》

#更新2020.05.10

#更新 2021.10.28
这篇文章说的麦克偏置都是老平台的东西了,新平台比如一些5G平台是没有啥内部偏置的,高通给的硬件参考设计也没有。即无论是硅麦还是驻极体麦克,都是用的外部偏置。
#更新2021.10.28

1. 问题背景

代码路径:

 kernel/msm-3.18/sound/soc/codecs/msm8x16-wcd.c

今天一个学长,问我这个这个修改几个意思,我为啥要改这个;我随口就说,两个都是关闭主、副麦克内部供电,因为是MEMS麦克(硅麦),如果是驻极体麦克的话,就要打开这个两个偏置,分别写

(codec,micb_int_reg,0x80,0x80);
(codec,micb_int_reg,0x02,0x02);

然后学长问是MIC_BIAS,我说应该是吧…(有点没底气…),我给他截了两个寄存器介绍:



( 第7位表明 主麦克的内部供电的开关,第1位表明副麦克的内部供电开关)

然后学长问我有没有硬件原理图;我掏出来两张珍藏许久的原理图。。。。



第一张是驻极体麦克(ECM),第二张是模拟硅麦(MEMS);然后学长问…你在逗我吗,驻极体麦克的
供电我都找不到,什么关闭内部偏置。。。

2. 先解释硬件

首先高通芯片 PMU内部有 MIC_BIAS,PMU外部也有 MIC_BIAS,取决于你是怎么上拉的;
MIC1_P(主麦)和MIC3_P(副麦)内部上拉到MICBIAS1,MIC2_P(耳机麦)内部上拉到MICBIAS2;



(灵魂画手。。希望大佬们不要介意…)

对于ECM麦克来说,它需要打开内部MIC_BIAS,而对于MEMS麦克来说,它需要关闭内部MIAS,使用外部的MIC_BIAS.


具体到代码上就是设备树里面这样配置,表明都是使用的PMU内部的 MIC_BIAS,而若你要使用PMU外部的
MIC_BIAS,应该这样写:

 "MIC BIAS External1", "Handset Mic","MIC BIAS External2", "Headset Mic","MIC BIAS External3", "Secondary Mic",

update on 2020.03.12
/**********************************************************************/
经大佬提醒,我这个地方写的有点片面;就是如果设备树里面是配置的是内部mic bias的话,以上
的修改都OK,但是如果配置的外部mic bias,也是可以通过寄存器来 开关mic bias的,就在原修改的
下面一点点:

代码路径:kernel/msm-3.18/sound/soc/codecs/msm8x16-wcd.c
char *external2_text = "External2";
char *external_text = "External";

if (!strnstr(w->name, external_text, strlen(w->name)))snd_soc_update_bits(codec,MSM8X16_WCD_A_ANALOG_MICB_1_EN, 0x05, 0x04);
if (w->reg == MSM8X16_WCD_A_ANALOG_MICB_1_EN)msm8x16_wcd_configure_cap(codec, true, micbias2);

/**********************************************************************/

OK,其实我们已经知道了,我之前回答学长的问题是不准确的;正确答案应该是: 基于当前的电路设计,驻极体(ECM)使用的是PMU内部的 MIC_BIAS,所以我们要把那两个bit打开(置1),而对于模拟硅麦(MEMS),由于是使用的PMU外部的MIC_BIAS,所以我们要把PMU内部的MIC_BIAS关闭,这样才能让MEMS麦克正常工作。

3. 再解释软件

作为社会主义的接班人,尤其是接受了九年义务教育的人,咱不能满足于此,还需要继续分析…

micbias2 = (snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN) & 0x80);switch (event) {case SND_SOC_DAPM_PRE_PMU:if (strnstr(w->name, internal1_text, strlen(w->name))) {if (get_codec_version(msm8x16_wcd) >= CAJON)snd_soc_update_bits(codec,MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL_2,0x02, 0x02);snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);} else if (strnstr(w->name, internal2_text, strlen(w->name))) {snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);snd_soc_update_bits(codec, w->reg, 0x60, 0x00);} else if (strnstr(w->name, internal3_text, strlen(w->name))) {snd_soc_update_bits(codec, micb_int_reg, 0x02, 0x00);

灵魂拷问: snd_soc_update_bits函数是怎么把寄存器写进去的???

./kernel/msm-3.18/include/sound/soc.hint snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,unsigned int mask, unsigned int value);

这里定义了函数的原型,但是没有初始化;

./kernel/msm-3.18/sound/soc/soc-io.cint snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,unsigned int mask, unsigned int value)
{return snd_soc_component_update_bits(&codec->component, reg, mask,value);
}

我们继续追踪代码,看下snd_soc_component_update_bits函数;

int snd_soc_component_update_bits(struct snd_soc_component *component,unsigned int reg, unsigned int mask, unsigned int val)
{bool change;int ret;if (component->regmap)ret = regmap_update_bits_check(component->regmap, reg, mask,val, &change);elseret = snd_soc_component_update_bits_legacy(component, reg,mask, val, &change);if (ret < 0)return ret;return change;
}

component->regmap这个是一个虚拟的内存映射,表明如果这里进行了虚拟内存映射的话,
代码就走if后面的,否则就走else下面的,
这个是玩Linux kernel那帮大佬调试用的,具体我没用过;

其实两者都是一个意思啊,如果用SI追代码的话,从regmap_update_bits_check函数进去,到_regmap_update_bits函数;

static int _regmap_update_bits(struct regmap *map, unsigned int reg,unsigned int mask, unsigned int val,bool *change)
{int ret;unsigned int tmp, orig;ret = _regmap_read(map, reg, &orig);if (ret != 0)return ret;tmp = orig & ~mask;tmp |= val & mask;if (tmp != orig) {ret = _regmap_write(map, reg, tmp);if (change)*change = true;} else {if (change)*change = false;}return ret;
}

或者直接追snd_soc_component_update_bits_legacy函数,

static int snd_soc_component_update_bits_legacy(struct snd_soc_component *component, unsigned int reg,unsigned int mask, unsigned int val, bool *change)
{unsigned int old, new;int ret;if (!component->read || !component->write)return -EIO;mutex_lock(&component->io_mutex);ret = component->read(component, reg, &old);if (ret < 0)goto out_unlock;new = (old & ~mask) | (val & mask);*change = old != new;if (*change)ret = component->write(component, reg, new);
out_unlock:mutex_unlock(&component->io_mutex);return ret;
}

解释下核心代码:

new = (old & ~mask) | (val & mask);

(old & ~mask) //原来寄存器mask标志位上的值清0,
(val & mask) // val是你要写入的值,这个是把mask位的值修改成val的值

回到我们最开始:

(codec,micb_int_reg,0x02,0x02); // 第一个0x02指的就是第一位,即mask位; 第二个0x02,是
指的是把这个值修改为1,这个0x02就是val的值。

mutex_lock(&component->io_mutex);

特别提一下这里有个mutex互斥锁,说明这个该函数很重要,不能被中断打断;

其实早期的kernel里面有注解;

 * snd_soc_component_update_bits() - Perform read/modify/write cycle* @component: Component to update* @reg: Register to update* @mask: Mask that specifies which bits to update* @val: New value for the bits specified by mask** Return: 1 if the operation was successful and the value of the register* changed, 0 if the operation was successful, but the value did not change.* Returns a negative error code otherwise.int snd_soc_component_update_bits(struct snd_soc_component *component,unsigned int reg, unsigned int mask, unsigned int val)
....

很清晰,已经指出了mask以及val的意思;

4. 作者注

/******
@article{Linux Audio Driver,
Author = { 1byte ≠ 8bit},
Year = { 2020},
}
******/

希望对大家有帮助.

OVER.

[Linux Audio Driver] 高通平台内部MIC_BIAS简介相关推荐

  1. [Linux Device Driver] 高通平台分区学习

    1. 分区名字 && 作用 ssd ---ssd diag模块的分区,存储加密的RSA密钥. persist ---其中包含在设备出厂后不应该更改的数据,例如:芯片的校准数据(WIFI ...

  2. [Linux Audio Driver] 高通平台MI2S总线配置

    0. 背景 hardware platform:骁龙865 android version:android10 Linux kernel version:msm-4.19 思维导图如下: 1. 遇到的 ...

  3. [Linux Audio Driver] 高通TDM总线配置

    0. 背景 TDM接口与平台SOC相关,调试前需要确定平台支持TDM,目前一些中高端的平台都支持的.(转载请备注链接) 本文介绍配置: SEN_TDM_TX_0. 1. tinymix查看当前虚拟总线 ...

  4. 高通平台环境搭建,编译,系统引导流程分析 .

    1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流 ...

  5. 高通平台启动log概述(PBL log、sbl1 log、kernel log)

    高通平台启动log概述(PBL log.sbl1 log.kernel log) 在嵌入式linux的调试过程中log有着至关重要的地位,等同于医生的CT报告.能够熟悉启动各个阶段的log,如PBL阶 ...

  6. 高通平台调试Nxp Smart PA-TFA9897

    前言 新项目对speaker的输出响度和声音质量有一定的要求,所有选择了Nxp smart PA-TFA9897,其实高通平台有WSA系列的smart PA,由于后期tuning的复杂性,选择了Nxp ...

  7. UEFI在高通平台实现

    UEFI(Unified extensible firmware interface)统一的可扩展固件接口,是一种详细描述类型接口的标准. 可扩展固件接口(Extensible Firmware In ...

  8. android 高通平台有前途吗,华为鸿蒙计划要适配高通平台了,可以告别安卓搭载鸿蒙OS了?...

    鸿蒙走出这一步是可以想象到的,看来华为打造这个系统希望的结果是万物皆可盘呀,所以一开始就提出了开源,也就意味着这次是高通,下次就可以是联发科,甚至更多的手机品牌也完全就可以搭载!早期我们一直在说国产手 ...

  9. Android高通平台调试Camera驱动全纪录

    项目比较紧,3周内把一个带有外置ISP,MIPI数据通信,800万像素的camera从无驱动到实现客户全部需求. 1日 搭平台,建环境,编译内核,烧写代码. 我是一直在Window下搭个虚拟机登服务器 ...

最新文章

  1. 评测指标(metrics)
  2. JavaScript设计模式(二)之单例模式
  3. php mysql长连接聊天室_PHP之探索MySQL 长连接、连接池
  4. Node.js 替换文档内容
  5. 遗传算法锦标赛选择java实现_java – 遗传算法锦标赛选择
  6. 从源码编译安装TensorFlow
  7. 443端口与80端口
  8. 尺度不变特征变换(SIFT)匹配算法详解
  9. 全景图怎么拍?相机参数该怎样设置呢?
  10. 【报告分享】抖店百宝书-抖音电商(附下载)
  11. C# 串口助手中英文显示问题
  12. C语言中,求三个数中最大数
  13. 如何将spine的素材导入unity
  14. linux ksh 用户名,学习Linux中ksh的用法
  15. NLM(Non-Local means)算法原理
  16. 10只小白鼠1000支药水找出毒药问题
  17. python的CUDA加速编程科普
  18. 什么是docker –rm选项
  19. [春秋云镜]CVE-2021-44983
  20. 文献阅读 2018 Deep Retinex Decomposition for low-light Enhancement

热门文章

  1. 你的业务被AI所取替的风险度有多高?AI社交、克隆人、角色扮演、代理人
  2. dedesql自定义字段_dede织梦 添加及调用自定义字段方法
  3. 半梦半醒之间-林清玄
  4. Postgresql 开启SSL连接
  5. 大学生能从计算机游戏中受益,2017年大学英语四级作文习题及范文:大学生玩游戏...
  6. springboot—监听容器启动事件—拦截器及注册
  7. PostgreSQL从菜鸟到专家 什么是数据库管理系统
  8. 我们的心情,你能体会吗,Ms. Phoebe?
  9. 裁员70%,CTO亲自写代码!(聊聊职场中年危机)
  10. LiveNVR视频平台接收无人机等移动终端RTMP推流后转成GB28181协议输出级联到GB28181视频平台的操作说明...