ASoC: wcd9335: Update HIFI mode sequence for headphones

Update HIFI mode register sequence for headphones on
wcd9335 codec for better performance.

Change-Id: I277a38847d02c4500cc3d2c77b00fbe4a63e2f83
Signed-off-by: Phani Kumar Uppalapati <phaniu@codeaurora.org>
This commit is contained in:
Phani Kumar Uppalapati 2015-10-26 16:39:07 -07:00 committed by David Keitel
parent 0307f3529b
commit b7f1874102
2 changed files with 176 additions and 15 deletions

View file

@ -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[] = {

View file

@ -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);