mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
Merge "ASoC: wcd: add polling for cross connection"
This commit is contained in:
commit
786caaa7f8
1 changed files with 157 additions and 66 deletions
|
@ -46,6 +46,7 @@
|
|||
#define HS_DETECT_PLUG_TIME_MS (3 * 1000)
|
||||
#define SPECIAL_HS_DETECT_TIME_MS (2 * 1000)
|
||||
#define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
|
||||
#define GND_MIC_SWAP_THRESHOLD 4
|
||||
|
||||
#define WCD_MBHC_RSC_LOCK(mbhc) \
|
||||
{ \
|
||||
|
@ -667,6 +668,51 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool wcd_check_cross_conn(struct wcd_mbhc *mbhc)
|
||||
{
|
||||
u16 result1, swap_res;
|
||||
struct snd_soc_codec *codec = mbhc->codec;
|
||||
enum wcd_mbhc_plug_type plug_type = mbhc->current_plug;
|
||||
s16 reg, reg1;
|
||||
|
||||
reg = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL);
|
||||
reg1 = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2);
|
||||
/*
|
||||
* Check if there is any cross connection,
|
||||
* Micbias and schmitt trigger (HPHL-HPHR)
|
||||
* needs to be enabled.
|
||||
*/
|
||||
result1 = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_BTN_RESULT);
|
||||
/* Make sure micbias is enabled now */
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MICB_2_EN, 0x80, 0x80);
|
||||
/*If enabling micbias, turn off current source*/
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL, 0xB0, 0x80);
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2, 0x6, 0x4);
|
||||
/* read reg MBHC_RESULT_2 value with cross connection bit */
|
||||
swap_res = snd_soc_read(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT);
|
||||
pr_debug("%s: swap_res %x\n", __func__, swap_res);
|
||||
if (!result1 && !(swap_res & 0x04)) {
|
||||
plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
|
||||
pr_debug("%s: Cross connection identified\n", __func__);
|
||||
} else {
|
||||
pr_debug("%s: No Cross connection found\n", __func__);
|
||||
}
|
||||
|
||||
/* Disable micbias and schmitt trigger */
|
||||
snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2, reg1);
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MICB_2_EN,
|
||||
0x80, 0x00);
|
||||
snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL, reg);
|
||||
pr_debug("%s: leave, plug type: %d\n", __func__, plug_type);
|
||||
|
||||
return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
|
||||
}
|
||||
|
||||
static void wcd_correct_swch_plug(struct work_struct *work)
|
||||
{
|
||||
struct wcd_mbhc *mbhc;
|
||||
|
@ -675,6 +721,8 @@ static void wcd_correct_swch_plug(struct work_struct *work)
|
|||
unsigned long timeout;
|
||||
u16 result1, result2;
|
||||
bool wrk_complete = false;
|
||||
int pt_gnd_mic_swap_cnt = 0;
|
||||
bool is_pa_on;
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
|
||||
|
@ -686,19 +734,16 @@ static void wcd_correct_swch_plug(struct work_struct *work)
|
|||
mbhc->mbhc_cb->enable_mb_source(codec, true);
|
||||
timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
|
||||
while (!time_after(jiffies, timeout)) {
|
||||
if (mbhc->hs_detect_work_stop) {
|
||||
pr_debug("%s: stop requested\n", __func__);
|
||||
if (mbhc->hs_detect_work_stop || wcd_swch_level_remove(mbhc)) {
|
||||
pr_debug("%s: stop requested: %d\n", __func__,
|
||||
mbhc->hs_detect_work_stop);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* allow sometime and re-check stop requested again.
|
||||
* this is as recommeneded by HW design team after
|
||||
* multiple test iterations with trial error basis.
|
||||
*/
|
||||
/* allow sometime and re-check stop requested again */
|
||||
msleep(200);
|
||||
if (mbhc->hs_detect_work_stop) {
|
||||
pr_debug("%s: stop requested\n", __func__);
|
||||
if (mbhc->hs_detect_work_stop || wcd_swch_level_remove(mbhc)) {
|
||||
pr_debug("%s: stop requested: %d\n", __func__,
|
||||
mbhc->hs_detect_work_stop);
|
||||
goto exit;
|
||||
}
|
||||
result1 = snd_soc_read(codec,
|
||||
|
@ -706,30 +751,86 @@ static void wcd_correct_swch_plug(struct work_struct *work)
|
|||
result2 = snd_soc_read(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT);
|
||||
pr_debug("%s: result2 = %x\n", __func__, result2);
|
||||
|
||||
is_pa_on = snd_soc_read(codec,
|
||||
MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN) &
|
||||
0x30;
|
||||
|
||||
if ((!(result2 & 0x01)) && (!is_pa_on)) {
|
||||
/* Check for cross connection*/
|
||||
if (wcd_check_cross_conn(mbhc)) {
|
||||
plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
|
||||
pt_gnd_mic_swap_cnt++;
|
||||
if (pt_gnd_mic_swap_cnt <
|
||||
GND_MIC_SWAP_THRESHOLD) {
|
||||
continue;
|
||||
} else if (pt_gnd_mic_swap_cnt >
|
||||
GND_MIC_SWAP_THRESHOLD) {
|
||||
/*
|
||||
* This is due to GND/MIC switch didn't
|
||||
* work, Report unsupported plug.
|
||||
*/
|
||||
pr_debug("%s: switch didnt work\n",
|
||||
__func__);
|
||||
goto report;
|
||||
} else if (mbhc->mbhc_cfg->swap_gnd_mic) {
|
||||
pr_debug("%s: US_EU gpio present, flip switch\n",
|
||||
__func__);
|
||||
/*
|
||||
* if switch is toggled, check again,
|
||||
* otherwise report unsupported plug
|
||||
*/
|
||||
if (mbhc->mbhc_cfg->swap_gnd_mic(codec))
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
pt_gnd_mic_swap_cnt++;
|
||||
plug_type = MBHC_PLUG_TYPE_HEADSET;
|
||||
if (pt_gnd_mic_swap_cnt <
|
||||
GND_MIC_SWAP_THRESHOLD) {
|
||||
continue;
|
||||
} else {
|
||||
pt_gnd_mic_swap_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result2 == 1) {
|
||||
pr_debug("%s: cable is extension cable\n", __func__);
|
||||
plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
|
||||
wrk_complete = true;
|
||||
} else {
|
||||
pr_debug("%s: cable is headset\n", __func__);
|
||||
plug_type = MBHC_PLUG_TYPE_HEADSET;
|
||||
if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) {
|
||||
wcd_mbhc_find_plug_and_report(mbhc, plug_type);
|
||||
goto exit;
|
||||
pr_debug("%s: cable might be headset: %d\n", __func__,
|
||||
plug_type);
|
||||
if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
|
||||
plug_type = MBHC_PLUG_TYPE_HEADSET;
|
||||
/*
|
||||
* Report headset only if not already reported
|
||||
* and if there is not button press without
|
||||
* release
|
||||
*/
|
||||
if (mbhc->current_plug !=
|
||||
MBHC_PLUG_TYPE_HEADSET &&
|
||||
!mbhc->btn_press_intr) {
|
||||
pr_debug("%s: cable is headset\n",
|
||||
__func__);
|
||||
goto report;
|
||||
}
|
||||
}
|
||||
wrk_complete = false;
|
||||
}
|
||||
}
|
||||
if (wrk_complete == true)
|
||||
plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
|
||||
else if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
|
||||
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
|
||||
mbhc->btn_press_intr) {
|
||||
pr_debug("%s: Can be slow insertion of headphone\n",
|
||||
__func__);
|
||||
plug_type = MBHC_PLUG_TYPE_HEADPHONE;
|
||||
}
|
||||
} else
|
||||
plug_type = MBHC_PLUG_TYPE_INVALID;
|
||||
if (mbhc->btn_press_intr) {
|
||||
pr_debug("%s: Can be slow insertion of headphone\n", __func__);
|
||||
plug_type = MBHC_PLUG_TYPE_HEADPHONE;
|
||||
}
|
||||
/*
|
||||
* If plug_tye is headset, we might have already reported either in
|
||||
* detect_plug-type or in above while loop, no need to report again
|
||||
*/
|
||||
if (!wrk_complete && plug_type == MBHC_PLUG_TYPE_HEADSET) {
|
||||
pr_debug("%s: It's neither headset nor headphone\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
|
||||
if (wcd_is_special_headset(mbhc)) {
|
||||
|
@ -741,6 +842,9 @@ static void wcd_correct_swch_plug(struct work_struct *work)
|
|||
}
|
||||
|
||||
report:
|
||||
pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
|
||||
__func__, plug_type, wrk_complete,
|
||||
mbhc->btn_press_intr);
|
||||
wcd_mbhc_find_plug_and_report(mbhc, plug_type);
|
||||
exit:
|
||||
/* Disable external voltage source to micbias if present */
|
||||
|
@ -757,7 +861,9 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
|
|||
long timeout = msecs_to_jiffies(50); /* 50ms */
|
||||
enum wcd_mbhc_plug_type plug_type;
|
||||
int timeout_result;
|
||||
u16 result1, result2, swap_res;
|
||||
u16 result1, result2;
|
||||
bool cross_conn;
|
||||
int try = 0;
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
|
||||
|
@ -792,34 +898,24 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
|
|||
* Micbias and schmitt trigger (HPHL-HPHR)
|
||||
* needs to be enabled.
|
||||
*/
|
||||
pr_debug("%s: result1 %x, result2 %x\n",
|
||||
__func__, result1, result2);
|
||||
pr_debug("%s: result1 %x, result2 %x\n", __func__,
|
||||
result1, result2);
|
||||
if (!(result2 & 0x01)) {
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
|
||||
0x6, 0x2);
|
||||
/*
|
||||
* read reg MBHC_RESULT_2 value with cross
|
||||
* connection bit
|
||||
* Cross connection result is not reliable
|
||||
* so do check for it for 4 times to conclude
|
||||
* cross connection occured or not.
|
||||
*/
|
||||
swap_res = snd_soc_read(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT);
|
||||
pr_debug("%s: swap_res %x\n", __func__, swap_res);
|
||||
|
||||
if (!result1 && !(swap_res & 0x04)) {
|
||||
do {
|
||||
cross_conn = wcd_check_cross_conn(mbhc);
|
||||
try++;
|
||||
} while (try < GND_MIC_SWAP_THRESHOLD);
|
||||
if (cross_conn) {
|
||||
pr_debug("%s: cross con found, start polling\n",
|
||||
__func__);
|
||||
plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
|
||||
pr_debug("%s: Cross connection identified\n",
|
||||
__func__);
|
||||
goto eu_us_switch;
|
||||
} else {
|
||||
pr_debug("%s: No Cross connection found\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Disable micbias and schmitt trigger */
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
|
||||
0x6, 0x0);
|
||||
}
|
||||
if (!result1 && !(result2 & 0x01))
|
||||
plug_type = MBHC_PLUG_TYPE_HEADSET;
|
||||
|
@ -838,20 +934,7 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
|
|||
}
|
||||
}
|
||||
|
||||
eu_us_switch:
|
||||
if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
|
||||
pr_debug("%s: cross connection found\n", __func__);
|
||||
if (mbhc->mbhc_cfg->swap_gnd_mic) {
|
||||
pr_debug("%s: US_EU gpio present, flip switch\n",
|
||||
__func__);
|
||||
if (mbhc->mbhc_cfg->swap_gnd_mic(codec))
|
||||
plug_type = MBHC_PLUG_TYPE_HEADSET;
|
||||
}
|
||||
/* Disable micbias and schmitt trigger */
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
|
||||
0x6, 0x0);
|
||||
}
|
||||
exit:
|
||||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MICB_2_EN,
|
||||
0x80, 0x00);
|
||||
|
@ -862,6 +945,7 @@ eu_us_switch:
|
|||
pr_debug("%s: Valid plug found, plug type is %d\n",
|
||||
__func__, plug_type);
|
||||
if (plug_type != MBHC_PLUG_TYPE_HIGH_HPH &&
|
||||
plug_type != MBHC_PLUG_TYPE_GND_MIC_SWAP &&
|
||||
plug_type != MBHC_PLUG_TYPE_HEADSET &&
|
||||
plug_type != MBHC_PLUG_TYPE_INVALID)
|
||||
wcd_mbhc_find_plug_and_report(mbhc, plug_type);
|
||||
|
@ -870,7 +954,6 @@ eu_us_switch:
|
|||
wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
|
||||
} else
|
||||
wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
|
||||
exit:
|
||||
pr_debug("%s: leave\n", __func__);
|
||||
}
|
||||
|
||||
|
@ -928,9 +1011,9 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
|
|||
snd_soc_update_bits(codec,
|
||||
MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
|
||||
0xB0, 0x00);
|
||||
mbhc->btn_press_intr = false;
|
||||
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
|
||||
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
|
||||
mbhc->btn_press_intr = false;
|
||||
} else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
|
||||
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
|
||||
} else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
|
||||
|
@ -1065,6 +1148,10 @@ irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
|
|||
/* send event to sw intr handler*/
|
||||
mbhc->is_btn_press = true;
|
||||
wake_up_interruptible(&mbhc->wait_btn_press);
|
||||
if (wcd_swch_level_remove(mbhc)) {
|
||||
pr_debug("%s: Switch level is low ", __func__);
|
||||
goto done;
|
||||
}
|
||||
mbhc->btn_press_intr = true;
|
||||
|
||||
msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
|
||||
|
@ -1105,6 +1192,10 @@ static irqreturn_t wcd_mbhc_release_handler(int irq, void *data)
|
|||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
WCD_MBHC_RSC_LOCK(mbhc);
|
||||
if (wcd_swch_level_remove(mbhc)) {
|
||||
pr_debug("%s: Switch level is low ", __func__);
|
||||
goto exit;
|
||||
}
|
||||
mbhc->btn_press_intr = false;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue