ASoC: rk3308_codec: using BIST mode switching during loopback

This patch using BIST mode switching to fix the glitches
during loopback and reset ADCs.

Change-Id: Icb9dbd6557736fe555d9f8296369571e78bc6844
Signed-off-by: Xing Zheng <zhengxing@rock-chips.com>
This commit is contained in:
Xing Zheng
2018-06-29 10:37:14 +08:00
committed by Tao Huang
parent 3d09cc8e0d
commit 07503e7108

View File

@@ -54,6 +54,7 @@
#define CODEC_DRV_NAME "rk3308-acodec"
#define ADC_LR_GROUP_MAX 4
#define ADC_STABLE_MS 20
#define DEBUG_POP_ALWAYS 0
#define ENABLE_AGC 0
#define HPDET_POLL_MS 2000
@@ -192,6 +193,8 @@ static const DECLARE_TLV_DB_RANGE(rk3308_codec_adc_3_8_mic_gain_tlv,
3, 3, TLV_DB_MINMAX_ITEM(2000, 2000),
);
static bool has_loopback(int loopback_grp);
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,
@@ -957,6 +960,30 @@ static int rk3308_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
#endif
} else {
#if !DEBUG_POP_ALWAYS
if (has_loopback(rk3308->loopback_grp) &&
(rk3308->dac_output == DAC_LINEOUT)) {
int type = ADC_TYPE_LOOPBACK;
int idx, grp;
/*
* Switch to dummy BIST mode (BIST keep reset
* now) to keep the zero input data in I2S bus.
*
* It may cause the glitch if we hold the ADC
* digtital i2s module in codec.
*/
for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) {
regmap_update_bits(rk3308->regmap,
RK3308_ADC_DIG_CON03(grp),
RK3308_ADC_L_CH_BIST_MSK,
RK3308_ADC_L_CH_BIST_SINE);
regmap_update_bits(rk3308->regmap,
RK3308_ADC_DIG_CON03(grp),
RK3308_ADC_R_CH_BIST_MSK,
RK3308_ADC_R_CH_BIST_SINE);
}
}
if (rk3308->dac_output == DAC_LINEOUT)
rk3308_speaker_ctl(rk3308, 1);
else if (rk3308->dac_output == DAC_HPOUT)
@@ -2920,13 +2947,30 @@ static void rk3308_codec_loopback_work(struct work_struct *work)
{
struct rk3308_codec_priv *rk3308 =
container_of(work, struct rk3308_codec_priv, loopback_work.work);
int type = ADC_TYPE_LOOPBACK;
int idx, grp;
/* Reset ADC quickly */
rk3308_codec_alc_disable(rk3308, ADC_TYPE_LOOPBACK);
rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_LOOPBACK);
rk3308_codec_alc_disable(rk3308, type);
rk3308_codec_adc_ana_disable(rk3308, type);
rk3308_codec_alc_enable(rk3308, ADC_TYPE_LOOPBACK);
rk3308_codec_adc_ana_enable(rk3308, ADC_TYPE_LOOPBACK);
rk3308_codec_alc_enable(rk3308, type);
rk3308_codec_adc_ana_enable(rk3308, type);
/* Waiting ADCs are stable */
msleep(ADC_STABLE_MS);
/* Recover normal mode after enable ADCs */
for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) {
regmap_update_bits(rk3308->regmap,
RK3308_ADC_DIG_CON03(grp),
RK3308_ADC_L_CH_BIST_MSK,
RK3308_ADC_L_CH_NORMAL_LEFT);
regmap_update_bits(rk3308->regmap,
RK3308_ADC_DIG_CON03(grp),
RK3308_ADC_R_CH_BIST_MSK,
RK3308_ADC_R_CH_NORMAL_RIGHT);
}
}
static irqreturn_t rk3308_codec_hpdet_isr(int irq, void *data)