asoc: mbhc: add extcon device for MBHC

Add extcon device for MBHC.

Change-Id: I2f22223bc62f4f4b5f2e8cb61cf7e7d41548947f
Signed-off-by: Meng Wang <mengw@codeaurora.org>
This commit is contained in:
Meng Wang
2020-12-09 12:33:01 +08:00
parent 3ae97cf8fa
commit ecf424366e
4 changed files with 88 additions and 17 deletions

View File

@@ -1049,16 +1049,21 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
mbhc->btn_press_intr = false; mbhc->btn_press_intr = false;
mbhc->is_btn_press = false; mbhc->is_btn_press = false;
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 0);
} else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 0);
} else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
#if IS_ENABLED(CONFIG_AUDIO_QGKI) #if IS_ENABLED(CONFIG_AUDIO_QGKI)
else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP)
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
#endif /* CONFIG_AUDIO_QGKI */ #endif /* CONFIG_AUDIO_QGKI */
else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) extcon_set_state_sync(mbhc->extdev, EXTCON_MECHANICAL, 0);
} else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) {
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 0);
}
} else { } else {
/* /*
* ADC COMPLETE and ELEC_REM interrupts are both enabled for * ADC COMPLETE and ELEC_REM interrupts are both enabled for

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
@@ -861,23 +861,28 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
mbhc->btn_press_intr = false; mbhc->btn_press_intr = false;
mbhc->is_btn_press = false; mbhc->is_btn_press = false;
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
wcd_mbhc_report_plug( wcd_mbhc_report_plug(
mbhc, 0, SND_JACK_HEADSET); mbhc, 0, SND_JACK_HEADSET);
else if (mbhc->current_plug == extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 0);
} else if (mbhc->current_plug ==
MBHC_PLUG_TYPE_HEADPHONE) MBHC_PLUG_TYPE_HEADPHONE)
wcd_mbhc_report_plug( wcd_mbhc_report_plug(
mbhc, 0, SND_JACK_HEADPHONE); mbhc, 0, SND_JACK_HEADPHONE);
#if IS_ENABLED(CONFIG_AUDIO_QGKI) extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 0);
else if (mbhc->current_plug == } else if (mbhc->current_plug ==
MBHC_PLUG_TYPE_GND_MIC_SWAP) MBHC_PLUG_TYPE_GND_MIC_SWAP)
#if IS_ENABLED(CONFIG_AUDIO_QGKI)
wcd_mbhc_report_plug( wcd_mbhc_report_plug(
mbhc, 0, SND_JACK_UNSUPPORTED); mbhc, 0, SND_JACK_UNSUPPORTED);
#endif /* CONFIG_AUDIO_QGKI */ #endif /* CONFIG_AUDIO_QGKI */
else if (mbhc->current_plug == extcon_set_state_sync(mbhc->extdev, EXTCON_MECHANICAL, 0);
MBHC_PLUG_TYPE_HIGH_HPH) } else if (mbhc->current_plug ==
MBHC_PLUG_TYPE_HIGH_HPH) {
wcd_mbhc_report_plug( wcd_mbhc_report_plug(
mbhc, 0, SND_JACK_LINEOUT); mbhc, 0, SND_JACK_LINEOUT);
extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 0);
}
} else { } else {
if (!(hphl_sch && mic_sch && hs_comp_result)) { if (!(hphl_sch && mic_sch && hs_comp_result)) {
/* /*

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
@@ -27,6 +27,14 @@
#include "wcd-mbhc-adc.h" #include "wcd-mbhc-adc.h"
#include <asoc/wcd-mbhc-v2-api.h> #include <asoc/wcd-mbhc-v2-api.h>
static const unsigned int mbhc_ext_dev_supported_table[] = {
EXTCON_JACK_MICROPHONE,
EXTCON_JACK_HEADPHONE,
EXTCON_JACK_LINE_OUT,
EXTCON_MECHANICAL,
EXTCON_NONE,
};
void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc, void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc,
struct snd_soc_jack *jack, int status, int mask) struct snd_soc_jack *jack, int status, int mask)
{ {
@@ -560,6 +568,7 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
struct snd_soc_component *component = mbhc->component; struct snd_soc_component *component = mbhc->component;
bool is_pa_on = false; bool is_pa_on = false;
u8 fsm_en = 0; u8 fsm_en = 0;
int extdev_type = 0;
WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
@@ -648,6 +657,16 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
__func__, mbhc->hph_status); __func__, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
0, WCD_MBHC_JACK_MASK); 0, WCD_MBHC_JACK_MASK);
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
extdev_type = EXTCON_JACK_HEADPHONE;
else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
extdev_type = EXTCON_JACK_MICROPHONE;
else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH)
extdev_type = EXTCON_JACK_LINE_OUT;
else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP)
extdev_type = EXTCON_MECHANICAL;
extcon_set_state_sync(mbhc->extdev, extdev_type, 0);
} }
if (mbhc->hph_status == SND_JACK_LINEOUT) { if (mbhc->hph_status == SND_JACK_LINEOUT) {
@@ -788,6 +807,7 @@ void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
pr_debug("%s: Report extension cable\n", __func__); pr_debug("%s: Report extension cable\n", __func__);
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 1);
/* /*
* If PA is enabled HPHL schmitt trigger can * If PA is enabled HPHL schmitt trigger can
* be unreliable, make sure to disable it * be unreliable, make sure to disable it
@@ -818,6 +838,7 @@ void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
{ {
bool anc_mic_found = false; bool anc_mic_found = false;
enum snd_jack_types jack_type; enum snd_jack_types jack_type;
int ret = 0;
if (mbhc->deinit_in_progress) { if (mbhc->deinit_in_progress) {
pr_info("%s: mbhc deinit in progess: ignore report\n", __func__); pr_info("%s: mbhc deinit in progess: ignore report\n", __func__);
@@ -840,14 +861,20 @@ void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
* report a headphone or unsupported * report a headphone or unsupported
*/ */
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE); wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 1);
} else if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) { } else if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 0);
}
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 0);
}
#if IS_ENABLED(CONFIG_AUDIO_QGKI) #if IS_ENABLED(CONFIG_AUDIO_QGKI)
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED); wcd_mbhc_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
#endif /* CONFIG_AUDIO_QGKI */ #endif /* CONFIG_AUDIO_QGKI */
ret = extcon_set_state_sync(mbhc->extdev, EXTCON_MECHANICAL, 1);
} else if (plug_type == MBHC_PLUG_TYPE_HEADSET) { } else if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
if (mbhc->mbhc_cfg->enable_anc_mic_detect && if (mbhc->mbhc_cfg->enable_anc_mic_detect &&
mbhc->mbhc_fn->wcd_mbhc_detect_anc_plug_type) mbhc->mbhc_fn->wcd_mbhc_detect_anc_plug_type)
@@ -860,10 +887,12 @@ void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
* only report the mic line * only report the mic line
*/ */
wcd_mbhc_report_plug(mbhc, 1, jack_type); wcd_mbhc_report_plug(mbhc, 1, jack_type);
ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 1);
} else if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) { } else if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
if (mbhc->mbhc_cfg->detect_extn_cable) { if (mbhc->mbhc_cfg->detect_extn_cable) {
/* High impedance device found. Report as LINEOUT */ /* High impedance device found. Report as LINEOUT */
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 1);
pr_debug("%s: setup mic trigger for further detection\n", pr_debug("%s: setup mic trigger for further detection\n",
__func__); __func__);
@@ -883,6 +912,7 @@ void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
true); true);
} else { } else {
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 1);
} }
} else { } else {
WARN(1, "Unexpected current plug_type %d, plug_type %d\n", WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
@@ -930,6 +960,7 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
bool micbias1 = false; bool micbias1 = false;
struct snd_soc_component *component = mbhc->component; struct snd_soc_component *component = mbhc->component;
enum snd_jack_types jack_type; enum snd_jack_types jack_type;
int extdev_type = 0;
dev_dbg(component->dev, "%s: enter\n", __func__); dev_dbg(component->dev, "%s: enter\n", __func__);
WCD_MBHC_RSC_LOCK(mbhc); WCD_MBHC_RSC_LOCK(mbhc);
@@ -1017,12 +1048,16 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
switch (mbhc->current_plug) { switch (mbhc->current_plug) {
case MBHC_PLUG_TYPE_HEADPHONE: case MBHC_PLUG_TYPE_HEADPHONE:
jack_type = SND_JACK_HEADPHONE; jack_type = SND_JACK_HEADPHONE;
extdev_type = EXTCON_JACK_HEADPHONE;
break; break;
#if IS_ENABLED(CONFIG_AUDIO_QGKI)
case MBHC_PLUG_TYPE_GND_MIC_SWAP: case MBHC_PLUG_TYPE_GND_MIC_SWAP:
#if IS_ENABLED(CONFIG_AUDIO_QGKI)
jack_type = SND_JACK_UNSUPPORTED; jack_type = SND_JACK_UNSUPPORTED;
break; #else
jack_type = SND_JACK_HEADPHONE;
#endif /* CONFIG_AUDIO_QGKI */ #endif /* CONFIG_AUDIO_QGKI */
extdev_type = EXTCON_MECHANICAL;
break;
case MBHC_PLUG_TYPE_HEADSET: case MBHC_PLUG_TYPE_HEADSET:
/* make sure to turn off Rbias */ /* make sure to turn off Rbias */
if (mbhc->mbhc_cb->micb_internal) if (mbhc->mbhc_cb->micb_internal)
@@ -1031,12 +1066,14 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
/* Pulldown micbias */ /* Pulldown micbias */
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 1); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 1);
jack_type = SND_JACK_HEADSET; jack_type = SND_JACK_HEADSET;
extdev_type = EXTCON_JACK_MICROPHONE;
break; break;
case MBHC_PLUG_TYPE_HIGH_HPH: case MBHC_PLUG_TYPE_HIGH_HPH:
if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC) if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC)
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0);
mbhc->is_extn_cable = false; mbhc->is_extn_cable = false;
jack_type = SND_JACK_LINEOUT; jack_type = SND_JACK_LINEOUT;
extdev_type = EXTCON_JACK_LINE_OUT;
break; break;
default: default:
pr_info("%s: Invalid current plug: %d\n", pr_info("%s: Invalid current plug: %d\n",
@@ -1046,6 +1083,7 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
#else #else
jack_type = SND_JACK_HEADPHONE; jack_type = SND_JACK_HEADPHONE;
#endif /* CONFIG_AUDIO_QGKI */ #endif /* CONFIG_AUDIO_QGKI */
extdev_type = EXTCON_MECHANICAL;
break; break;
} }
wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false); wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false);
@@ -1054,6 +1092,7 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
mbhc->extn_cable_hph_rem = false; mbhc->extn_cable_hph_rem = false;
wcd_mbhc_report_plug(mbhc, 0, jack_type); wcd_mbhc_report_plug(mbhc, 0, jack_type);
extcon_set_state_sync(mbhc->extdev, extdev_type, 0);
if (mbhc->mbhc_cfg->enable_usbc_analog) { if (mbhc->mbhc_cfg->enable_usbc_analog) {
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0);
@@ -2010,11 +2049,26 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_component *component,
mbhc->intr_ids->hph_right_ocp); mbhc->intr_ids->hph_right_ocp);
goto err_hphr_ocp_irq; goto err_hphr_ocp_irq;
} }
if (!mbhc->extdev)
mbhc->extdev =
devm_extcon_dev_allocate(component->dev,
mbhc_ext_dev_supported_table);
if (IS_ERR(mbhc->extdev)) {
goto err_ext_dev;
ret = PTR_ERR(mbhc->extdev);
}
ret = devm_extcon_dev_register(component->dev, mbhc->extdev);
if (ret) {
pr_err("%s:audio registration failed\n", __func__);
goto err_ext_dev;
}
mbhc->deinit_in_progress = false; mbhc->deinit_in_progress = false;
pr_debug("%s: leave ret %d\n", __func__, ret); pr_debug("%s: leave ret %d\n", __func__, ret);
return ret; return ret;
err_ext_dev:
mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->hph_right_ocp, mbhc);
err_hphr_ocp_irq: err_hphr_ocp_irq:
mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->hph_left_ocp, mbhc); mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->hph_left_ocp, mbhc);
err_hphl_ocp_irq: err_hphl_ocp_irq:
@@ -2046,6 +2100,9 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
{ {
struct snd_soc_component *component = mbhc->component; struct snd_soc_component *component = mbhc->component;
if (mbhc->extdev)
devm_extcon_dev_unregister(component->dev, mbhc->extdev);
mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_sw_intr, mbhc); mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_sw_intr, mbhc);
mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_btn_press_intr, mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_btn_press_intr,
mbhc); mbhc);

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2021, The Linux Foundation. All rights reserved.
*/ */
#ifndef __WCD_MBHC_V2_H__ #ifndef __WCD_MBHC_V2_H__
#define __WCD_MBHC_V2_H__ #define __WCD_MBHC_V2_H__
@@ -7,6 +7,8 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/extcon.h>
#include <linux/extcon-provider.h>
#include "wcdcal-hwdep.h" #include "wcdcal-hwdep.h"
#include <sound/jack.h> #include <sound/jack.h>
@@ -621,6 +623,8 @@ struct wcd_mbhc {
bool force_linein; bool force_linein;
struct device_node *fsa_np; struct device_node *fsa_np;
struct notifier_block fsa_nb; struct notifier_block fsa_nb;
struct extcon_dev *extdev;
}; };
void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc, void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,