From 07503e7108f0d9b1e5a3c36cbd735422b51cdbeb Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Fri, 29 Jun 2018 10:37:14 +0800 Subject: [PATCH] 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 --- sound/soc/codecs/rk3308_codec.c | 52 ++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c index 2dfe046b0aea..8ce989f211f1 100644 --- a/sound/soc/codecs/rk3308_codec.c +++ b/sound/soc/codecs/rk3308_codec.c @@ -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)