/*clear ACCDET IRQ in accdet register*/ 814 static inline void clear_accdet_interrupt(void) 815 { 816 /*it is safe by using polling to adjust when to clear IRQ_CLR_BIT*/ 817 pmic_pwrap_write(ACCDET_IRQ_STS, ((pmic_pwrap_read(ACCDET_IRQ_STS)) & 0x8000) | (IRQ_CLR_BIT)); 818 ACCDET_DEBUG("[Accdet]clear_accdet_interrupt: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); 819 } 820 821 static inline void clear_accdet_eint_interrupt(void) 822 { 823 pmic_pwrap_write(ACCDET_IRQ_STS, (((pmic_pwrap_read(ACCDET_IRQ_STS)) & 0x8000) | IRQ_EINT_CLR_BIT)); 824 ACCDET_DEBUG("[Accdet]clear_accdet_eint_interrupt: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); 825 } 826 827 static inline void check_cable_type(void) 828 { 829 int current_status = 0; 830 int irq_temp = 0; /*for clear IRQ_bit*/ 831 int wait_clear_irq_times = 0; 832 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 833 int pin_adc_value = 0; 834 #define PIN_ADC_CHANNEL 5 835 #endif 836 837 current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6); /*A=bit1; B=bit0*/ 838 ACCDET_DEBUG("[Accdet]accdet interrupt happen:[%s]current AB = %d\n", 839 accdet_status_string[accdet_status], current_status); 840 841 button_status = 0; 842 pre_status = accdet_status; 843 844 /*ACCDET_DEBUG("[Accdet]check_cable_type: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));*/ 845 IRQ_CLR_FLAG = false; 846 switch (accdet_status) { 847 case PLUG_OUT: 848 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 849 pmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1); 850 #endif 851 if (current_status == 0) { 852 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 853 /*micbias always on during detected PIN recognition*/ 854 pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width); 855 pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width); 856 ACCDET_DEBUG("[Accdet]PIN recognition micbias always on!\n"); 857 ACCDET_DEBUG("[Accdet]before adc read, pin_adc_value = %d mv!\n", pin_adc_value); 858 msleep(500); 859 current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6); /*A=bit1; B=bit0*/ 860 if (current_status == 0 && show_icon_delay != 0) { 861 /*accdet_auxadc_switch(1);switch on when need to use auxadc read voltage*/ 862 pin_adc_value = Accdet_PMIC_IMM_GetOneChannelValue(1); 863 ACCDET_DEBUG("[Accdet]pin_adc_value = %d mv!\n", pin_adc_value); 864 /*accdet_auxadc_switch(0);*/ 865 if (180 > pin_adc_value && pin_adc_value > 90) { /*90mv ilegal headset*/ 866 /*mt_set_gpio_out(GPIO_CAMERA_2_CMRST_PIN, GPIO_OUT_ONE);*/ 867 /*ACCDET_DEBUG("[Accdet]PIN recognition change GPIO_OUT!\n");*/ 868 mutex_lock(&accdet_eint_irq_sync_mutex); 869 if (1 == eint_accdet_sync_flag) { 870 cable_type = HEADSET_NO_MIC; 871 accdet_status = HOOK_SWITCH; 872 cable_pin_recognition = 1; 873 ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", 874 cable_pin_recognition); 875 } else { 876 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 877 } 878 mutex_unlock(&accdet_eint_irq_sync_mutex); 879 } else { 880 mutex_lock(&accdet_eint_irq_sync_mutex); 881 if (1 == eint_accdet_sync_flag) { 882 cable_type = HEADSET_NO_MIC; 883 accdet_status = HOOK_SWITCH; 884 } else { 885 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 886 } 887 mutex_unlock(&accdet_eint_irq_sync_mutex); 888 } 889 } 890 #else 891 mutex_lock(&accdet_eint_irq_sync_mutex); 892 if (1 == eint_accdet_sync_flag) { 893 cable_type = HEADSET_NO_MIC; 894 accdet_status = HOOK_SWITCH; 895 } else { 896 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 897 } 898 mutex_unlock(&accdet_eint_irq_sync_mutex); 899 #endif 900 } else if (current_status == 1) { 901 mutex_lock(&accdet_eint_irq_sync_mutex); 902 if (1 == eint_accdet_sync_flag) { 903 accdet_status = MIC_BIAS; 904 cable_type = HEADSET_MIC; 905 /*AB=11 debounce=30ms*/ 906 pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3 * 30); 907 } else { 908 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 909 } 910 mutex_unlock(&accdet_eint_irq_sync_mutex); 911 pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce); 912 /*recover polling set AB 00-01*/ 913 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 914 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 915 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); 916 #endif 917 } else if (current_status == 3) { 918 ACCDET_DEBUG("[Accdet]PLUG_OUT state not change!\n"); 919 #ifdef CONFIG_ACCDET_EINT 920 ACCDET_DEBUG("[Accdet] do not send plug out event in plug out\n"); 921 #else 922 mutex_lock(&accdet_eint_irq_sync_mutex); 923 if (1 == eint_accdet_sync_flag) { 924 accdet_status = PLUG_OUT; 925 cable_type = NO_DEVICE; 926 } else { 927 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 928 } 929 mutex_unlock(&accdet_eint_irq_sync_mutex); 930 #endif 931 } else { 932 ACCDET_DEBUG("[Accdet]PLUG_OUT can't change to this state!\n"); 933 } 934 break; 935 936 case MIC_BIAS: 937 /*solution: resume hook switch debounce time*/ 938 pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0); 939 940 if (current_status == 0) { 941 mutex_lock(&accdet_eint_irq_sync_mutex); 942 if (1 == eint_accdet_sync_flag) { 943 while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) 944 && (wait_clear_irq_times < 3)) { 945 ACCDET_DEBUG("[Accdet]check_cable_type: MIC BIAS clear IRQ on-going1....\n"); 946 wait_clear_irq_times++; 947 msleep(20); 948 } 949 irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS); 950 irq_temp = irq_temp & (~IRQ_CLR_BIT); 951 pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp); 952 IRQ_CLR_FLAG = true; 953 accdet_status = HOOK_SWITCH; 954 } else { 955 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 956 } 957 mutex_unlock(&accdet_eint_irq_sync_mutex); 958 button_status = 1; 959 if (button_status) { 960 mutex_lock(&accdet_eint_irq_sync_mutex); 961 if (1 == eint_accdet_sync_flag) 962 multi_key_detection(current_status); 963 else 964 ACCDET_DEBUG("[Accdet] multi_key_detection: Headset has plugged out\n"); 965 mutex_unlock(&accdet_eint_irq_sync_mutex); 966 /*accdet_auxadc_switch(0);*/ 967 /*recover pwm frequency and duty*/ 968 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 969 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); 970 } 971 } else if (current_status == 1) { 972 mutex_lock(&accdet_eint_irq_sync_mutex); 973 if (1 == eint_accdet_sync_flag) { 974 accdet_status = MIC_BIAS; 975 cable_type = HEADSET_MIC; 976 ACCDET_DEBUG("[Accdet]MIC_BIAS state not change!\n"); 977 } else { 978 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 979 } 980 mutex_unlock(&accdet_eint_irq_sync_mutex); 981 } else if (current_status == 3) { 982 #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ 983 ACCDET_DEBUG("[Accdet]do not send plug ou in micbiast\n"); 984 mutex_lock(&accdet_eint_irq_sync_mutex); 985 if (1 == eint_accdet_sync_flag) 986 accdet_status = PLUG_OUT; 987 else 988 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 989 mutex_unlock(&accdet_eint_irq_sync_mutex); 990 #else 991 mutex_lock(&accdet_eint_irq_sync_mutex); 992 if (1 == eint_accdet_sync_flag) { 993 accdet_status = PLUG_OUT; 994 cable_type = NO_DEVICE; 995 } else { 996 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 997 } 998 mutex_unlock(&accdet_eint_irq_sync_mutex); 999 #endif 1000 } else { 1001 ACCDET_DEBUG("[Accdet]MIC_BIAS can't change to this state!\n"); 1002 } 1003 break; 1004 1005 case HOOK_SWITCH: 1006 if (current_status == 0) { 1007 mutex_lock(&accdet_eint_irq_sync_mutex); 1008 if (1 == eint_accdet_sync_flag) { 1009 /*for avoid 01->00 framework of Headset will report press key info for Audio*/ 1010 /*cable_type = HEADSET_NO_MIC;*/ 1011 /*accdet_status = HOOK_SWITCH;*/ 1012 ACCDET_DEBUG("[Accdet]HOOK_SWITCH state not change!\n"); 1013 } else { 1014 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1015 } 1016 mutex_unlock(&accdet_eint_irq_sync_mutex); 1017 } else if (current_status == 1) { 1018 mutex_lock(&accdet_eint_irq_sync_mutex); 1019 if (1 == eint_accdet_sync_flag) { 1020 multi_key_detection(current_status); 1021 accdet_status = MIC_BIAS; 1022 cable_type = HEADSET_MIC; 1023 } else { 1024 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1025 } 1026 mutex_unlock(&accdet_eint_irq_sync_mutex); 1027 /*accdet_auxadc_switch(0);*/ 1028 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 1029 cable_pin_recognition = 0; 1030 ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); 1031 pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); 1032 pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); 1033 #endif 1034 /*solution: reduce hook switch debounce time to 0x400*/ 1035 pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce); 1036 } else if (current_status == 3) { 1037 1038 #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION 1039 cable_pin_recognition = 0; 1040 ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); 1041 mutex_lock(&accdet_eint_irq_sync_mutex); 1042 if (1 == eint_accdet_sync_flag) 1043 accdet_status = PLUG_OUT; 1044 else 1045 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1046 mutex_unlock(&accdet_eint_irq_sync_mutex); 1047 #endif 1048 #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ 1049 ACCDET_DEBUG("[Accdet] do not send plug out event in hook switch\n"); 1050 mutex_lock(&accdet_eint_irq_sync_mutex); 1051 if (1 == eint_accdet_sync_flag) 1052 accdet_status = PLUG_OUT; 1053 else 1054 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1055 mutex_unlock(&accdet_eint_irq_sync_mutex); 1056 #else 1057 mutex_lock(&accdet_eint_irq_sync_mutex); 1058 if (1 == eint_accdet_sync_flag) { 1059 accdet_status = PLUG_OUT; 1060 cable_type = NO_DEVICE; 1061 } else { 1062 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1063 } 1064 mutex_unlock(&accdet_eint_irq_sync_mutex); 1065 #endif 1066 } else { 1067 ACCDET_DEBUG("[Accdet]HOOK_SWITCH can't change to this state!\n"); 1068 } 1069 break; 1070 case STAND_BY: 1071 if (current_status == 3) { 1072 #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ 1073 ACCDET_DEBUG("[Accdet]accdet do not send plug out event in stand by!\n"); 1074 #else 1075 mutex_lock(&accdet_eint_irq_sync_mutex); 1076 if (1 == eint_accdet_sync_flag) { 1077 accdet_status = PLUG_OUT; 1078 cable_type = NO_DEVICE; 1079 } else { 1080 ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); 1081 } 1082 mutex_unlock(&accdet_eint_irq_sync_mutex); 1083 #endif 1084 } else { 1085 ACCDET_DEBUG("[Accdet]STAND_BY can't change to this state!\n"); 1086 } 1087 break; 1088 1089 default: 1090 ACCDET_DEBUG("[Accdet]check_cable_type: accdet current status error!\n"); 1091 break; 1092 1093 } 1094 1095 if (!IRQ_CLR_FLAG) { 1096 mutex_lock(&accdet_eint_irq_sync_mutex); 1097 if (1 == eint_accdet_sync_flag) { 1098 while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && (wait_clear_irq_times < 3)) { 1099 ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going2....\n"); 1100 wait_clear_irq_times++; 1101 msleep(20); 1102 } 1103 } 1104 irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS); 1105 irq_temp = irq_temp & (~IRQ_CLR_BIT); 1106 pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp); 1107 mutex_unlock(&accdet_eint_irq_sync_mutex); 1108 IRQ_CLR_FLAG = true; 1109 ACCDET_DEBUG("[Accdet]check_cable_type:Clear interrupt:Done[0x%x]!\n", pmic_pwrap_read(ACCDET_IRQ_STS)); 1110 1111 } else { 1112 IRQ_CLR_FLAG = false; 1113 } 1114 1115 ACCDET_DEBUG("[Accdet]cable type:[%s], status switch:[%s]->[%s]\n", 1116 accdet_report_string[cable_type], accdet_status_string[pre_status], 1117 accdet_status_string[accdet_status]); 1118 }
时间: 2025-07-21 09:01:21 浏览: 12
<think>我们正在分析一个耳机检测驱动中的`check_cable_type`函数。该函数负责根据当前状态和读取的寄存器值来确定耳机类型和状态变化。
函数主要逻辑:
1. 读取当前状态寄存器值(ACCDET_STATE_RG),提取A、B两个状态位(current_status)
2. 根据accdet_status(当前记录的状态)和current_status(硬件当前状态)进行状态转移和事件处理
3. 使用互斥锁(accdet_eint_irq_sync_mutex)保护共享变量(如eint_accdet_sync_flag)的访问
4. 在状态转移过程中,可能会调用multi_key_detection进行按键检测,并设置cable_type(耳机类型)和accdet_status(状态)
状态定义:
从代码中可以看出,accdet_status有以下几个状态:
PLUG_OUT: 拔出状态
MIC_BIAS: 带麦克风的耳机(四极)插入状态
HOOK_SWITCH: 无麦克风的耳机(三极)插入状态,或按键状态
STAND_BY: 待机状态(代码中处理较少)
另外,cable_type有:
HEADSET_NO_MIC: 无麦克风耳机(三极)
HEADSET_MIC: 带麦克风耳机(四极)
NO_DEVICE: 无设备
关键变量:
eint_accdet_sync_flag: 用于同步中断事件,表示耳机插入事件是否有效(防止在拔出过程中处理中断)
函数流程:
1. 获取当前硬件状态current_status(AB两位)
2. 根据当前accdet_status(之前的状态)进行分支处理(switch)
3. 在每个状态分支中,根据current_status的值(0,1,3)进行不同的处理
详细分析每个状态分支:
一、当前状态为PLUG_OUT(拔出状态)时:
- 如果current_status为0(AB=00):
#ifdef CONFIG_ACCDET_PIN_RECOGNIZATION(支持引脚识别)
设置去抖参数,然后打开麦克风偏置(micbias always on),延迟500ms后再次读取状态。
如果状态仍为0,则进行ADC采样(检测引脚电压):
如果电压在90mv到180mv之间,则认为是非法耳机(可能是三极耳机,但代码中标记为HEADSET_NO_MIC)并设置cable_pin_recognition=1(表示通过引脚识别出的三极耳机)
否则,也设置为三极耳机(HEADSET_NO_MIC)并进入HOOK_SWITCH状态(但没有设置cable_pin_recognition)
#else
直接设置为三极耳机(HEADSET_NO_MIC)并进入HOOK_SWITCH状态
#endif
- 如果current_status为1(AB=01):
设置为四极耳机(HEADSET_MIC),进入MIC_BIAS状态,并设置去抖参数(debounce3为30倍的设定值,即30ms*30=900ms?)
同时设置按键按下的去抖时间为button_press_debounce(较短)
- 如果current_status为3(AB=11):
在PLUG_OUT状态下出现AB=11,可能是未改变状态(即仍然为拔出),但根据配置(如定义了CONFIG_ACCDET_EINT)可能不发送事件,或者设置为PLUG_OUT(无设备)
二、当前状态为MIC_BIAS(四极耳机插入)时:
- 恢复去抖时间(debounce0为正常值)
- 如果current_status为0(AB=00):
清除中断标志,并设置状态为HOOK_SWITCH(注意:这里在状态转换后,还进行了按键检测(multi_key_detection))
同时,设置button_status=1,表示有按键事件?然后调用multi_key_detection(注意:这里传递的current_status是0,表示按键释放?)
最后恢复PWM设置。
- 如果current_status为1(AB=01):
状态不变(仍然是MIC_BIAS,四极耳机)
- 如果current_status为3(AB=11):
进入PLUG_OUT状态(拔出),设置cable_type为NO_DEVICE。
三、当前状态为HOOK_SWITCH(三极耳机插入)时:
- 如果current_status为0(AB=00):
状态不变(还是HOOK_SWITCH),打印日志
- 如果current_status为1(AB=01):
调用multi_key_detection(注意:此时传递的current_status是1,表示按键按下?)然后状态转为MIC_BIAS(四极耳机)?这里似乎有矛盾。
注意:三极耳机只有三个触点(左、右、地),不会出现AB=01(四极耳机才有的状态)。所以这里可能是检测到四极耳机了?
实际上,当三极耳机上按下按键时,会将左右声道短接到麦克风,从而模拟出四极耳机的状态?所以这里可能是按键事件导致状态变化。
因此,这里将状态改为MIC_BIAS(表示按键按下,进入四极耳机模式?)并设置cable_type为HEADSET_MIC(四极)?但三极耳机按下按键时,我们不应该改变耳机类型。
这里可能设计为:当三极耳机按下按键时,我们暂时将其当作四极耳机来处理(因为此时电路连接类似四极耳机),然后通过按键检测来上报按键事件。
在按键释放后,状态会回到HOOK_SWITCH(三极耳机状态)。
另外,这里还做了一些操作:恢复PWM设置,设置去抖时间为button_press_debounce(较短,以便快速响应按键)
- 如果current_status为3(AB=11):
进入PLUG_OUT状态(拔出)
四、当前状态为STAND_BY(待机)时:
只有current_status为3(AB=11)时,才进入PLUG_OUT状态。
最后,函数会清除中断标志(如果之前没有清除的话),并打印状态转换日志。
注意:在整个过程中,都使用eint_accdet_sync_flag(在互斥锁保护下)来判断耳机是否在检测过程中被拔出。如果被拔出(eint_accdet_sync_flag为0),则不进行状态转换。
状态转移图(简化):
PLUG_OUT -> HOOK_SWITCH (当检测到三极耳机)
PLUG_OUT -> MIC_BIAS (当检测到四极耳机)
MIC_BIAS -> HOOK_SWITCH (当AB从01变为00,即按键按下?)
HOOK_SWITCH -> MIC_BIAS (当AB从00变为01,即按键释放?但实际上代码中在HOOK_SWITCH状态遇到AB=01会转到MIC_BIAS,这可能是按键按下)
MIC_BIAS -> PLUG_OUT (当AB=11)
HOOK_SWITCH -> PLUG_OUT (当AB=11)
但注意:状态转移中,按键事件会触发状态在HOOK_SWITCH和MIC_BIAS之间转换,而PLUG_OUT是初始和结束状态。
问题:为什么在MIC_BIAS状态下,AB=00会转换到HOOK_SWITCH?而在HOOK_SWITCH状态下,AB=01会转换到MIC_BIAS?
这可能是因为:
- 在四极耳机上按下按键时,电路状态会从AB=01(MIC_BIAS)变为AB=00(按键按下,麦克风与地短路,相当于三极耳机的状态?),所以转到HOOK_SWITCH状态(三极状态)并检测按键。
- 而在三极耳机上按下按键时,电路状态会从AB=00(HOOK_SWITCH)变为AB=01(按键按下,左右声道短接到麦克风引脚,模拟四极耳机的麦克风状态),所以转到MIC_BIAS状态(四极状态)并检测按键。
因此,状态转移实际上是根据按键按下/释放引起的电路变化而设计的。
总结:
这个函数通过状态机来管理耳机的插入、拔出和按键事件,结合硬件状态(AB两位)和当前状态,进行状态转移,并在转移过程中上报事件(通过调用send_accdet_status_event和send_key_event,但这两个调用不在这个函数中,而是在状态转移后的其他地方?)。
注意:函数中并没有直接上报事件,而是设置cable_type和accdet_status,事件上报可能在另一个函数(如工作队列函数)中处理。
另外,代码中很多地方使用互斥锁来保护对eint_accdet_sync_flag的访问,这是为了防止在中断服务例程中修改这个标志时发生竞争条件。
最后,函数末尾会清除中断标志(如果之前没有清除的话),确保中断不会被重复触发。
由于代码较长,我们只分析主要逻辑,具体细节可结合注释和调试日志。</think>以下是对耳机检测驱动中状态机与电缆类型识别机制的详细解析:
### 核心状态机设计
```mermaid
stateDiagram-v2
[*] --> PLUG_OUT
PLUG_OUT --> HOOK_SWITCH: AB=00 (三极耳机)
PLUG_OUT --> MIC_BIAS: AB=01 (四极耳机)
HOOK_SWITCH --> MIC_BIAS: AB=01 (按键按下)
MIC_BIAS --> HOOK_SWITCH: AB=00 (按键释放)
HOOK_SWITCH --> PLUG_OUT: AB=11 (拔出)
MIC_BIAS --> PLUG_OUT: AB=11 (拔出)
```
### 关键处理流程
#### 1. 状态寄存器解析(行837)
```c
current_status = (pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6;
```
- **AB位含义**:
- `00`:三极耳机(无麦克风)
- `01`:四极耳机(带麦克风)
- `11`:拔出状态
#### 2. 引脚识别机制(CONFIG_ACCDET_PIN_RECOGNIZATION)
```c
#ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
pin_adc_value = Accdet_PMIC_IMM_GetOneChannelValue(1); // ADC通道1采样
if (180 > pin_adc_value && pin_adc_value > 90) { // 90-180mV范围
cable_type = HEADSET_NO_MIC; // 识别为三极耳机
cable_pin_recognition = 1; // 设置引脚识别标志
}
#endif
```
**电压阈值**:
- 90-180mV → 三极耳机
- 其他范围 → 四极耳机
#### 3. 状态转移控制
##### (1) PLUG_OUT → HOOK_SWITCH(三极耳机插入)
```c
case PLUG_OUT:
if (current_status == 0) {
cable_type = HEADSET_NO_MIC;
accdet_status = HOOK_SWITCH;
}
```
##### (2) PLUG_OUT → MIC_BIAS(四极耳机插入)
```c
else if (current_status == 1) {
accdet_status = MIC_BIAS;
cable_type = HEADSET_MIC;
pmic_pwrap_write(ACCDET_DEBOUNCE3, debounce3*30); // 配置去抖
}
```
##### (3) MIC_BIAS ↔ HOOK_SWITCH(按键检测)
```c
case MIC_BIAS:
if (current_status == 0) { // 按键按下
accdet_status = HOOK_SWITCH;
multi_key_detection(current_status); // 触发按键检测
}
case HOOK_SWITCH:
if (current_status == 1) { // 按键释放
accdet_status = MIC_BIAS;
multi_key_detection(current_status);
}
```
### 互斥锁保护机制
```c
mutex_lock(&accdet_eint_irq_sync_mutex);
if (1 == eint_accdet_sync_flag) { // 检查插拔同步标志
// 执行状态变更操作
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
```
**作用**:
1. 防止中断服务程序与工作队列并发访问共享状态
2. 确保在耳机拔出时不处理无效状态转换
3. 避免按键检测过程中的竞态条件
### 寄存器配置策略
| 寄存器 | 功能说明 | 典型配置位置 |
|----------------------|-----------------------------------|-----------------------|
| ACCDET_DEBOUNCE0 | 按键释放去抖时间 | 行938, 1035 |
| ACCDET_DEBOUNCE3 | 四极耳机插入去抖时间 | 行906 |
| ACCDET_PWM_WIDTH | PWM脉冲宽度配置 | 行758, 914 |
| ACCDET_PWM_THRESH | PWM电压阈值 | 行759, 915 |
### 异常处理机制
```c
// 中断清除重试机制(行943-948)
while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) &&
(wait_clear_irq_times < 3)) {
wait_clear_irq_times++;
msleep(20); // 20ms重试间隔
}
```
**设计要点**:
1. 最大重试次数3次防止死循环
2. 20ms延时兼顾硬件响应速度和系统性能
3. 配合IRQ_CLR_FLAG确保中断状态同步
### 调试日志系统
```c
ACCDET_DEBUG("cable type:[%s], status:[%s]->[%s]\n",
accdet_report_string[cable_type],
accdet_status_string[pre_status],
accdet_status_string[accdet_status]); // 行1115
```
**日志等级**:
- 状态转换:INFO级(常规记录)
- 异常检测:WARN级(如行932,1001)
- 硬件错误:ERROR级(如行802负电压检测)
阅读全文
相关推荐

















