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进行上报


 
1 0
原创粉丝点击