From d1b463ef192d861d46d158ef28432113bd546090 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Thu, 7 Jun 2018 16:48:12 +0800 Subject: [PATCH] ASoC: rk3308_codec: using default gains on startup We don't need to set gains when enable/disable ADC and DAC, keep gains at last time. And add hpout fade-in when enable DAC, and clean up a bit of coding style for gains. Change-Id: I2d8cdc1b0d87b55714177a1208a8f7a4e655a732 Signed-off-by: Xing Zheng --- sound/soc/codecs/rk3308_codec.c | 324 +++++++++++++++++++++----------- 1 file changed, 210 insertions(+), 114 deletions(-) diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c index c4e871afd3da..ae25655d5725 100644 --- a/sound/soc/codecs/rk3308_codec.c +++ b/sound/soc/codecs/rk3308_codec.c @@ -140,6 +140,10 @@ struct rk3308_codec_priv { int adc_path_state; int dac_path_state; + /* Only hpout do fade-in and fade-out */ + unsigned int hpout_l_dgain; + unsigned int hpout_r_dgain; + bool enable_all_adcs; bool hp_plugged; struct delayed_work hpdet_work; @@ -175,6 +179,15 @@ static const DECLARE_TLV_DB_RANGE(rk3308_codec_adc_3_8_mic_gain_tlv, 3, 3, TLV_DB_MINMAX_ITEM(2000, 2000), ); +static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + static const struct snd_kcontrol_new rk3308_codec_dapm_controls[] = { /* ALC AGC Group */ SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Left Volume", @@ -448,16 +461,22 @@ static const struct snd_kcontrol_new rk3308_codec_dapm_controls[] = { 0, rk3308_codec_dac_lineout_gain_tlv), /* DAC HPOUT */ - SOC_SINGLE_TLV("DAC HPOUT Left Volume", - RK3308_DAC_ANA_CON05, - RK3308_DAC_L_HPOUT_GAIN_SFT, - RK3308_DAC_L_HPOUT_GAIN_MAX, - 0, rk3308_codec_dac_hpout_gain_tlv), - SOC_SINGLE_TLV("DAC HPOUT Right Volume", - RK3308_DAC_ANA_CON06, - RK3308_DAC_R_HPOUT_GAIN_SFT, - RK3308_DAC_R_HPOUT_GAIN_MAX, - 0, rk3308_codec_dac_hpout_gain_tlv), + SOC_SINGLE_EXT_TLV("DAC HPOUT Left Volume", + RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_SFT, + RK3308_DAC_L_HPOUT_GAIN_MAX, + 0, + rk3308_codec_hpout_l_get_tlv, + rk3308_codec_hpout_l_put_tlv, + rk3308_codec_dac_hpout_gain_tlv), + SOC_SINGLE_EXT_TLV("DAC HPOUT Right Volume", + RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_SFT, + RK3308_DAC_R_HPOUT_GAIN_MAX, + 0, + rk3308_codec_hpout_r_get_tlv, + rk3308_codec_hpout_r_put_tlv, + rk3308_codec_dac_hpout_gain_tlv), /* DAC HPMIX */ SOC_SINGLE_RANGE_TLV("DAC HPMIX Left Volume", @@ -474,6 +493,54 @@ static const struct snd_kcontrol_new rk3308_codec_dapm_controls[] = { 0, rk3308_codec_dac_hpmix_gain_tlv), }; +static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return snd_soc_get_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); + unsigned int dgain = ucontrol->value.integer.value[0]; + + if (dgain > RK3308_DAC_L_HPOUT_GAIN_MAX) { + dev_err(rk3308->plat_dev, "%s: invalid l_dgain: %d\n", + __func__, dgain); + return -EINVAL; + } + + rk3308->hpout_l_dgain = dgain; + + return snd_soc_put_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return snd_soc_get_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); + unsigned int dgain = ucontrol->value.integer.value[0]; + + if (dgain > RK3308_DAC_R_HPOUT_GAIN_MAX) { + dev_err(rk3308->plat_dev, "%s: invalid r_dgain: %d\n", + __func__, dgain); + return -EINVAL; + } + + rk3308->hpout_r_dgain = dgain; + + return snd_soc_put_volsw_range(kcontrol, ucontrol); +} + static bool adc_for_each_grp(struct rk3308_codec_priv *rk3308, int type, int idx, u32 *grp) { @@ -901,6 +968,84 @@ static int rk3308_mute_stream(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static int rk3308_codec_digital_fadein(struct rk3308_codec_priv *rk3308) +{ + unsigned int dgain, dgain_ref; + + if (rk3308->hpout_l_dgain != rk3308->hpout_r_dgain) { + pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n", + rk3308->hpout_l_dgain, rk3308->hpout_r_dgain); + dgain_ref = min(rk3308->hpout_l_dgain, rk3308->hpout_r_dgain); + } else { + dgain_ref = rk3308->hpout_l_dgain; + } + + /* + * We'd better change the gain of the left and right channels + * at the same time to avoid different listening + */ + for (dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39; + dgain <= dgain_ref; dgain++) { + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_MSK, + dgain); + + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_MSK, + dgain); + } + + return 0; +} + +static int rk3308_codec_digital_fadeout(struct rk3308_codec_priv *rk3308) +{ + unsigned int l_dgain, r_dgain; + + /* + * Note. In the step2, adjusting the register step by step to + * the appropriate value and taking 20ms as time step + */ + regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON05, &l_dgain); + l_dgain &= RK3308_DAC_L_HPOUT_GAIN_MSK; + + regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON06, &r_dgain); + r_dgain &= RK3308_DAC_R_HPOUT_GAIN_MSK; + + if (l_dgain != r_dgain) { + pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n", + l_dgain, r_dgain); + l_dgain = min(l_dgain, r_dgain); + } + + /* + * We'd better change the gain of the left and right channels + * at the same time to avoid different listening + */ + while (l_dgain >= RK3308_DAC_L_HPOUT_GAIN_NDB_39) { + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_MSK, + l_dgain); + + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_MSK, + l_dgain); + + usleep_range(200, 300); /* estimated value */ + + if (l_dgain == RK3308_DAC_L_HPOUT_GAIN_NDB_39) + break; + + l_dgain--; + } + + return 0; +} + static int rk3308_codec_dac_lineout_enable(struct rk3308_codec_priv *rk3308) { /* Step 06 */ @@ -1245,15 +1390,6 @@ static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) udelay(20); - /* Step 15 */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, - RK3308_DAC_L_HPMIX_GAIN_MSK | - RK3308_DAC_R_HPMIX_GAIN_MSK, - RK3308_DAC_L_HPMIX_GAIN_NDB_6 | - RK3308_DAC_R_HPMIX_GAIN_NDB_6); - - udelay(20); - if (rk3308->dac_output == DAC_HPOUT || rk3308->dac_output == DAC_LINEOUT_HPOUT) { /* Step 16 */ @@ -1280,28 +1416,8 @@ static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) if (rk3308->dac_output == DAC_HPOUT || rk3308->dac_output == DAC_LINEOUT_HPOUT) { /* Step 18 */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, - RK3308_DAC_L_HPOUT_GAIN_MSK, - RK3308_DAC_L_HPOUT_GAIN_NDB_39); - - /* Step 18 */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, - RK3308_DAC_R_HPOUT_GAIN_MSK, - RK3308_DAC_R_HPOUT_GAIN_NDB_39); - - udelay(20); - } - - if (rk3308->dac_output == DAC_LINEOUT || - rk3308->dac_output == DAC_LINEOUT_HPOUT) { /* Step 19 */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, - RK3308_DAC_L_LINEOUT_GAIN_MSK | - RK3308_DAC_R_LINEOUT_GAIN_MSK, - RK3308_DAC_L_LINEOUT_GAIN_NDB_6 | - RK3308_DAC_R_LINEOUT_GAIN_NDB_6); - - udelay(20); + rk3308_codec_digital_fadein(rk3308); } /* TODO: TRY TO TEST DRIVE STRENGTH */ @@ -1309,61 +1425,11 @@ static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) return 0; } -static int rk3308_codec_digital_fadeout(struct rk3308_codec_priv *rk3308) -{ - unsigned int l_dgain, r_dgain; - - /* - * Note. In the step2, adjusting the register step by step to - * the appropriate value and taking 20ms as time step - */ - regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON05, &l_dgain); - l_dgain &= RK3308_DAC_L_HPOUT_GAIN_MSK; - - regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON06, &r_dgain); - r_dgain &= RK3308_DAC_R_HPOUT_GAIN_MSK; - - if (l_dgain != r_dgain) - pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n", - l_dgain, r_dgain); - - /* - * We'd better change the gain of the left and right channels - * at the same time to avoid different listening - */ - while (l_dgain >= RK3308_DAC_L_HPOUT_GAIN_NDB_39) { - /* Step 02 decrease dgains for de-pop */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, - RK3308_DAC_L_HPOUT_GAIN_MSK, - l_dgain); - - /* Step 02 decrease dgains for de-pop */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, - RK3308_DAC_R_HPOUT_GAIN_MSK, - r_dgain); - - usleep_range(200, 300); /* estimated value */ - - if (l_dgain == RK3308_DAC_L_HPOUT_GAIN_NDB_39) - break; - - l_dgain--; - r_dgain--; - } - - return 0; -} - static int rk3308_codec_dac_disable(struct rk3308_codec_priv *rk3308) { /* Step 00, the min digital gain for mute */ /* Step 01 */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, - RK3308_DAC_L_LINEOUT_GAIN_MSK | - RK3308_DAC_R_LINEOUT_GAIN_MSK, - RK3308_DAC_L_LINEOUT_GAIN_NDB_6 | - RK3308_DAC_R_LINEOUT_GAIN_NDB_6); /* Step 02 */ rk3308_codec_digital_fadeout(rk3308); @@ -1477,13 +1543,6 @@ static int rk3308_codec_dac_disable(struct rk3308_codec_priv *rk3308) RK3308_DAC_L_HPMIX_INIT | RK3308_DAC_R_HPMIX_INIT); - /* Step 19 */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, - RK3308_DAC_L_HPMIX_GAIN_MSK | - RK3308_DAC_R_HPMIX_GAIN_MSK, - RK3308_DAC_L_HPMIX_GAIN_NDB_6 | - RK3308_DAC_R_HPMIX_GAIN_NDB_6); - /* * Note2. If the ACODEC_DAC_ANA_CON12[7] or ACODEC_DAC_ANA_CON12[3] * is set to 0x1, add the steps from the section Disable ADC @@ -2078,7 +2137,6 @@ static int rk3308_codec_adc_reinit_mics(struct rk3308_codec_priv *rk3308, static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308, int type) { - unsigned int adc_aif1 = 0, adc_aif2 = 0; unsigned int agc_func_en; int idx, grp; @@ -2216,24 +2274,8 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308, } /* vendor step 12 */ - adc_aif1 = RK3308_ADC_CH1_MIC_GAIN_0DB; - adc_aif2 = RK3308_ADC_CH2_MIC_GAIN_0DB; - for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON01(grp), - RK3308_ADC_CH1_MIC_GAIN_MSK | - RK3308_ADC_CH2_MIC_GAIN_MSK, - adc_aif1 | adc_aif2); - } /* vendor step 13 */ - for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON03(grp), - RK3308_ADC_CH1_ALC_GAIN_MSK, - RK3308_ADC_CH1_ALC_GAIN_0DB); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON04(grp), - RK3308_ADC_CH2_ALC_GAIN_MSK, - RK3308_ADC_CH2_ALC_GAIN_0DB); - } /* vendor step 14 */ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { @@ -2527,11 +2569,65 @@ static int rk3308_resume(struct snd_soc_codec *codec) return 0; } +static int rk3308_codec_default_gains(struct rk3308_codec_priv *rk3308) +{ + int grp; + + /* Prepare ADC gains */ + /* vendor step 12, set MIC PGA default gains */ + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON01(grp), + RK3308_ADC_CH1_MIC_GAIN_MSK | + RK3308_ADC_CH2_MIC_GAIN_MSK, + RK3308_ADC_CH1_MIC_GAIN_0DB | + RK3308_ADC_CH2_MIC_GAIN_0DB); + } + + /* vendor step 13, set ALC default gains */ + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON03(grp), + RK3308_ADC_CH1_ALC_GAIN_MSK, + RK3308_ADC_CH1_ALC_GAIN_0DB); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON04(grp), + RK3308_ADC_CH2_ALC_GAIN_MSK, + RK3308_ADC_CH2_ALC_GAIN_0DB); + } + + /* Prepare DAC gains */ + /* Step 15, set HPMIX default gains */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, + RK3308_DAC_L_HPMIX_GAIN_MSK | + RK3308_DAC_R_HPMIX_GAIN_MSK, + RK3308_DAC_L_HPMIX_GAIN_NDB_6 | + RK3308_DAC_R_HPMIX_GAIN_NDB_6); + + /* Step 18, set HPOUT default gains */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_MSK, + RK3308_DAC_L_HPOUT_GAIN_NDB_39); + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_MSK, + RK3308_DAC_R_HPOUT_GAIN_NDB_39); + + /* Using the same gain to HPOUT LR channels */ + rk3308->hpout_l_dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39; + + /* Step 19, set LINEOUT default gains */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_GAIN_MSK | + RK3308_DAC_R_LINEOUT_GAIN_MSK, + RK3308_DAC_L_LINEOUT_GAIN_NDB_6 | + RK3308_DAC_R_LINEOUT_GAIN_NDB_6); + + return 0; +} + static int rk3308_codec_prepare(struct rk3308_codec_priv *rk3308) { /* Clear registers for ADC and DAC */ rk3308_codec_close_playback(rk3308); rk3308_codec_close_capture(rk3308); + rk3308_codec_default_gains(rk3308); return 0; }