Skip to content

Commit 3c8a3ad

Browse files
Srinivasa Rao Mandadapubroonie
authored andcommitted
ASoC: codecs: MBHC: Add support for special headset
Update MBHC driver to support special headset such as apple and huwawei headsets. Signed-off-by: Srinivasa Rao Mandadapu <[email protected]> Co-developed-by: Venkata Prasad Potturu <[email protected]> Signed-off-by: Venkata Prasad Potturu <[email protected]> Reviewed-by: Srinivas Kandagatla <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 5b59289 commit 3c8a3ad

File tree

1 file changed

+71
-4
lines changed

1 file changed

+71
-4
lines changed

sound/soc/codecs/wcd-mbhc-v2.c

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,19 +1022,71 @@ static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result)
10221022
return plug_type;
10231023
}
10241024

1025+
static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc)
1026+
{
1027+
int hs_threshold, micbias_mv;
1028+
1029+
micbias_mv = wcd_mbhc_get_micbias(mbhc);
1030+
if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) {
1031+
if (mbhc->cfg->micb_mv == micbias_mv)
1032+
hs_threshold = mbhc->cfg->hs_thr;
1033+
else
1034+
hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv;
1035+
} else {
1036+
hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) /
1037+
WCD_MBHC_ADC_MICBIAS_MV);
1038+
}
1039+
return hs_threshold;
1040+
}
1041+
1042+
static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc)
1043+
{
1044+
bool is_spl_hs = false;
1045+
int output_mv, hs_threshold, hph_threshold;
1046+
1047+
if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1048+
return false;
1049+
1050+
/* Bump up MIC_BIAS2 to 2.7V */
1051+
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true);
1052+
usleep_range(10000, 10100);
1053+
1054+
output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1055+
hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc);
1056+
hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc);
1057+
1058+
if (output_mv > hs_threshold || output_mv < hph_threshold) {
1059+
if (mbhc->force_linein == true)
1060+
is_spl_hs = false;
1061+
} else {
1062+
is_spl_hs = true;
1063+
}
1064+
1065+
/* Back MIC_BIAS2 to 1.8v if the type is not special headset */
1066+
if (!is_spl_hs) {
1067+
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false);
1068+
/* Add 10ms delay for micbias to settle */
1069+
usleep_range(10000, 10100);
1070+
}
1071+
1072+
return is_spl_hs;
1073+
}
1074+
10251075
static void wcd_correct_swch_plug(struct work_struct *work)
10261076
{
10271077
struct wcd_mbhc *mbhc;
10281078
struct snd_soc_component *component;
10291079
enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
10301080
unsigned long timeout;
10311081
int pt_gnd_mic_swap_cnt = 0;
1032-
int output_mv, cross_conn, hs_threshold, try = 0;
1082+
int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv;
1083+
bool is_spl_hs = false;
10331084
bool is_pa_on;
10341085

10351086
mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
10361087
component = mbhc->component;
10371088

1089+
micbias_mv = wcd_mbhc_get_micbias(mbhc);
10381090
hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
10391091

10401092
/* Mask ADC COMPLETE interrupt */
@@ -1097,6 +1149,16 @@ static void wcd_correct_swch_plug(struct work_struct *work)
10971149
plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
10981150
is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
10991151

1152+
if ((output_mv > hs_threshold) && (!is_spl_hs)) {
1153+
is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc);
1154+
output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1155+
1156+
if (is_spl_hs) {
1157+
hs_threshold = (hs_threshold * wcd_mbhc_get_micbias(mbhc)) /
1158+
micbias_mv;
1159+
}
1160+
}
1161+
11001162
if ((output_mv <= hs_threshold) && !is_pa_on) {
11011163
/* Check for cross connection*/
11021164
cross_conn = wcd_check_cross_conn(mbhc);
@@ -1122,14 +1184,19 @@ static void wcd_correct_swch_plug(struct work_struct *work)
11221184
}
11231185
}
11241186

1125-
if (output_mv > hs_threshold) /* cable is extension cable */
1187+
/* cable is extension cable */
1188+
if (output_mv > hs_threshold || mbhc->force_linein == true)
11261189
plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
11271190
}
11281191

11291192
wcd_mbhc_bcs_enable(mbhc, plug_type, true);
11301193

1131-
if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH)
1132-
wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1194+
if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
1195+
if (is_spl_hs)
1196+
plug_type = MBHC_PLUG_TYPE_HEADSET;
1197+
else
1198+
wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1199+
}
11331200

11341201
wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
11351202
wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);

0 commit comments

Comments
 (0)