耳机插入后中断相应,在wcd_mbhc_report_plug上报的时候可以读取阻抗动态,动态的提高驱动能力。
static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
enum snd_jack_types jack_type)
{
struct snd_soc_codec *codec = mbhc->codec;
bool is_pa_on = false;
WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
pr_debug("%s: enter insertion %d hph_status %x\n",
__func__, insertion, mbhc->hph_status);
if (!insertion) {
/* Report removal */
mbhc->hph_status &= ~jack_type;
/*
* cancel possibly scheduled btn work and
* report release if we reported button press
*/
if (wcd_cancel_btn_work(mbhc)) {
pr_debug("%s: button press is canceled\n", __func__);
} else if (mbhc->buttons_pressed) {
pr_debug("%s: release of button press%d\n",
__func__, jack_type);
wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, 0,
mbhc->buttons_pressed);
mbhc->buttons_pressed &=
~WCD_MBHC_JACK_BUTTON_MASK;
}
if (mbhc->micbias_enable) {
if (mbhc->mbhc_cb->mbhc_micbias_control)
mbhc->mbhc_cb->mbhc_micbias_control(
codec, MIC_BIAS_2,
MICB_DISABLE);
if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
codec,
MIC_BIAS_2, false);
if (mbhc->mbhc_cb->set_micbias_value) {
mbhc->mbhc_cb->set_micbias_value(codec);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
}
mbhc->micbias_enable = false;
}
mbhc->hph_type = WCD_MBHC_HPH_NONE;
mbhc->zl = mbhc->zr = 0;
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD_MBHC_JACK_MASK);
wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
gpio_set_value_cansleep(us_eu_pull_gpio, US_EU_PULL_DOWN);
} else {
/*
* Report removal of current jack type.
* Headphone to headset shouldn't report headphone
* removal.
*/
if (mbhc->mbhc_cfg->detect_extn_cable &&
(mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH ||
jack_type == SND_JACK_LINEOUT) &&
(mbhc->hph_status && mbhc->hph_status != jack_type)) {
if (mbhc->micbias_enable &&
mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
if (mbhc->mbhc_cb->mbhc_micbias_control)
mbhc->mbhc_cb->mbhc_micbias_control(
codec, MIC_BIAS_2,
MICB_DISABLE);
if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
codec,
MIC_BIAS_2, false);
if (mbhc->mbhc_cb->set_micbias_value) {
mbhc->mbhc_cb->set_micbias_value(
codec);
WCD_MBHC_REG_UPDATE_BITS(
WCD_MBHC_MICB_CTRL, 0);
}
mbhc->micbias_enable = false;
}
mbhc->hph_type = WCD_MBHC_HPH_NONE;
mbhc->zl = mbhc->zr = 0;
pr_debug("%s: Reporting removal (%x)\n",
__func__, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
0, WCD_MBHC_JACK_MASK);
if (mbhc->hph_status == SND_JACK_LINEOUT) {
pr_debug("%s: Enable micbias\n", __func__);
/* Disable current source and enable micbias */
wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
pr_debug("%s: set up elec removal detection\n",
__func__);
WCD_MBHC_REG_UPDATE_BITS(
WCD_MBHC_ELECT_DETECTION_TYPE,
0);
usleep_range(200, 210);
wcd_mbhc_hs_elec_irq(mbhc,
WCD_MBHC_ELEC_HS_REM,
true);
}
mbhc->hph_status &= ~(SND_JACK_HEADSET |
SND_JACK_LINEOUT |
SND_JACK_ANC_HEADPHONE |
SND_JACK_UNSUPPORTED);
}
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
jack_type == SND_JACK_HEADPHONE)
mbhc->hph_status &= ~SND_JACK_HEADSET;
/* Report insertion */
if (jack_type == SND_JACK_HEADPHONE)
mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
else if (jack_type == SND_JACK_UNSUPPORTED)
mbhc->current_plug = MBHC_PLUG_TYPE_GND_MIC_SWAP;
else if (jack_type == SND_JACK_HEADSET) {
mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
mbhc->jiffies_atreport = jiffies;
} else if (jack_type == SND_JACK_LINEOUT) {
mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
} else if (jack_type == SND_JACK_ANC_HEADPHONE)
mbhc->current_plug = MBHC_PLUG_TYPE_ANC_HEADPHONE;
if (mbhc->mbhc_cb->hph_pa_on_status)
is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(codec);
if (mbhc->impedance_detect &&
mbhc->mbhc_cb->compute_impedance &&
(mbhc->mbhc_cfg->linein_th != 0) &&
(!is_pa_on)) {
mbhc->mbhc_cb->compute_impedance(mbhc,
&mbhc->zl, &mbhc->zr);
if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
mbhc->zl < MAX_IMPED) &&
(mbhc->zr > mbhc->mbhc_cfg->linein_th &&
mbhc->zr < MAX_IMPED) &&
(jack_type == SND_JACK_HEADPHONE)) {
jack_type = SND_JACK_LINEOUT;
mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
if (mbhc->hph_status) {
mbhc->hph_status &= ~(SND_JACK_HEADSET |
SND_JACK_LINEOUT |
SND_JACK_UNSUPPORTED);
wcd_mbhc_jack_report(mbhc,
&mbhc->headset_jack,
mbhc->hph_status,
WCD_MBHC_JACK_MASK);
}
pr_debug("%s: Marking jack type as SND_JACK_LINEOUT\n",
__func__);
}
}
mbhc->hph_status |= jack_type;
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
(mbhc->hph_status | SND_JACK_MECHANICAL),
WCD_MBHC_JACK_MASK);
wcd_mbhc_clr_and_turnon_hph_padac(mbhc);
}
pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
}
compute_impedance
static const struct wcd_mbhc_cb mbhc_cb = {
.enable_mb_source = msm8x16_wcd_enable_ext_mb_source,
.trim_btn_reg = msm8x16_trim_btn_reg,
.compute_impedance = msm8x16_wcd_mbhc_calc_impedance,
.set_micbias_value = msm8x16_wcd_set_micb_v,
.set_auto_zeroing = msm8x16_wcd_set_auto_zeroing,
.get_hwdep_fw_cal = msm8x16_wcd_get_hwdep_fw_cal,
.set_cap_mode = msm8x16_wcd_configure_cap,
.register_notifier = msm8x16_register_notifier,
.request_irq = msm8x16_wcd_request_irq,
.irq_control = wcd9xxx_spmi_irq_control,
.free_irq = msm8x16_wcd_free_irq,
.clk_setup = msm8x16_mbhc_clk_setup,
.map_btn_code_to_num = msm8x16_mbhc_map_btn_code_to_num,
.lock_sleep = msm8x16_spmi_lock_sleep,
.micbias_enable_status = msm8x16_wcd_micb_en_status,
.mbhc_bias = msm8x16_wcd_enable_master_bias,
.mbhc_common_micb_ctrl = msm8x16_wcd_mbhc_common_micb_ctrl,
.micb_internal = msm8x16_wcd_mbhc_internal_micbias_ctrl,
.hph_pa_on_status = msm8x16_wcd_mbhc_hph_pa_on_status,
.set_btn_thr = msm8x16_wcd_mbhc_program_btn_thr,
.extn_use_mb = msm8x16_wcd_use_mb,
};