MTK6797 Accdet驱动分析总结
来源:互联网 发布:大数据hive 编辑:程序博客网 时间:2024/05/21 17:27
MTK6797 Accdet驱动分析总结
一、相关概念介绍
1、EINT+ACCDET检测中断
EINT中断:主要用来检测耳机的插入和拔出,即plug in 和plug out
ACCDET中断:主要用来检测耳机的事件类型,包括PLUG_OUT、PLUG_IN、MIC_BIAS(耳机上的mic)和HOOK_SWITCH(耳机按键)
a、采用AP端的中断作为EINT,(3 steps:a0 a1 a2)
a0、如果采用此方式,需要打开宏
CONFIG_ACCDET_EINT=y
# CONFIG_ACCDET_EINT_IRQ is not set
a1、also config the dws for eint
a2、meanwhile reconfig the gpio in the dts
b、采用PMIC的中断作为EINT,
如果采用此方式,需要打开宏(only)
CONFIG_ACCDET_EINT_IRQ =y
#CONFGI_ACCDET_EINT is not set
2、耳机按键的检测
耳机按键的原理图如下:
PMIC有内部ADC通道可以读取不同的耳机电压,其中不同事件类型对应的电压如下:
plug out:1.77<=voltage<=1.9
mic bias:0.5v<=voltage<1.77v
hook switch:0v<=voltage<=0.5v
如上三个状态是通过ACCDET_STATE_RG寄存器获取的,通过2个bit A=bit1、B=bit0判断,对应如上的事件如下:
plug out:1.77<=voltage<=1.9 A=1,B=1,AB=3,
mic bias:0.5v<=voltage<1.77v A=0,B=1,AB=1,
hook switch:0v<=voltage<=0.5v A=0,B=0,AB=0,
其中hook switch包括了up、middle、down三个按键,对应的电压如下;
0v<=middle<=0.09v<=up<=0.24v<=down<=0.5v
二、耳机插入流程分析
当插入耳机按键时,首先是触发了EINT中断,然后再触发ACCDET中断,这2个中断都是PMIC函数中注册的,属于PMIC端的中断。
在probe初始化函数中注册了之前提到的两个中断函数,此为中断上半部分:
pmic_register_interrupt_callback(12, accdet_int_handler );pmic_register_interrupt_callback(13, accdet_eint_int_handler );
然后又初始化了两个工作队列accdet_work和accdet_eint_work,对应如上两个中断的下半部分。
1、总的大体流程如下,具体的耳机事件插拔检测在下一副流程图会介绍,
2、这里主要介绍两种耳机模式:MIC_BIAS和HOOK SWITCH
a、MIC_BIAS模式,即插入耳机后的默认模式,状态从PLUG_OUT----->MIC_BIAS,主要代码如下
case PLUG_OUT:#ifdef CONFIG_ACCDET_PIN_RECOGNIZATIONpmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1);#endifif (current_status == 0) {#ifdef CONFIG_ACCDET_PIN_RECOGNIZATION/*micbias always on during detected PIN recognition*/pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width);ACCDET_DEBUG("[Accdet]PIN recognition micbias always on!\n");ACCDET_DEBUG("[Accdet]before adc read, pin_adc_value = %d mv!\n", pin_adc_value);msleep(500);current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6);/*A=bit1; B=bit0*/if (current_status == 0 && show_icon_delay != 0) {/*accdet_auxadc_switch(1);switch on when need to use auxadc read voltage*/pin_adc_value = Accdet_PMIC_IMM_GetOneChannelValue(1);ACCDET_DEBUG("[Accdet]pin_adc_value = %d mv!\n", pin_adc_value);/*accdet_auxadc_switch(0);*/if (180 > pin_adc_value && pin_adc_value > 90) {/*90mv ilegal headset*//*mt_set_gpio_out(GPIO_CAMERA_2_CMRST_PIN, GPIO_OUT_ONE);*//*ACCDET_DEBUG("[Accdet]PIN recognition change GPIO_OUT!\n");*/mutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {cable_type = HEADSET_NO_MIC;accdet_status = HOOK_SWITCH;cable_pin_recognition = 1;ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);} else {mutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {cable_type = HEADSET_NO_MIC;accdet_status = HOOK_SWITCH;} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);}}#elsemutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {cable_type = HEADSET_NO_MIC;accdet_status = HOOK_SWITCH;} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);#endif} else if (current_status == 1) {mutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {accdet_status = MIC_BIAS;cable_type = HEADSET_MIC;#ifdef CONFIG_HEADSET_SUPPORT_FIVE_POLEmsleep(20);if (pmic_pwrap_read(0x0F46) & 0x01) {/*check 5 pole headset*/ACCDET_DEBUG("[Accdet]check 5 pole headset: YES\n");cable_type = HEADSET_FIVE_POLE;}#endif/*AB=11 debounce=30ms*/pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3 * 30);} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce);/*recover polling set AB 00-01*/#ifdef CONFIG_ACCDET_PIN_RECOGNIZATIONpmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));#endif} else if (current_status == 3) {ACCDET_DEBUG("[Accdet]PLUG_OUT state not change!\n");#ifdef CONFIG_ACCDET_EINTACCDET_DEBUG("[Accdet] do not send plug out event in plug out\n");#elsemutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {accdet_status = PLUG_OUT;cable_type = NO_DEVICE;} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);#endif} else {ACCDET_DEBUG("[Accdet]PLUG_OUT can't change to this state!\n");}break;
b、HOOK_SWITCH模式,即耳机按键按下的状态,状态从MIC_BIAS----->HOOK_SWITCH,按键松开时HOOK_SWITCH----->MIC_BIAS,主要代码如下:
case MIC_BIAS:/*solution: resume hook switch debounce time*/pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0);if (current_status == 0) {mutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)&& (wait_clear_irq_times < 3)) {ACCDET_DEBUG("[Accdet]check_cable_type: MIC BIAS clear IRQ on-going1....\n");wait_clear_irq_times++;msleep(20);}irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);irq_temp = irq_temp & (~IRQ_CLR_BIT);pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);IRQ_CLR_FLAG = true;accdet_status = HOOK_SWITCH;} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);button_status = 1;if (button_status) {mutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag)multi_key_detection(current_status);elseACCDET_DEBUG("[Accdet] multi_key_detection: Headset has plugged out\n");mutex_unlock(&accdet_eint_irq_sync_mutex);/*accdet_auxadc_switch(0);*//*recover pwm frequency and duty*/pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));}} else if (current_status == 1) {mutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {accdet_status = MIC_BIAS;cable_type = HEADSET_MIC;ACCDET_DEBUG("[Accdet]MIC_BIAS state not change!\n");} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);} else if (current_status == 3) {#if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQACCDET_DEBUG("[Accdet]do not send plug ou in micbiast\n");mutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag)accdet_status = PLUG_OUT;elseACCDET_DEBUG("[Accdet] Headset has plugged out\n");mutex_unlock(&accdet_eint_irq_sync_mutex);#elsemutex_lock(&accdet_eint_irq_sync_mutex);if (1 == eint_accdet_sync_flag) {accdet_status = PLUG_OUT;cable_type = NO_DEVICE;} else {ACCDET_DEBUG("[Accdet] Headset has plugged out\n");}mutex_unlock(&accdet_eint_irq_sync_mutex);#endif} else {ACCDET_DEBUG("[Accdet]MIC_BIAS can't change to this state!\n");}break;case HOOK_SWITCH: //按键松开后 if (current_status == 0) { mutex_lock(&accdet_eint_irq_sync_mutex); if (1 == eint_accdet_sync_flag) { /*for avoid 01->00 framework of Headset will report press key info for Audio*/ /*cable_type = HEADSET_NO_MIC;*/ /*accdet_status = HOOK_SWITCH;*/ ACCDET_DEBUG("[Accdet]HOOK_SWITCH state not change!\n"); } else { ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); } mutex_unlock(&accdet_eint_irq_sync_mutex); } else if (current_status == 1) { mutex_lock(&accdet_eint_irq_sync_mutex); if (1 == eint_accdet_sync_flag) { multi_key_detection(current_status); accdet_status = MIC_BIAS; cable_type = HEADSET_MIC; } else { ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); } mutex_unlock(&accdet_eint_irq_sync_mutex); /*accdet_auxadc_switch(0);*/ #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION cable_pin_recognition = 0; ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); #endif /*solution: reduce hook switch debounce time to 0x400*/ pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce); } else if (current_status == 3) { #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION cable_pin_recognition = 0; ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); mutex_lock(&accdet_eint_irq_sync_mutex); if (1 == eint_accdet_sync_flag) accdet_status = PLUG_OUT; else ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); mutex_unlock(&accdet_eint_irq_sync_mutex); #endif #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ ACCDET_DEBUG("[Accdet] do not send plug out event in hook switch\n"); mutex_lock(&accdet_eint_irq_sync_mutex); if (1 == eint_accdet_sync_flag) accdet_status = PLUG_OUT; else ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); mutex_unlock(&accdet_eint_irq_sync_mutex); #else mutex_lock(&accdet_eint_irq_sync_mutex); if (1 == eint_accdet_sync_flag) { accdet_status = PLUG_OUT; cable_type = NO_DEVICE; } else { ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); } mutex_unlock(&accdet_eint_irq_sync_mutex); #endif } else { ACCDET_DEBUG("[Accdet]HOOK_SWITCH can't change to this state!\n"); } break;
代码对应的耳机按键处理流程如下:
三、总结
耳机按键处理主要依靠2个中断EINT+ACCDET,然后按键检测依靠内部ADC检测,上报按键事件时,按下和松开都要通过send_key_event进行上报。
- MTK6797 Accdet驱动分析总结
- MTK6797 Accdet驱动分析总结
- 2. MTK6737 7.0 Accdet驱动分析总结
- mtk 耳机accdet检测驱动分析
- alsa声卡驱动分析总结
- alsa声卡驱动分析总结
- alsa声卡驱动分析总结
- linux字符设备驱动总结分析
- alsa声卡驱动分析总结(一)
- alsa声卡驱动分析总结 (二)
- alsa声卡驱动分析总结 (三)
- 按键驱动——plat_button分析总结
- mtk-accdet学习文档
- mtk-accdet学习文档
- 30. accdet调试日志
- uboot移植与源码分析总结(3)-Serial驱动分析
- uboot移植与源码分析总结(3)-Serial驱动分析
- uboot移植与源码分析总结(3)-Serial驱动分析
- QQ联系人1
- zookeeper 实际使用场景举例
- 微信支付流程
- QQ联系人菜单2:
- 错误:/bin/sh: 1: protoc: not found
- MTK6797 Accdet驱动分析总结
- webView使用大全
- 隐马尔可夫模型(五)——隐马尔可夫模型的解码问题(维特比算法)
- Linux中debugfs的应用实例
- Android开发中远程连接
- 14.4.6 Configuring Thread Concurrency for InnoDB 配置Thread 并发
- 在高速信号换层时打回流地VIA过孔,减小回流路径
- 画布画笔
- 修改ubuntu的apt-get软件源