diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index a2a0105a28e7..c3ed33f00d6b 100755 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -335,6 +335,7 @@ enum { AIF4_SWITCH_VALUE, AUDIO_NOMINAL, CPE_NOMINAL, + HPH_PA_DELAY, }; enum { @@ -764,6 +765,8 @@ struct tasha_priv { struct hpf_work tx_hpf_work[TASHA_NUM_DECIMATORS]; struct tx_mute_work tx_mute_dwork[TASHA_NUM_DECIMATORS]; struct mutex codec_mutex; + int hph_l_gain; + int hph_r_gain; }; static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec, @@ -3526,22 +3529,80 @@ err: return ret; } +static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha, + int mode, int event) +{ + u8 scale_val = 0; + + if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) + return; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (mode) { + case CLS_H_HIFI: + scale_val = 0x3; + break; + case CLS_H_LOHIFI: + scale_val = 0x1; + break; + } + break; + case SND_SOC_DAPM_PRE_PMD: + scale_val = 0x6; + break; + } + + if (scale_val) + snd_soc_update_bits(tasha->codec, WCD9335_HPH_PA_CTL1, 0x0E, + scale_val << 1); + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (tasha->comp_enabled[COMPANDER_1] || + tasha->comp_enabled[COMPANDER_2]) { + snd_soc_update_bits(tasha->codec, WCD9335_HPH_L_EN, + 0x20, 0x00); + snd_soc_update_bits(tasha->codec, WCD9335_HPH_R_EN, + 0x20, 0x00); + snd_soc_update_bits(tasha->codec, WCD9335_HPH_AUTO_CHOP, + 0x20, 0x20); + } + snd_soc_update_bits(tasha->codec, WCD9335_HPH_L_EN, 0x1F, + tasha->hph_l_gain); + snd_soc_update_bits(tasha->codec, WCD9335_HPH_R_EN, 0x1F, + tasha->hph_r_gain); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(tasha->codec, WCD9335_HPH_AUTO_CHOP, 0x20, + 0x00); + } +} + static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + int hph_mode = tasha->hph_mode; int ret = 0; dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + set_bit(HPH_PA_DELAY, &tasha->status_mask); + break; case SND_SOC_DAPM_POST_PMU: - /* 5ms sleep is required after PA is enabled as per + /* + * 7ms sleep is required after PA is enabled as per * HW requirement */ - usleep_range(5000, 5500); + if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) { + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tasha->status_mask); + } + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_CTL, 0x10, 0x00); /* Remove mix path mute if it is enabled */ @@ -3555,6 +3616,7 @@ static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_PRE_HPHR_PA_OFF, &tasha->mbhc); + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); break; case SND_SOC_DAPM_POST_PMD: /* 5ms sleep is required after PA is disabled as per @@ -3582,16 +3644,26 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + int hph_mode = tasha->hph_mode; int ret = 0; dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + set_bit(HPH_PA_DELAY, &tasha->status_mask); + break; case SND_SOC_DAPM_POST_PMU: - /* 5ms sleep is required after PA is enabled as per + /* + * 7ms sleep is required after PA is enabled as per * HW requirement */ - usleep_range(5000, 5500); + if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) { + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tasha->status_mask); + } + + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CTL, 0x10, 0x00); /* Remove mix path mute if it is enabled */ @@ -3605,6 +3677,7 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_PRE_HPHL_PA_OFF, &tasha->mbhc); + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); break; case SND_SOC_DAPM_POST_PMD: /* 5ms sleep is required after PA is disabled as per @@ -3734,8 +3807,43 @@ static int tasha_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, return ret; } +static void tasha_codec_hph_mode_gain_opt(struct snd_soc_codec *codec, + u8 gain) +{ + struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + u8 hph_l_en, hph_r_en; + u8 l_val, r_val; + u8 hph_pa_status; + bool is_hphl_pa, is_hphr_pa; + + hph_pa_status = snd_soc_read(codec, WCD9335_ANA_HPH); + is_hphl_pa = hph_pa_status >> 7; + is_hphr_pa = (hph_pa_status & 0x40) >> 6; + + hph_l_en = snd_soc_read(codec, WCD9335_HPH_L_EN); + hph_r_en = snd_soc_read(codec, WCD9335_HPH_R_EN); + + l_val = (hph_l_en & 0xC0) | 0x20 | gain; + r_val = (hph_r_en & 0xC0) | 0x20 | gain; + + /* + * Set HPH_L & HPH_R gain source selection to REGISTER + * for better click and pop only if corresponding PAs are + * not enabled. Also cache the values of the HPHL/R + * PA gains to be applied after PAs are enabled + */ + if ((l_val != hph_l_en) && !is_hphl_pa) { + snd_soc_write(codec, WCD9335_HPH_L_EN, l_val); + tasha->hph_l_gain = hph_l_en & 0x1F; + } + + if ((r_val != hph_r_en) && !is_hphr_pa) { + snd_soc_write(codec, WCD9335_HPH_R_EN, r_val); + tasha->hph_r_gain = hph_r_en & 0x1F; + } +} + static void tasha_codec_hph_lohifi_config(struct snd_soc_codec *codec, - struct tasha_priv *tasha, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) { @@ -3755,7 +3863,6 @@ static void tasha_codec_hph_lohifi_config(struct snd_soc_codec *codec, } static void tasha_codec_hph_lp_config(struct snd_soc_codec *codec, - struct tasha_priv *tasha, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) { @@ -3785,6 +3892,22 @@ static void tasha_codec_hph_lp_config(struct snd_soc_codec *codec, } } +static void tasha_codec_hph_hifi_config(struct snd_soc_codec *codec, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C); + tasha_codec_hph_mode_gain_opt(codec, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00); + snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02); + } +} + static void tasha_codec_hph_mode_config(struct snd_soc_codec *codec, int event, int mode) { @@ -3795,10 +3918,13 @@ static void tasha_codec_hph_mode_config(struct snd_soc_codec *codec, switch (mode) { case CLS_H_LP: - tasha_codec_hph_lp_config(codec, tasha, event); + tasha_codec_hph_lp_config(codec, event); break; case CLS_H_LOHIFI: - tasha_codec_hph_lohifi_config(codec, tasha, event); + tasha_codec_hph_lohifi_config(codec, event); + break; + case CLS_H_HIFI: + tasha_codec_hph_hifi_config(codec, event); break; } } @@ -4146,6 +4272,38 @@ static u16 tasha_interp_get_primary_reg(u16 reg, u16 *ind) return prim_int_reg; } +static void tasha_codec_hd2_control(struct snd_soc_codec *codec, + u16 prim_int_reg, int event) +{ + struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) + return; + + if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + } + if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10); + snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01); + snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00); + snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00); + snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00); + } +} + static int tasha_codec_enable_prim_interpolator( struct snd_soc_codec *codec, u16 reg, int event) @@ -4162,6 +4320,7 @@ static int tasha_codec_enable_prim_interpolator( if (tasha->prim_int_users[ind] == 1) { snd_soc_update_bits(codec, prim_int_reg, 0x10, 0x10); + tasha_codec_hd2_control(codec, prim_int_reg, event); snd_soc_update_bits(codec, prim_int_reg, 1 << 0x5, 1 << 0x5); } @@ -4178,6 +4337,7 @@ static int tasha_codec_enable_prim_interpolator( 0x40, 0x40); snd_soc_update_bits(codec, prim_int_reg, 0x40, 0x00); + tasha_codec_hd2_control(codec, prim_int_reg, event); } break; }; @@ -9782,11 +9942,11 @@ static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("ANC HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0, tasha_codec_enable_hphl_pa, - SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("ANC HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0, tasha_codec_enable_hphr_pa, - SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("ANC LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0, @@ -10995,7 +11155,6 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = { {WCD9335_HPH_OCP_CTL, 0xFF, 0x5A}, {WCD9335_HPH_L_TEST, 0x01, 0x01}, {WCD9335_HPH_R_TEST, 0x01, 0x01}, - {WCD9335_FLYBACK_VNEG_DAC_CTRL_2, 0xE0, 0x20}, {WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12}, {WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08}, {WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18}, @@ -11004,6 +11163,8 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = { {WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, {WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45}, {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, }; static const struct tasha_reg_mask_val tasha_codec_reg_defaults[] = { diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c index 301cf5cf42c4..2661fab3b67f 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.c +++ b/sound/soc/codecs/wcd9xxx-common-v2.c @@ -660,13 +660,13 @@ static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec, 0x40, 0x40); } wcd_clsh_set_buck_regulator_mode(codec, mode); - wcd_clsh_set_buck_mode(codec, mode); wcd_clsh_set_flyback_mode(codec, mode); wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true); wcd_clsh_set_flyback_current(codec, mode); + wcd_clsh_set_buck_mode(codec, mode); wcd_clsh_buck_ctrl(codec, clsh_d, mode, true); - wcd_clsh_set_gain_path(codec, mode); wcd_clsh_set_hph_mode(codec, mode); + wcd_clsh_set_gain_path(codec, mode); } else { wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL); @@ -714,13 +714,13 @@ static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec, 0x40, 0x40); } wcd_clsh_set_buck_regulator_mode(codec, mode); - wcd_clsh_set_buck_mode(codec, mode); wcd_clsh_set_flyback_mode(codec, mode); wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true); wcd_clsh_set_flyback_current(codec, mode); + wcd_clsh_set_buck_mode(codec, mode); wcd_clsh_buck_ctrl(codec, clsh_d, mode, true); - wcd_clsh_set_gain_path(codec, mode); wcd_clsh_set_hph_mode(codec, mode); + wcd_clsh_set_gain_path(codec, mode); } else { wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);