Loading sound/soc/codecs/msm8x16-wcd.c +9 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include <sound/tlv.h> #include <soc/qcom/subsystem_notif.h> #include "msm8x16-wcd.h" #include "wcd-mbhc-v2.h" #include "msm8916-wcd-irq.h" #include "msm8x16_wcd_registers.h" #include "../msm/qdsp6v2/q6core.h" Loading Loading @@ -2087,6 +2088,7 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event); Loading Loading @@ -2129,6 +2131,13 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, } break; case SND_SOC_DAPM_POST_PMD: if (w->shift == 5) { clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &msm8x16_wcd->mbhc.hph_pa_dac_state); } else if (w->shift == 4) { clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &msm8x16_wcd->mbhc.hph_pa_dac_state); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_NCP_FBCTRL, 0x20, 0x00); usleep_range(4000, 4100); Loading sound/soc/codecs/wcd-mbhc-v2.c +63 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,67 @@ static void hphlocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status) mbhc->intr_ids->hph_left_ocp); } static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc) { bool pa_turned_on = false; u8 wg_time; struct snd_soc_codec *codec = mbhc->codec; wg_time = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME); wg_time += 1; if (test_and_clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state)) { pr_debug("%s: HPHR clear flag and enable PA\n", __func__); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x10, 0x10); pa_turned_on = true; } if (test_and_clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state)) { pr_debug("%s: HPHL clear flag and enable PA\n", __func__); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x20, 0x20); pa_turned_on = true; } if (pa_turned_on) { pr_debug("%s: PA was turned off by MBHC and not by DAPM\n", __func__); usleep_range(wg_time * 1000, wg_time * 1000 + 50); } } static bool wcd_mbhc_is_hph_pa_on(struct snd_soc_codec *codec) { u8 hph_reg_val = 0; hph_reg_val = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN); return (hph_reg_val & 0x30) ? true : false; } static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc) { u8 wg_time; struct snd_soc_codec *codec = mbhc->codec; wg_time = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME); wg_time += 1; /* If headphone PA is on, check if userspace receives * removal event to sync-up PA's state */ if (wcd_mbhc_is_hph_pa_on(codec)) { pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__); set_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state); set_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state); } else { pr_debug("%s PA is off\n", __func__); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x30, 0x00); usleep_range(wg_time * 1000, wg_time * 1000 + 50); } static void wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) { Loading Loading @@ -300,6 +361,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, 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 = PLUG_TYPE_NONE; Loading Loading @@ -340,6 +402,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, jack_type, mbhc->hph_status); wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status, WCD_MBHC_JACK_MASK); wcd_mbhc_clr_and_turnon_hph_padac(mbhc); } pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status); } Loading sound/soc/codecs/wcd-mbhc-v2.h +8 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,11 @@ enum wcd_mbhc_plug_type { PLUG_TYPE_GND_MIC_SWAP, }; enum pa_dac_ack_flags { WCD_MBHC_HPHL_PA_OFF_ACK = 0, WCD_MBHC_HPHR_PA_OFF_ACK, }; struct wcd_mbhc_config { bool read_fw_bin; void *calibration; Loading Loading @@ -60,6 +65,9 @@ struct wcd_mbhc { struct snd_soc_codec *codec; /* track PA/DAC state to sync with userspace */ unsigned long hph_pa_dac_state; /* impedance of hphl and hphr */ uint32_t zl, zr; bool impedance_detect; Loading Loading
sound/soc/codecs/msm8x16-wcd.c +9 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include <sound/tlv.h> #include <soc/qcom/subsystem_notif.h> #include "msm8x16-wcd.h" #include "wcd-mbhc-v2.h" #include "msm8916-wcd-irq.h" #include "msm8x16_wcd_registers.h" #include "../msm/qdsp6v2/q6core.h" Loading Loading @@ -2087,6 +2088,7 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event); Loading Loading @@ -2129,6 +2131,13 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, } break; case SND_SOC_DAPM_POST_PMD: if (w->shift == 5) { clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &msm8x16_wcd->mbhc.hph_pa_dac_state); } else if (w->shift == 4) { clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &msm8x16_wcd->mbhc.hph_pa_dac_state); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_NCP_FBCTRL, 0x20, 0x00); usleep_range(4000, 4100); Loading
sound/soc/codecs/wcd-mbhc-v2.c +63 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,67 @@ static void hphlocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status) mbhc->intr_ids->hph_left_ocp); } static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc) { bool pa_turned_on = false; u8 wg_time; struct snd_soc_codec *codec = mbhc->codec; wg_time = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME); wg_time += 1; if (test_and_clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state)) { pr_debug("%s: HPHR clear flag and enable PA\n", __func__); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x10, 0x10); pa_turned_on = true; } if (test_and_clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state)) { pr_debug("%s: HPHL clear flag and enable PA\n", __func__); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x20, 0x20); pa_turned_on = true; } if (pa_turned_on) { pr_debug("%s: PA was turned off by MBHC and not by DAPM\n", __func__); usleep_range(wg_time * 1000, wg_time * 1000 + 50); } } static bool wcd_mbhc_is_hph_pa_on(struct snd_soc_codec *codec) { u8 hph_reg_val = 0; hph_reg_val = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN); return (hph_reg_val & 0x30) ? true : false; } static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc) { u8 wg_time; struct snd_soc_codec *codec = mbhc->codec; wg_time = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME); wg_time += 1; /* If headphone PA is on, check if userspace receives * removal event to sync-up PA's state */ if (wcd_mbhc_is_hph_pa_on(codec)) { pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__); set_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state); set_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state); } else { pr_debug("%s PA is off\n", __func__); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x30, 0x00); usleep_range(wg_time * 1000, wg_time * 1000 + 50); } static void wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) { Loading Loading @@ -300,6 +361,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, 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 = PLUG_TYPE_NONE; Loading Loading @@ -340,6 +402,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, jack_type, mbhc->hph_status); wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status, WCD_MBHC_JACK_MASK); wcd_mbhc_clr_and_turnon_hph_padac(mbhc); } pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status); } Loading
sound/soc/codecs/wcd-mbhc-v2.h +8 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,11 @@ enum wcd_mbhc_plug_type { PLUG_TYPE_GND_MIC_SWAP, }; enum pa_dac_ack_flags { WCD_MBHC_HPHL_PA_OFF_ACK = 0, WCD_MBHC_HPHR_PA_OFF_ACK, }; struct wcd_mbhc_config { bool read_fw_bin; void *calibration; Loading Loading @@ -60,6 +65,9 @@ struct wcd_mbhc { struct snd_soc_codec *codec; /* track PA/DAC state to sync with userspace */ unsigned long hph_pa_dac_state; /* impedance of hphl and hphr */ uint32_t zl, zr; bool impedance_detect; Loading