mtk耳机调试
一.耳机的基本知识
1.手机全部使用了标准的3.5mm接口,对于一款采用3段式3.5mm接口的耳机来说是不存在兼容问题了,但采用四段式的线控耳机仍旧是有不兼容情况。常见的三段式接口叫做TRS端子,四段式为TRRS端子
2. 智能手机所使用四段式的3.5mm TRRS端子是有两种接口定义标准的,OMTP和CTIA,OMTP就是我们俗称的国家标准,CTIA是国际标准,两种标准在接口前两段的定义都是相同的。最新的手机基本都使用了CTIA标准。
3. 三段式的TRS端子的定义,从上到下依次是左声道、右声道和接地,这也就是为什么它能兼容任何手机的原因了。
4.线控结构,其实原理也很简单,耳机接口上用于输入信号的只有麦克风正极了,既然多键线控耳机一样是使用4段式的接口,那么线控的命令一定也是通过这里输入手机的。
市面上常见的线控类型大致有这几种,音量滑块带麦线控、单键带麦和多键带麦,通过音量滑块改变音量原理很简单,只要在电路当中串入可变电阻即可实现。采用多按键的就比较复杂了,但依旧是通过改变电阻来实现的,从原理电路图上不难看出,不同的按键下串入了不同的电阻,当按键被按下后不同的电阻被接入到了回路当中,麦克风正极接收到的信号也随之发生改变,借此手机可以来识别用户按下的是哪个按键,应该执行何种操作。
二.MTK平台耳机的检测方式
1.Accdet only
此方式是让耳机micbias 常开下,依靠耳机内部中断来检测耳机处于的状态的。但此方式会带来耳机插入瞬间有pop杂音的出现。
2.Accdet+EINT方式
此方式在耳机为插入时,micbias是被disable的。利用中断EINT来打开micbias`,从而达到省功耗和减小杂音的效果的。待插入后,耳机检测走的路线还是accdet内部中断。
三.Accdet检测pin内部比较器
电压范围说明
mt6589/72:
– Plug out state: 1.77V Voltage 1.9V (A=1, B=1);– Mic Bias state: 0.5V Voltage<1.77V (A=0, B=1);– Hook Switch state: 0V Voltage < 0.5V (A=0, B=0).
其中Hook switch multi-key电压分布:
0v<=MD<0.09V<=UP<0.24V<=DW<0.5V
0v<=MD<0.09V<=UP<0.24V<=DW<0.5V
内部通过adc读取电压值,
MD:middle keyUP: up keyDW:down key
另外一种:看芯片手册(pmu)或者驱动
MD UP DW
|--------------------|---------------|---------------|
0V<=MD< 0.08V<= UP<0.22V<=DW <0.5V
|--------------------|---------------|---------------|
0V<=MD< 0.08V<= UP<0.22V<=DW <0.5V
耳机按键的电阻值推荐如下:
Middle Key:0欧Up Key:220欧Down Key:600欧
ADC读取的耳机按键电压是根据基准电压1.9V来输出,就算MICBIAS电压调整到2.7V,PMIC ADC芯片内部会根据读取到的电压转换基准电压后输出一个值。
这就解释了为什么MICBIAS电压调整后,耳机按键检测的电压范围不改变的原因。
四.ACCDET模块耳机检测的原理
ACCDET内部有两个比较器,会根据传入的电压判断并产生中断。ACCDET的输入电压即耳机 MIC PIN 的电压,内部比较器的输出分别对应A/B两个寄存器。
ACCDET内部两个比较器的Vref分别是1.77V和0.5V(硬件决定的,不能修改),所以,对应的电压有
3个范围:
1.77V-1.9V: 未插入耳机的状态(AB=B11)
0.5V-1.77V: 插入4段式(有Mic)耳机时的状态(AB = B01)
0-0.5V : 插入3段式耳机时的状态, 或者4段式按键按下时的状态(AB = B00)
耳机的状态会保存到ACCDET的寄存器中,当电压在任意2个范围间切换时,状态发生变化,ACCDET产生
中断,中断处理中读取状态寄存器的值,并根据状态的变化做相应的处理.
如果电压调整到2.5或者其他.各段会按照比例变化。
五.调整耳机MICBIAS电压的方法
修改文件
alps\kernel-3.10\drivers\misc\mediatek\mach\$platform\$project\accdet\accdet_custom_def.h
修改下面的宏:
#define ACCDET_HIGH_VOL_MODE#ifdef ACCDET_HIGH_VOL_MODE#define ACCDET_MIC_VOL 7 //2.7v#else#define ACCDET_MIC_VOL 2 //1.9v#endif
其中数字表示的电压如下:
MIC Bias 0 Output voltage selection
0: 1.7V1: 1.8V2: 1.9V3: 2.0V4: 2.1V5: 2.3V6: 2.5V7: 2.7V
六.驱动分析
驱动入口:
accdet_mod_init: Accdet_drv.c (kernel-3.10\drivers\misc\mediatek\accdet)
platform_driver_register(&accdet_driver); //调用accdet_probe函数
accdet_probe
mt_accdet_probe(); //调用的这个函数在Accdet.c (kernel-3.10\drivers\misc\mediatek\accdet\mt6735)
press_key_time = get_headset_key_custom_setting(); //得到长按的时间:在Accdet_custom.c (kernel-3.10\drivers\misc\mediatek\mach\mt6735\lentk6753_65c_l1\accdet)中
switch_dev_register(&accdet_data); //创建sysfs接口
cdev_add(accdet_cdev, accdet_devno, 1); //添加字符设备
init_timer(&micbias_timer); //定时器用于插入三段式耳机后关闭micbias,因为不需要录音
input_register_device(kpd_accdet_dev) //注册input子系统用于耳机按键上报
INIT_WORK(&accdet_work, accdet_work_callback); //accdet_work的工作队列
pmic_register_interrupt_callback(12,accdet_int_handler); //设置中断的调用函数
pmic_register_interrupt_callback(13,accdet_eint_int_handler);
accdet_init(); //初始化accdet,这个pmu中的寄存器
queue_work(accdet_workqueue, &accdet_work); //schedule a work for the first detection ,第一次检测
INIT_WORK(&accdet_disable_work, disable_micbias_callback); //初始化micbias的工作队列
INIT_WORK(&accdet_eint_work, accdet_eint_work_callback); //accdet中断的工作队列
INIT_WORK(&sendkey_eint_work, sendkey_eint_work_callback); //自定义的sendkey工作队列
accdet_setup_eint //初始化中断
mt65xx_eint_registration(, accdet_eint_func, 0);中断处理函数为accdet_eint_func
到这里初始化完成了
执行第一次检测:比如耳机插入后开机这种情况
queue_work(accdet_workqueue, &accdet_work);
accdet_work_callback
check_cable_type //检测耳机的状态,就是是不是一上电已经插入了
switch_set_state((struct switch_dev *)&accdet_data, cable_type); //如果已经插入就上报
kobject_uevent_env //填充上报环境变量
kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE); //上报,发送改变
当开机后插入耳机时,int中断产生
accdet_eint_func
if(cur_eint_state == EINT_PIN_PLUG_IN ) //如果已经插入了,现在就是拔出
cur_eint_state = EINT_PIN_PLUG_IN; //没有插入,就设置为插入状态
queue_work(accdet_eint_workqueue, &accdet_eint_work); //调用accdet_eint_work工作队列
accdet_eint_work_callback //调用相应函数
eint_accdet_sync_flag = 1; //设置为1
accdet_init();// do set pwm_idle on in accdet_init,初始化accdet
enable_accdet(ACCDET_SWCTRL_EN); //启动accdet
//Turn on micbias always
pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width); //打开micbias ,公司定义的
pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width);//公司定义的
sendkey_setup_eint(); //sendkey中断注册,公司定义的
检测按键
当按下按键accdet检测到电压区域变化: 通过pmu的中断,pm会调用设置callback函数,分别是pmu的中断12和中断13
pmic_register_interrupt_callback(12,accdet_int_handler); //设置中断的调用函数pmic_register_interrupt_callback(13,accdet_eint_int_handler);
accdet_int_handler和 accdet_eint_int_handler都调用accdet_irq_handler
accdet_irq_handler
accdet_get_current_time //得到现在的时间
clear_accdet_interrupt(); //清中断
accdet_workqueue_func
queue_work(accdet_workqueue, &accdet_work); //执行函数为accdet_work_callback
accdet_work_callback
check_cable_type(); //
current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6) //得到现在的状态, 包括按键检测,三段式耳机检测等
if(1 == eint_accdet_sync_flag) { switch_set_state((struct switch_dev *)&accdet_data, cable_type); /、
七.在kernel层实现sendkey的长按,双击,单击上报:accdet.c
附件中用
#ifdef RUNBO_CUST_HEADSET
#endif
包含的代码是用于实现这个功能
注意:mic的mode很重要,有没有接电容可能导致mic无声,还有五六脚一定要接地。mic的P端的电压一般在0.7,N端接地。