Loading sound/soc/codecs/wcd-mbhc-v2.c +120 −25 Original line number Diff line number Diff line Loading @@ -191,6 +191,43 @@ static void wcd_enable_curr_micbias(const struct wcd_mbhc *mbhc, pr_debug("%s: exit\n", __func__); } static const char *wcd_mbhc_get_event_string(int event) { switch (event) { case WCD_EVENT_PRE_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_OFF); case WCD_EVENT_POST_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_OFF); case WCD_EVENT_PRE_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_ON); case WCD_EVENT_POST_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_ON); case WCD_EVENT_PRE_HPHL_PA_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_ON); case WCD_EVENT_POST_HPHL_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHL_PA_OFF); case WCD_EVENT_PRE_HPHR_PA_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_ON); case WCD_EVENT_POST_HPHR_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHR_PA_OFF); case WCD_EVENT_PRE_HPHR_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_OFF); case WCD_EVENT_PRE_HPHL_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_OFF); case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_ON); case WCD_EVENT_PRE_DAPM_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_ON); case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); case WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF); case WCD_EVENT_INVALID: default: return WCD_MBHC_STRINGIFY(WCD_EVENT_INVALID); } } static int wcd_event_notify(struct notifier_block *self, unsigned long val, void *data) { Loading @@ -201,7 +238,8 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, bool micbias1 = false; u8 fsm_en; pr_debug("%s: event %d\n", __func__, event); pr_debug("%s: event %s (%d)\n", __func__, wcd_mbhc_get_event_string(event), event); if (mbhc->mbhc_cb->micbias_enable_status) { micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_2); Loading @@ -210,6 +248,11 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, } switch (event) { /* MICBIAS usage change */ case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: mbhc->is_hs_recording = true; pr_debug("%s: is_capture: %d\n", __func__, mbhc->is_hs_recording); break; case WCD_EVENT_POST_MICBIAS_2_ON: if (!mbhc->micbias_enable) goto out_micb_en; Loading @@ -233,7 +276,6 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, MBHC_COMMON_MICB_PRECHARGE, false); out_micb_en: mbhc->is_hs_recording = true; /* Disable current source if micbias enabled */ if (mbhc->mbhc_cb->mbhc_micbias_control) { WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); Loading @@ -241,18 +283,39 @@ out_micb_en: WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); } else { mbhc->is_hs_recording = true; wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); } /* configure cap settings properly when micbias is enabled */ if (mbhc->mbhc_cb->set_cap_mode) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true); break; case WCD_EVENT_PRE_MICBIAS_2_OFF: /* * Before MICBIAS_2 is turned off, if FSM is enabled, * make sure current source is enabled so as to detect * button press/release events */ if (mbhc->mbhc_cb->mbhc_micbias_control && !mbhc->micbias_enable) { WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); if (fsm_en) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); } break; /* MICBIAS usage change */ case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: mbhc->is_hs_recording = false; pr_debug("%s: is_capture: %d\n", __func__, mbhc->is_hs_recording); break; case WCD_EVENT_POST_MICBIAS_2_OFF: if (mbhc->mbhc_cb->set_auto_zeroing) mbhc->mbhc_cb->set_auto_zeroing(codec, false); if (mbhc->mbhc_cb->set_micbias_value) mbhc->mbhc_cb->set_micbias_value(codec); if (!mbhc->mbhc_cb->mbhc_micbias_control) mbhc->is_hs_recording = false; /* Enable PULL UP if PA's are enabled */ if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) || Loading @@ -264,12 +327,6 @@ out_micb_en: /* enable current source and disable mb, pullup*/ wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS); if (mbhc->mbhc_cb->mbhc_micbias_control) { WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); if (fsm_en) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); } /* configure cap settings properly when micbias is disabled */ if (mbhc->mbhc_cb->set_cap_mode) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false); Loading Loading @@ -480,8 +537,17 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, ~WCD_MBHC_JACK_BUTTON_MASK; } if (mbhc->micbias_enable) if (mbhc->micbias_enable) { if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control( mbhc->codec, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); mbhc->micbias_enable = false; } mbhc->hph_type = WCD_MBHC_HPH_NONE; mbhc->zl = mbhc->zr = 0; Loading @@ -504,8 +570,17 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, jack_type == SND_JACK_LINEOUT) && (mbhc->hph_status && mbhc->hph_status != jack_type)) { if (mbhc->micbias_enable) if (mbhc->micbias_enable) { if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control( mbhc->codec, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); mbhc->micbias_enable = false; } mbhc->hph_type = WCD_MBHC_HPH_NONE; mbhc->zl = mbhc->zr = 0; pr_debug("%s: Reporting removal (%x)\n", Loading Loading @@ -679,17 +754,29 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) { struct snd_soc_codec *codec = mbhc->codec; int delay = 0; int delay = 0, rc; bool ret = false; bool hs_comp_res; /* * Enable micbias if not already enabled * and disable current source if using micbias * Increase micbias to 2.7V to detect headsets with * threshold on microphone */ if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_ENABLE); else if (mbhc->mbhc_cb->mbhc_micbias_control && !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n", __func__); return false; } else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { rc = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec, MIC_BIAS_2, true); if (rc) { pr_err("%s: Micbias control for thr mic failed, rc: %d\n", __func__, rc); return false; } } wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); pr_debug("%s: special headset, start register writes\n", __func__); Loading Loading @@ -740,22 +827,29 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) if (mbhc->mbhc_cb->set_auto_zeroing) mbhc->mbhc_cb->set_auto_zeroing(codec, false); if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic && !mbhc->micbias_enable) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec, MIC_BIAS_2, false); pr_debug("%s: leave\n", __func__); pr_debug("%s: leave, micb_enable: %d\n", __func__, mbhc->micbias_enable); return ret; } static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc, enum wcd_mbhc_plug_type plug_type) { bool micbias2; micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_2); switch (plug_type) { case MBHC_PLUG_TYPE_HEADPHONE: WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); break; case MBHC_PLUG_TYPE_HEADSET: if (!mbhc->is_hs_recording) if (!mbhc->is_hs_recording && !micbias2) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); break; default: Loading Loading @@ -1031,9 +1125,10 @@ enable_supply: else wcd_enable_mbhc_supply(mbhc, plug_type); exit: if (mbhc->mbhc_cb->mbhc_micbias_control) if (mbhc->mbhc_cb->mbhc_micbias_control && !mbhc->micbias_enable) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_PULLUP_DISABLE); MICB_DISABLE); if (mbhc->mbhc_cb->micbias_enable_status) { micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_1); Loading Loading @@ -1065,7 +1160,7 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true); if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_PULLUP_ENABLE); mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_ENABLE); else wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); Loading sound/soc/codecs/wcd-mbhc-v2.h +8 −0 Original line number Diff line number Diff line Loading @@ -13,12 +13,15 @@ #define __WCD_MBHC_V2_H__ #include <linux/wait.h> #include <linux/stringify.h> #include "wcdcal-hwdep.h" #define TOMBAK_MBHC_NC 0 #define TOMBAK_MBHC_NO 1 #define WCD_MBHC_DEF_BUTTONS 8 #define WCD_MBHC_USLEEP_RANGE_MARGIN_US 100 #define WCD_MBHC_THR_HS_MICB_MV 2700 #define WCD_MBHC_STRINGIFY(s) __stringify(s) struct wcd_mbhc; enum wcd_mbhc_register_function { Loading Loading @@ -104,6 +107,10 @@ enum wcd_notify_event { WCD_EVENT_POST_MICBIAS_2_OFF, WCD_EVENT_PRE_MICBIAS_2_ON, WCD_EVENT_POST_MICBIAS_2_ON, WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF, WCD_EVENT_POST_DAPM_MICBIAS_2_OFF, WCD_EVENT_PRE_DAPM_MICBIAS_2_ON, WCD_EVENT_POST_DAPM_MICBIAS_2_ON, /* events for PA ON and OFF */ WCD_EVENT_PRE_HPHL_PA_ON, WCD_EVENT_POST_HPHL_PA_OFF, Loading Loading @@ -300,6 +307,7 @@ struct wcd_mbhc_cb { int (*mbhc_micbias_control)(struct snd_soc_codec *, int req); void (*mbhc_micb_ramp_control)(struct snd_soc_codec *, bool); bool (*extn_use_mb)(struct snd_soc_codec *); int (*mbhc_micb_ctrl_thr_mic)(struct snd_soc_codec *, int, bool); }; struct wcd_mbhc { Loading sound/soc/codecs/wcd9335.c +117 −10 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ #define CPE_FLL_CLK_150MHZ 150000000 #define WCD9335_REG_BITS 8 /* Convert from vout ctl to micbias voltage in mV */ #define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) static int cpe_debug_mode = 1; module_param(cpe_debug_mode, int, S_IRUGO | S_IWUSR | S_IWGRP); Loading Loading @@ -365,6 +368,7 @@ static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); static struct snd_soc_dai_driver tasha_dai[]; static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv); /* Hold instance to soundwire platform device */ struct tasha_swr_ctrl_data { Loading Loading @@ -746,7 +750,7 @@ static void tasha_mbhc_hph_l_pull_up_control(struct snd_soc_codec *codec, } static int tasha_micbias_control(struct snd_soc_codec *codec, int req) int req, bool is_dapm) { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); Loading Loading @@ -774,6 +778,10 @@ static int tasha_micbias_control(struct snd_soc_codec *codec, WCD_EVENT_POST_MICBIAS_2_ON, &tasha->mbhc); } if (is_dapm) blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_POST_DAPM_MICBIAS_2_ON, &tasha->mbhc); break; case MICB_DISABLE: tasha->micb_ref--; Loading @@ -781,12 +789,19 @@ static int tasha_micbias_control(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WCD9335_ANA_MICB2, 0xC0, 0x80); else if ((tasha->micb_ref == 0) && (tasha->pullup_ref == 0)) { blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_PRE_MICBIAS_2_OFF, &tasha->mbhc); snd_soc_update_bits(codec, WCD9335_ANA_MICB2, 0xC0, 0x00); blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_POST_MICBIAS_2_OFF, &tasha->mbhc); } if (is_dapm) blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_POST_DAPM_MICBIAS_2_OFF, &tasha->mbhc); break; }; Loading @@ -801,25 +816,25 @@ static int tasha_micbias_control(struct snd_soc_codec *codec, static int tasha_mbhc_request_micbias(struct snd_soc_codec *codec, int req) { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); int ret; /* * If micbias is requested, make sure that there * is vote to enable master bias * is vote to enable mclk */ if (req == MICB_ENABLE) wcd_resmgr_enable_master_bias(tasha->resmgr); tasha_cdc_mclk_enable(codec, true, false); tasha_micbias_control(codec, req); ret = tasha_micbias_control(codec, req, false); /* * Release vote for master bias while requesting for * Release vote for mclk while requesting for * micbias disable */ if (req == MICB_DISABLE) wcd_resmgr_disable_master_bias(tasha->resmgr); tasha_cdc_mclk_enable(codec, false, false); return 0; return ret; } static void tasha_mbhc_micb_ramp_control(struct snd_soc_codec *codec, Loading Loading @@ -857,6 +872,96 @@ static struct firmware_cal *tasha_get_hwdep_fw_cal(struct snd_soc_codec *codec, return hwdep_cal; } static int tasha_mbhc_micb_adjust_voltage(struct snd_soc_codec *codec, int req_volt, int micb_num) { int cur_vout_ctl, req_vout_ctl; int micb_reg, micb_val, micb_en; switch (micb_num) { case MIC_BIAS_1: micb_reg = WCD9335_ANA_MICB1; break; case MIC_BIAS_2: micb_reg = WCD9335_ANA_MICB2; break; case MIC_BIAS_3: micb_reg = WCD9335_ANA_MICB3; break; case MIC_BIAS_4: micb_reg = WCD9335_ANA_MICB4; break; default: return -EINVAL; } /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as * per requested value. If micbias is already enabled, then * to avoid slow micbias ramp-up or down enable pull-up * momentarily, change the micbias value and then re-enable * micbias. */ micb_val = snd_soc_read(codec, micb_reg); micb_en = (micb_val & 0xC0) >> 6; cur_vout_ctl = micb_val & 0x3F; req_vout_ctl = wcd9335_get_micb_vout_ctl_val(req_volt); if (IS_ERR_VALUE(req_vout_ctl)) return -EINVAL; if (cur_vout_ctl == req_vout_ctl) return 0; dev_dbg(codec->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n", __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl), req_volt, micb_en); if (micb_en == 0x1) snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80); snd_soc_update_bits(codec, micb_reg, 0x3F, req_vout_ctl); if (micb_en == 0x1) { snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40); /* * Add 2ms delay as per HW requirement after enabling * micbias */ usleep_range(2000, 2100); } return 0; } static int tasha_mbhc_micb_ctrl_threshold_mic(struct snd_soc_codec *codec, int micb_num, bool req_en) { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent); int rc, micb_mv; if (micb_num != MIC_BIAS_2) return -EINVAL; /* * If device tree micbias level is already above the minimum * voltage needed to detect threshold microphone, then do * not change the micbias, just return. */ if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) return 0; micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv; mutex_lock(&tasha->micb_lock); rc = tasha_mbhc_micb_adjust_voltage(codec, micb_mv, MIC_BIAS_2); mutex_unlock(&tasha->micb_lock); return rc; } static const struct wcd_mbhc_cb mbhc_cb = { .request_irq = tasha_mbhc_request_irq, .irq_control = tasha_mbhc_irq_control, Loading @@ -873,6 +978,7 @@ static const struct wcd_mbhc_cb mbhc_cb = { .mbhc_micbias_control = tasha_mbhc_request_micbias, .mbhc_micb_ramp_control = tasha_mbhc_micb_ramp_control, .get_hwdep_fw_cal = tasha_get_hwdep_fw_cal, .mbhc_micb_ctrl_thr_mic = tasha_mbhc_micb_ctrl_threshold_mic, }; static int tasha_get_iir_enable_audio_mixer( Loading Loading @@ -2988,7 +3094,7 @@ static int tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, * and enable requests */ if (micb_reg == WCD9335_ANA_MICB2) tasha_micbias_control(codec, MICB_ENABLE); tasha_micbias_control(codec, MICB_ENABLE, true); else snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40); break; Loading @@ -2998,7 +3104,7 @@ static int tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: if (micb_reg == WCD9335_ANA_MICB2) tasha_micbias_control(codec, MICB_DISABLE); tasha_micbias_control(codec, MICB_DISABLE, true); else snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00); break; Loading Loading @@ -7269,6 +7375,7 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val[] = { {WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, {WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03}, {WCD9335_MICB2_TEST_CTL_2, 0x07, 0x01}, }; static void tasha_update_reg_reset_values(struct snd_soc_codec *codec) Loading Loading
sound/soc/codecs/wcd-mbhc-v2.c +120 −25 Original line number Diff line number Diff line Loading @@ -191,6 +191,43 @@ static void wcd_enable_curr_micbias(const struct wcd_mbhc *mbhc, pr_debug("%s: exit\n", __func__); } static const char *wcd_mbhc_get_event_string(int event) { switch (event) { case WCD_EVENT_PRE_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_OFF); case WCD_EVENT_POST_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_OFF); case WCD_EVENT_PRE_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_ON); case WCD_EVENT_POST_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_ON); case WCD_EVENT_PRE_HPHL_PA_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_ON); case WCD_EVENT_POST_HPHL_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHL_PA_OFF); case WCD_EVENT_PRE_HPHR_PA_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_ON); case WCD_EVENT_POST_HPHR_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHR_PA_OFF); case WCD_EVENT_PRE_HPHR_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_OFF); case WCD_EVENT_PRE_HPHL_PA_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_OFF); case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_ON); case WCD_EVENT_PRE_DAPM_MICBIAS_2_ON: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_ON); case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); case WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF: return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF); case WCD_EVENT_INVALID: default: return WCD_MBHC_STRINGIFY(WCD_EVENT_INVALID); } } static int wcd_event_notify(struct notifier_block *self, unsigned long val, void *data) { Loading @@ -201,7 +238,8 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, bool micbias1 = false; u8 fsm_en; pr_debug("%s: event %d\n", __func__, event); pr_debug("%s: event %s (%d)\n", __func__, wcd_mbhc_get_event_string(event), event); if (mbhc->mbhc_cb->micbias_enable_status) { micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_2); Loading @@ -210,6 +248,11 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, } switch (event) { /* MICBIAS usage change */ case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: mbhc->is_hs_recording = true; pr_debug("%s: is_capture: %d\n", __func__, mbhc->is_hs_recording); break; case WCD_EVENT_POST_MICBIAS_2_ON: if (!mbhc->micbias_enable) goto out_micb_en; Loading @@ -233,7 +276,6 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, MBHC_COMMON_MICB_PRECHARGE, false); out_micb_en: mbhc->is_hs_recording = true; /* Disable current source if micbias enabled */ if (mbhc->mbhc_cb->mbhc_micbias_control) { WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); Loading @@ -241,18 +283,39 @@ out_micb_en: WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); } else { mbhc->is_hs_recording = true; wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); } /* configure cap settings properly when micbias is enabled */ if (mbhc->mbhc_cb->set_cap_mode) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true); break; case WCD_EVENT_PRE_MICBIAS_2_OFF: /* * Before MICBIAS_2 is turned off, if FSM is enabled, * make sure current source is enabled so as to detect * button press/release events */ if (mbhc->mbhc_cb->mbhc_micbias_control && !mbhc->micbias_enable) { WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); if (fsm_en) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); } break; /* MICBIAS usage change */ case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: mbhc->is_hs_recording = false; pr_debug("%s: is_capture: %d\n", __func__, mbhc->is_hs_recording); break; case WCD_EVENT_POST_MICBIAS_2_OFF: if (mbhc->mbhc_cb->set_auto_zeroing) mbhc->mbhc_cb->set_auto_zeroing(codec, false); if (mbhc->mbhc_cb->set_micbias_value) mbhc->mbhc_cb->set_micbias_value(codec); if (!mbhc->mbhc_cb->mbhc_micbias_control) mbhc->is_hs_recording = false; /* Enable PULL UP if PA's are enabled */ if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) || Loading @@ -264,12 +327,6 @@ out_micb_en: /* enable current source and disable mb, pullup*/ wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS); if (mbhc->mbhc_cb->mbhc_micbias_control) { WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); if (fsm_en) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); } /* configure cap settings properly when micbias is disabled */ if (mbhc->mbhc_cb->set_cap_mode) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false); Loading Loading @@ -480,8 +537,17 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, ~WCD_MBHC_JACK_BUTTON_MASK; } if (mbhc->micbias_enable) if (mbhc->micbias_enable) { if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control( mbhc->codec, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); mbhc->micbias_enable = false; } mbhc->hph_type = WCD_MBHC_HPH_NONE; mbhc->zl = mbhc->zr = 0; Loading @@ -504,8 +570,17 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, jack_type == SND_JACK_LINEOUT) && (mbhc->hph_status && mbhc->hph_status != jack_type)) { if (mbhc->micbias_enable) if (mbhc->micbias_enable) { if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control( mbhc->codec, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); mbhc->micbias_enable = false; } mbhc->hph_type = WCD_MBHC_HPH_NONE; mbhc->zl = mbhc->zr = 0; pr_debug("%s: Reporting removal (%x)\n", Loading Loading @@ -679,17 +754,29 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) { struct snd_soc_codec *codec = mbhc->codec; int delay = 0; int delay = 0, rc; bool ret = false; bool hs_comp_res; /* * Enable micbias if not already enabled * and disable current source if using micbias * Increase micbias to 2.7V to detect headsets with * threshold on microphone */ if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_ENABLE); else if (mbhc->mbhc_cb->mbhc_micbias_control && !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n", __func__); return false; } else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { rc = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec, MIC_BIAS_2, true); if (rc) { pr_err("%s: Micbias control for thr mic failed, rc: %d\n", __func__, rc); return false; } } wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); pr_debug("%s: special headset, start register writes\n", __func__); Loading Loading @@ -740,22 +827,29 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) if (mbhc->mbhc_cb->set_auto_zeroing) mbhc->mbhc_cb->set_auto_zeroing(codec, false); if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic && !mbhc->micbias_enable) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec, MIC_BIAS_2, false); pr_debug("%s: leave\n", __func__); pr_debug("%s: leave, micb_enable: %d\n", __func__, mbhc->micbias_enable); return ret; } static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc, enum wcd_mbhc_plug_type plug_type) { bool micbias2; micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_2); switch (plug_type) { case MBHC_PLUG_TYPE_HEADPHONE: WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); break; case MBHC_PLUG_TYPE_HEADSET: if (!mbhc->is_hs_recording) if (!mbhc->is_hs_recording && !micbias2) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); break; default: Loading Loading @@ -1031,9 +1125,10 @@ enable_supply: else wcd_enable_mbhc_supply(mbhc, plug_type); exit: if (mbhc->mbhc_cb->mbhc_micbias_control) if (mbhc->mbhc_cb->mbhc_micbias_control && !mbhc->micbias_enable) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_PULLUP_DISABLE); MICB_DISABLE); if (mbhc->mbhc_cb->micbias_enable_status) { micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_1); Loading Loading @@ -1065,7 +1160,7 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true); if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_PULLUP_ENABLE); mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_ENABLE); else wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); Loading
sound/soc/codecs/wcd-mbhc-v2.h +8 −0 Original line number Diff line number Diff line Loading @@ -13,12 +13,15 @@ #define __WCD_MBHC_V2_H__ #include <linux/wait.h> #include <linux/stringify.h> #include "wcdcal-hwdep.h" #define TOMBAK_MBHC_NC 0 #define TOMBAK_MBHC_NO 1 #define WCD_MBHC_DEF_BUTTONS 8 #define WCD_MBHC_USLEEP_RANGE_MARGIN_US 100 #define WCD_MBHC_THR_HS_MICB_MV 2700 #define WCD_MBHC_STRINGIFY(s) __stringify(s) struct wcd_mbhc; enum wcd_mbhc_register_function { Loading Loading @@ -104,6 +107,10 @@ enum wcd_notify_event { WCD_EVENT_POST_MICBIAS_2_OFF, WCD_EVENT_PRE_MICBIAS_2_ON, WCD_EVENT_POST_MICBIAS_2_ON, WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF, WCD_EVENT_POST_DAPM_MICBIAS_2_OFF, WCD_EVENT_PRE_DAPM_MICBIAS_2_ON, WCD_EVENT_POST_DAPM_MICBIAS_2_ON, /* events for PA ON and OFF */ WCD_EVENT_PRE_HPHL_PA_ON, WCD_EVENT_POST_HPHL_PA_OFF, Loading Loading @@ -300,6 +307,7 @@ struct wcd_mbhc_cb { int (*mbhc_micbias_control)(struct snd_soc_codec *, int req); void (*mbhc_micb_ramp_control)(struct snd_soc_codec *, bool); bool (*extn_use_mb)(struct snd_soc_codec *); int (*mbhc_micb_ctrl_thr_mic)(struct snd_soc_codec *, int, bool); }; struct wcd_mbhc { Loading
sound/soc/codecs/wcd9335.c +117 −10 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ #define CPE_FLL_CLK_150MHZ 150000000 #define WCD9335_REG_BITS 8 /* Convert from vout ctl to micbias voltage in mV */ #define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) static int cpe_debug_mode = 1; module_param(cpe_debug_mode, int, S_IRUGO | S_IWUSR | S_IWGRP); Loading Loading @@ -365,6 +368,7 @@ static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); static struct snd_soc_dai_driver tasha_dai[]; static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv); /* Hold instance to soundwire platform device */ struct tasha_swr_ctrl_data { Loading Loading @@ -746,7 +750,7 @@ static void tasha_mbhc_hph_l_pull_up_control(struct snd_soc_codec *codec, } static int tasha_micbias_control(struct snd_soc_codec *codec, int req) int req, bool is_dapm) { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); Loading Loading @@ -774,6 +778,10 @@ static int tasha_micbias_control(struct snd_soc_codec *codec, WCD_EVENT_POST_MICBIAS_2_ON, &tasha->mbhc); } if (is_dapm) blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_POST_DAPM_MICBIAS_2_ON, &tasha->mbhc); break; case MICB_DISABLE: tasha->micb_ref--; Loading @@ -781,12 +789,19 @@ static int tasha_micbias_control(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WCD9335_ANA_MICB2, 0xC0, 0x80); else if ((tasha->micb_ref == 0) && (tasha->pullup_ref == 0)) { blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_PRE_MICBIAS_2_OFF, &tasha->mbhc); snd_soc_update_bits(codec, WCD9335_ANA_MICB2, 0xC0, 0x00); blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_POST_MICBIAS_2_OFF, &tasha->mbhc); } if (is_dapm) blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_POST_DAPM_MICBIAS_2_OFF, &tasha->mbhc); break; }; Loading @@ -801,25 +816,25 @@ static int tasha_micbias_control(struct snd_soc_codec *codec, static int tasha_mbhc_request_micbias(struct snd_soc_codec *codec, int req) { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); int ret; /* * If micbias is requested, make sure that there * is vote to enable master bias * is vote to enable mclk */ if (req == MICB_ENABLE) wcd_resmgr_enable_master_bias(tasha->resmgr); tasha_cdc_mclk_enable(codec, true, false); tasha_micbias_control(codec, req); ret = tasha_micbias_control(codec, req, false); /* * Release vote for master bias while requesting for * Release vote for mclk while requesting for * micbias disable */ if (req == MICB_DISABLE) wcd_resmgr_disable_master_bias(tasha->resmgr); tasha_cdc_mclk_enable(codec, false, false); return 0; return ret; } static void tasha_mbhc_micb_ramp_control(struct snd_soc_codec *codec, Loading Loading @@ -857,6 +872,96 @@ static struct firmware_cal *tasha_get_hwdep_fw_cal(struct snd_soc_codec *codec, return hwdep_cal; } static int tasha_mbhc_micb_adjust_voltage(struct snd_soc_codec *codec, int req_volt, int micb_num) { int cur_vout_ctl, req_vout_ctl; int micb_reg, micb_val, micb_en; switch (micb_num) { case MIC_BIAS_1: micb_reg = WCD9335_ANA_MICB1; break; case MIC_BIAS_2: micb_reg = WCD9335_ANA_MICB2; break; case MIC_BIAS_3: micb_reg = WCD9335_ANA_MICB3; break; case MIC_BIAS_4: micb_reg = WCD9335_ANA_MICB4; break; default: return -EINVAL; } /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as * per requested value. If micbias is already enabled, then * to avoid slow micbias ramp-up or down enable pull-up * momentarily, change the micbias value and then re-enable * micbias. */ micb_val = snd_soc_read(codec, micb_reg); micb_en = (micb_val & 0xC0) >> 6; cur_vout_ctl = micb_val & 0x3F; req_vout_ctl = wcd9335_get_micb_vout_ctl_val(req_volt); if (IS_ERR_VALUE(req_vout_ctl)) return -EINVAL; if (cur_vout_ctl == req_vout_ctl) return 0; dev_dbg(codec->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n", __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl), req_volt, micb_en); if (micb_en == 0x1) snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80); snd_soc_update_bits(codec, micb_reg, 0x3F, req_vout_ctl); if (micb_en == 0x1) { snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40); /* * Add 2ms delay as per HW requirement after enabling * micbias */ usleep_range(2000, 2100); } return 0; } static int tasha_mbhc_micb_ctrl_threshold_mic(struct snd_soc_codec *codec, int micb_num, bool req_en) { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent); int rc, micb_mv; if (micb_num != MIC_BIAS_2) return -EINVAL; /* * If device tree micbias level is already above the minimum * voltage needed to detect threshold microphone, then do * not change the micbias, just return. */ if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) return 0; micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv; mutex_lock(&tasha->micb_lock); rc = tasha_mbhc_micb_adjust_voltage(codec, micb_mv, MIC_BIAS_2); mutex_unlock(&tasha->micb_lock); return rc; } static const struct wcd_mbhc_cb mbhc_cb = { .request_irq = tasha_mbhc_request_irq, .irq_control = tasha_mbhc_irq_control, Loading @@ -873,6 +978,7 @@ static const struct wcd_mbhc_cb mbhc_cb = { .mbhc_micbias_control = tasha_mbhc_request_micbias, .mbhc_micb_ramp_control = tasha_mbhc_micb_ramp_control, .get_hwdep_fw_cal = tasha_get_hwdep_fw_cal, .mbhc_micb_ctrl_thr_mic = tasha_mbhc_micb_ctrl_threshold_mic, }; static int tasha_get_iir_enable_audio_mixer( Loading Loading @@ -2988,7 +3094,7 @@ static int tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, * and enable requests */ if (micb_reg == WCD9335_ANA_MICB2) tasha_micbias_control(codec, MICB_ENABLE); tasha_micbias_control(codec, MICB_ENABLE, true); else snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40); break; Loading @@ -2998,7 +3104,7 @@ static int tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: if (micb_reg == WCD9335_ANA_MICB2) tasha_micbias_control(codec, MICB_DISABLE); tasha_micbias_control(codec, MICB_DISABLE, true); else snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00); break; Loading Loading @@ -7269,6 +7375,7 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val[] = { {WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, {WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03}, {WCD9335_MICB2_TEST_CTL_2, 0x07, 0x01}, }; static void tasha_update_reg_reset_values(struct snd_soc_codec *codec) Loading