From 5f27110ba793620fbdf7bb58446d2cc9cd5d27b8 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Mon, 26 Mar 2018 10:45:21 +0800 Subject: [PATCH] ASoC: codecs: update rk3308 codec driver This patch supports work internal codec on RK3308 EVB. The functions status are: DAC HEADPHONE 2CH -- OK DAC SPK 2CH -- OK ADC AMIC 8CH -- OK ADC AMIC 8CH LOOPBACK -- OK ADC AMIC 2CH -- OK ADC LINEIN 2CH -- OK Change-Id: I4f9ba3160b88e8c1e15980cf2eec7a1a5a25e7e7 Signed-off-by: Xing Zheng --- sound/soc/codecs/rk3308_codec.c | 767 +++++++++++++++++++++----------- sound/soc/codecs/rk3308_codec.h | 13 +- 2 files changed, 519 insertions(+), 261 deletions(-) diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c index 106f09738dd0..adf8a7ccd5e1 100644 --- a/sound/soc/codecs/rk3308_codec.c +++ b/sound/soc/codecs/rk3308_codec.c @@ -42,15 +42,39 @@ #include "rk3308_codec.h" +#if defined(CONFIG_DEBUG_FS) +#include +#include +#include +#endif + +#define CODEC_DRV_NAME "rk3308-acodec" + +#define ADC_LR_GROUP_MAX 4 + struct rk3308_codec_priv { const struct device *plat_dev; struct device dev; struct reset_control *reset; struct regmap *regmap; struct clk *pclk; + struct clk *mclk_rx; + struct clk *mclk_tx; struct gpio_desc *spk_ctl_gpio; - int adc_ch; /* To select ADCs for channel */ - int adc_ch0_using_linein; + /* + * To select ADCs for groups: + * + * grp 0 -- select ADC1 / ADC2 + * grp 1 -- select ADC3 / ADC4 + * grp 2 -- select ADC5 / ADC6 + * grp 3 -- select ADC7 / ADC8 + */ + int adc_cur_grp; + int adc_grp0_using_linein; + +#if defined(CONFIG_DEBUG_FS) + struct dentry *dbg_codec; +#endif }; static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_ch_gain_tlv, @@ -73,93 +97,93 @@ static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv, static const struct snd_kcontrol_new rk3308_codec_dapm_controls[] = { /* ALC AGC Channel*/ SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 0 Volume", - RK3308_ALC_L_DIG_CON03(0), - RK3308_ALC_R_DIG_CON03(0), - RK3308_AGC_PGA_GAIN_SFT, - RK3308_AGC_PGA_GAIN_NDB_18, - RK3308_AGC_PGA_GAIN_PDB_28_5, - 0, rk3308_codec_alc_agc_ch_gain_tlv), + RK3308_ALC_L_DIG_CON03(0), + RK3308_ALC_R_DIG_CON03(0), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_NDB_18, + RK3308_AGC_PGA_GAIN_PDB_28_5, + 0, rk3308_codec_alc_agc_ch_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 1 Volume", - RK3308_ALC_L_DIG_CON03(1), - RK3308_ALC_R_DIG_CON03(1), - RK3308_AGC_PGA_GAIN_SFT, - RK3308_AGC_PGA_GAIN_NDB_18, - RK3308_AGC_PGA_GAIN_PDB_28_5, - 0, rk3308_codec_alc_agc_ch_gain_tlv), + RK3308_ALC_L_DIG_CON03(1), + RK3308_ALC_R_DIG_CON03(1), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_NDB_18, + RK3308_AGC_PGA_GAIN_PDB_28_5, + 0, rk3308_codec_alc_agc_ch_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 2 Volume", - RK3308_ALC_L_DIG_CON03(2), - RK3308_ALC_R_DIG_CON03(2), - RK3308_AGC_PGA_GAIN_SFT, - RK3308_AGC_PGA_GAIN_NDB_18, - RK3308_AGC_PGA_GAIN_PDB_28_5, - 0, rk3308_codec_alc_agc_ch_gain_tlv), + RK3308_ALC_L_DIG_CON03(2), + RK3308_ALC_R_DIG_CON03(2), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_NDB_18, + RK3308_AGC_PGA_GAIN_PDB_28_5, + 0, rk3308_codec_alc_agc_ch_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 3 Volume", - RK3308_ALC_L_DIG_CON03(3), - RK3308_ALC_R_DIG_CON03(3), - RK3308_AGC_PGA_GAIN_SFT, - RK3308_AGC_PGA_GAIN_NDB_18, - RK3308_AGC_PGA_GAIN_PDB_28_5, - 0, rk3308_codec_alc_agc_ch_gain_tlv), + RK3308_ALC_L_DIG_CON03(3), + RK3308_ALC_R_DIG_CON03(3), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_NDB_18, + RK3308_AGC_PGA_GAIN_PDB_28_5, + 0, rk3308_codec_alc_agc_ch_gain_tlv), /* ALC AGC MAX */ SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 0 Max Volume", - RK3308_ALC_L_DIG_CON09(0), - RK3308_ALC_R_DIG_CON09(0), - RK3308_AGC_MAX_GAIN_PGA_SFT, - RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, - RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, - 0, rk3308_codec_alc_agc_ch_max_gain_tlv), + RK3308_ALC_L_DIG_CON09(0), + RK3308_ALC_R_DIG_CON09(0), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, + RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, + 0, rk3308_codec_alc_agc_ch_max_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 1 Max Volume", - RK3308_ALC_L_DIG_CON09(1), - RK3308_ALC_R_DIG_CON09(1), - RK3308_AGC_MAX_GAIN_PGA_SFT, - RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, - RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, - 0, rk3308_codec_alc_agc_ch_max_gain_tlv), + RK3308_ALC_L_DIG_CON09(1), + RK3308_ALC_R_DIG_CON09(1), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, + RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, + 0, rk3308_codec_alc_agc_ch_max_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 2 Max Volume", - RK3308_ALC_L_DIG_CON09(2), - RK3308_ALC_R_DIG_CON09(2), - RK3308_AGC_MAX_GAIN_PGA_SFT, - RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, - RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, + RK3308_ALC_L_DIG_CON09(2), + RK3308_ALC_R_DIG_CON09(2), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, + RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, 0, rk3308_codec_alc_agc_ch_max_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 3 Max Volume", - RK3308_ALC_L_DIG_CON09(3), - RK3308_ALC_R_DIG_CON09(3), - RK3308_AGC_MAX_GAIN_PGA_SFT, - RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, - RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, - 0, rk3308_codec_alc_agc_ch_max_gain_tlv), + RK3308_ALC_L_DIG_CON09(3), + RK3308_ALC_R_DIG_CON09(3), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_NDB_13_5, + RK3308_AGC_MAX_GAIN_PGA_PDB_28_5, + 0, rk3308_codec_alc_agc_ch_max_gain_tlv), /* ALC AGC MIN */ SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 0 Min Volume", - RK3308_ALC_L_DIG_CON09(0), - RK3308_ALC_R_DIG_CON09(0), - RK3308_AGC_MIN_GAIN_PGA_SFT, - RK3308_AGC_MIN_GAIN_PGA_NDB_18, - RK3308_AGC_MIN_GAIN_PGA_PDB_24, - 0, rk3308_codec_alc_agc_ch_min_gain_tlv), + RK3308_ALC_L_DIG_CON09(0), + RK3308_ALC_R_DIG_CON09(0), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_NDB_18, + RK3308_AGC_MIN_GAIN_PGA_PDB_24, + 0, rk3308_codec_alc_agc_ch_min_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 1 Min Volume", - RK3308_ALC_L_DIG_CON09(1), - RK3308_ALC_R_DIG_CON09(1), - RK3308_AGC_MIN_GAIN_PGA_SFT, - RK3308_AGC_MIN_GAIN_PGA_NDB_18, - RK3308_AGC_MIN_GAIN_PGA_PDB_24, - 0, rk3308_codec_alc_agc_ch_min_gain_tlv), + RK3308_ALC_L_DIG_CON09(1), + RK3308_ALC_R_DIG_CON09(1), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_NDB_18, + RK3308_AGC_MIN_GAIN_PGA_PDB_24, + 0, rk3308_codec_alc_agc_ch_min_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 2 Min Volume", - RK3308_ALC_L_DIG_CON09(2), - RK3308_ALC_R_DIG_CON09(2), - RK3308_AGC_MIN_GAIN_PGA_SFT, - RK3308_AGC_MIN_GAIN_PGA_NDB_18, - RK3308_AGC_MIN_GAIN_PGA_PDB_24, - 0, rk3308_codec_alc_agc_ch_min_gain_tlv), + RK3308_ALC_L_DIG_CON09(2), + RK3308_ALC_R_DIG_CON09(2), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_NDB_18, + RK3308_AGC_MIN_GAIN_PGA_PDB_24, + 0, rk3308_codec_alc_agc_ch_min_gain_tlv), SOC_DOUBLE_R_RANGE_TLV("ALC AGC Channel 3 Min Volume", - RK3308_ALC_L_DIG_CON09(3), - RK3308_ALC_R_DIG_CON09(3), - RK3308_AGC_MIN_GAIN_PGA_SFT, - RK3308_AGC_MIN_GAIN_PGA_NDB_18, - RK3308_AGC_MIN_GAIN_PGA_PDB_24, - 0, rk3308_codec_alc_agc_ch_min_gain_tlv), + RK3308_ALC_L_DIG_CON09(3), + RK3308_ALC_R_DIG_CON09(3), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_NDB_18, + RK3308_AGC_MIN_GAIN_PGA_PDB_24, + 0, rk3308_codec_alc_agc_ch_min_gain_tlv), /* ADC MIC */ SOC_SINGLE_RANGE_TLV("ADC MIC Channel 0 Left Volume", @@ -265,14 +289,14 @@ static const struct snd_kcontrol_new rk3308_codec_dapm_controls[] = { SOC_SINGLE_RANGE_TLV("DAC Left Volume", RK3308_DAC_ANA_CON04, RK3308_DAC_L_GAIN_SFT, - RK3308_DAC_L_GAIN_0DB, - RK3308_DAC_L_GAIN_PDB_6, + RK3308_DAC_L_GAIN_NDB_6, + RK3308_DAC_R_GAIN_0DB, 0, rk3308_codec_dac_gain_tlv), SOC_SINGLE_RANGE_TLV("DAC Right Volume", RK3308_DAC_ANA_CON04, RK3308_DAC_R_GAIN_SFT, + RK3308_DAC_R_GAIN_NDB_6, RK3308_DAC_R_GAIN_0DB, - RK3308_DAC_R_GAIN_PDB_6, 0, rk3308_codec_dac_gain_tlv), /* DAC HPOUT */ @@ -330,20 +354,21 @@ static int rk3308_codec_reset(struct snd_soc_codec *codec) static int rk3308_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_ON: break; - case SND_SOC_BIAS_PREPARE: break; - case SND_SOC_BIAS_STANDBY: + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + break; case SND_SOC_BIAS_OFF: break; } - snd_soc_codec_force_bias_level(codec, level); - return 0; } @@ -353,7 +378,7 @@ static int rk3308_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; - int ch = rk3308->adc_ch; + int grp; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: @@ -386,7 +411,7 @@ static int rk3308_set_dai_fmt(struct snd_soc_dai *codec_dai, dac_aif1 |= RK3308_DAC_I2S_MODE_RJ; break; case SND_SOC_DAIFMT_LEFT_J: - adc_aif1 |= RK3308_ADC_I2S_MODE_RJ; + adc_aif1 |= RK3308_ADC_I2S_MODE_LJ; dac_aif1 |= RK3308_DAC_I2S_MODE_LJ; break; default: @@ -422,15 +447,17 @@ static int rk3308_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(ch), - RK3308_ADC_I2S_LRC_POL_MSK | - RK3308_ADC_I2S_MODE_MSK, - adc_aif1); - regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(ch), - RK3308_ADC_IO_MODE_MSK | - RK3308_ADC_MODE_MSK | - RK3308_ADC_I2S_BIT_CLK_POL_MSK, - adc_aif2); + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), + RK3308_ADC_I2S_LRC_POL_MSK | + RK3308_ADC_I2S_MODE_MSK, + adc_aif1); + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), + RK3308_ADC_IO_MODE_MSK | + RK3308_ADC_MODE_MSK | + RK3308_ADC_I2S_BIT_CLK_POL_MSK, + adc_aif2); + } regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, RK3308_DAC_I2S_LRC_POL_MSK | @@ -452,7 +479,7 @@ static int rk3308_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; - int ch = rk3308->adc_ch; + int grp; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -480,6 +507,7 @@ static int rk3308_hw_params(struct snd_pcm_substream *substream, adc_aif1 |= RK3308_ADC_I2S_MONO; break; case 2: + case 8: adc_aif1 |= RK3308_ADC_I2S_STEREO; break; default: @@ -491,14 +519,16 @@ static int rk3308_hw_params(struct snd_pcm_substream *substream, dac_aif1 |= RK3308_DAC_I2S_LR_NORMAL; dac_aif2 |= RK3308_DAC_I2S_WORK; - regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(ch), - RK3308_ADC_I2S_VALID_LEN_MSK | - RK3308_ADC_I2S_LR_MSK | - RK3308_ADC_I2S_TYPE_MSK, - adc_aif1); - regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(ch), - RK3308_ADC_I2S_MSK, - adc_aif2); + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), + RK3308_ADC_I2S_VALID_LEN_MSK | + RK3308_ADC_I2S_LR_MSK | + RK3308_ADC_I2S_TYPE_MSK, + adc_aif1); + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), + RK3308_ADC_I2S_MSK, + adc_aif2); + } regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, RK3308_DAC_I2S_VALID_LEN_MSK | @@ -513,17 +543,24 @@ static int rk3308_hw_params(struct snd_pcm_substream *substream, static int rk3308_digital_mute(struct snd_soc_dai *dai, int mute) { + /* Do nothing */ return 0; } static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) { - /* Step 01 */ + /* + * 1. Set the ACODEC_DAC_ANA_CON0[0] to 0x1, to enable the current + * source of DAC + */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, RK3308_DAC_CURRENT_MSK, RK3308_DAC_CURRENT_EN); - /* Step 02 */ + /* + * 2. Set the ACODEC_DAC_ANA_CON1[6] and ACODEC_DAC_ANA_CON1[2] to 0x1, + * to enable the reference voltage buffer + */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, RK3308_DAC_BUF_REF_L_MSK | RK3308_DAC_BUF_REF_R_MSK, @@ -600,8 +637,8 @@ static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) 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_0DB | - RK3308_DAC_R_HPMIX_GAIN_0DB); + RK3308_DAC_L_HPMIX_GAIN_NDB_6 | + RK3308_DAC_R_HPMIX_GAIN_NDB_6); /* Step 16 */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, @@ -620,17 +657,17 @@ static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) /* Step 18 */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, RK3308_DAC_L_HPOUT_GAIN_MSK, - RK3308_DAC_L_HPOUT_GAIN_0DB); + RK3308_DAC_L_HPOUT_GAIN_NDB_1_5); /* Step 18 */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, RK3308_DAC_R_HPOUT_GAIN_MSK, - RK3308_DAC_R_HPOUT_GAIN_0DB); + RK3308_DAC_R_HPOUT_GAIN_NDB_1_5); /* Step 19 */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, RK3308_DAC_L_GAIN_MSK | RK3308_DAC_R_GAIN_MSK, - RK3308_DAC_L_GAIN_0DB | RK3308_DAC_R_GAIN_0DB); + RK3308_DAC_L_GAIN_NDB_6 | RK3308_DAC_R_GAIN_NDB_6); return 0; } @@ -640,12 +677,12 @@ static int rk3308_codec_dac_disable(struct rk3308_codec_priv *rk3308) /* Step 01 */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, RK3308_DAC_L_GAIN_MSK | RK3308_DAC_R_GAIN_MSK, - RK3308_DAC_L_GAIN_0DB | RK3308_DAC_R_GAIN_0DB); + RK3308_DAC_L_GAIN_NDB_6 | RK3308_DAC_R_GAIN_NDB_6); /* * Step 02 * - * Note1. In the step2, adjusting the register step by step to the + * Note. In the step2, adjusting the register step by step to the * appropriate value and taking 20ms as time step */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, @@ -775,9 +812,11 @@ static int rk3308_codec_power_on(struct snd_soc_codec *codec) * to 0x1, to setup dc voltage of the DAC channel output */ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, - RK3308_DAC_POP_SOUND_L_MSK, RK3308_DAC_POP_SOUND_L_INIT); + RK3308_DAC_POP_SOUND_L_MSK, + RK3308_DAC_POP_SOUND_L_INIT); regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, - RK3308_DAC_POP_SOUND_R_MSK, RK3308_DAC_POP_SOUND_R_INIT); + RK3308_DAC_POP_SOUND_R_MSK, + RK3308_DAC_POP_SOUND_R_INIT); /* * 3. Configure the register ACODEC_ADC_ANA_CON10[6:0] to 0x1 @@ -786,7 +825,8 @@ static int rk3308_codec_power_on(struct snd_soc_codec *codec) * signal to select current to pre-charge/dis_charge */ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_CURRENT_CHARGE_MSK, RK3308_ADC_SEL_I_64(1)); + RK3308_ADC_CURRENT_CHARGE_MSK, + RK3308_ADC_SEL_I_64(1)); /* 4. Supply the power of the analog part(AVDD,AVDDRV) */ @@ -819,6 +859,8 @@ static int rk3308_codec_power_on(struct snd_soc_codec *codec) */ /* TODO: choose an appropriate charge value */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_CURRENT_CHARGE_MSK, 0x7c); return 0; } @@ -834,11 +876,13 @@ static int rk3308_codec_power_off(struct snd_soc_codec *codec) /* 2. Configure the register ACODEC_ADC_ANA_CON10[6:0] to 0x1 */ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_CURRENT_CHARGE_MSK, RK3308_ADC_SEL_I_64(1)); + RK3308_ADC_CURRENT_CHARGE_MSK, + RK3308_ADC_SEL_I_64(1)); /* 3. Configure the register ACODEC_ADC_ANA_CON10[7] to 0x0 */ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_REF_EN, RK3308_ADC_REF_DIS); + RK3308_ADC_REF_EN, + RK3308_ADC_REF_DIS); /* * 4.Change the register ACODEC_ADC_ANA_CON10[6:0] from the 0x1 to 0x7f @@ -861,6 +905,41 @@ static int rk3308_codec_power_off(struct snd_soc_codec *codec) return 0; } +static int rk3308_codec_headset_detect_enable(struct rk3308_codec_priv *rk3308) +{ + /* HACK: headset_detect bypass */ + return 0; + + /* + * Set ACODEC_DAC_ANA_CON0[1] to 0x1, to enable the headset insert + * detection + * + * Note. When the voltage of PAD HPDET> 8*AVDD/9, the output value of + * the pin_hpdet will be set to 0x1 and assert a interrupt + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, + RK3308_DAC_HEADPHONE_DET_MSK, + RK3308_DAC_HEADPHONE_DET_EN); + + return 0; +} + +static int rk3308_codec_headset_detect_disable(struct rk3308_codec_priv *rk3308) +{ + /* HACK: headset_detect bypass */ + return 0; + + /* + * Set ACODEC_DAC_ANA_CON0[1] to 0x0, to disable the headset insert + * detection + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, + RK3308_DAC_HEADPHONE_DET_MSK, + RK3308_DAC_HEADPHONE_DET_DIS); + + return 0; +} + static int check_micbias(int micbias) { switch (micbias) { @@ -881,16 +960,8 @@ static int check_micbias(int micbias) static int rk3308_codec_micbias_enable(struct rk3308_codec_priv *rk3308, int micbias) { - int ch = rk3308->adc_ch; int ret; - if (ch != 1 && ch != 2) { - dev_err(rk3308->plat_dev, - "%s: currnet ch: %d, only ch1/2 control MICBIAS1/2\n", - __func__, ch); - return -EINVAL; - } - /* 1. Power up the ACODEC and keep the AVDDH stable */ /* 2. Configure ACODEC_ADC_ANA_CON7[2:0] to the certain value */ @@ -912,8 +983,13 @@ static int rk3308_codec_micbias_enable(struct rk3308_codec_priv *rk3308, /* 3. Wait until the VCMH keep stable */ usleep_range(200, 300); /* estimated value */ - /* 4. Configure ACODEC_ADC_ANA_CON8[4] to 0x1 */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(ch), + /* + * 4. Configure ACODEC_ADC_ANA_CON8[4] to 0x1 + * + * Note: Only the reg (ADC_ANA_CON8+0x0)[4] represent the enable + * signal of current source for MICBIAS + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0), RK3308_ADC_MICBIAS_CURRENT_MSK, RK3308_ADC_MICBIAS_CURRENT_EN); @@ -924,24 +1000,20 @@ static int rk3308_codec_micbias_enable(struct rk3308_codec_priv *rk3308, * (ADC_ANA_CON7+0x80)[3] used to control the MICBIAS2 */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(ch), + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(1), RK3308_ADC_MIC_BIAS_BUF_EN, RK3308_ADC_MIC_BIAS_BUF_EN); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(2), + RK3308_ADC_MIC_BIAS_BUF_EN, + RK3308_ADC_MIC_BIAS_BUF_EN); + + usleep_range(200, 300); /* estimated value */ return 0; } static int rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308) { - int ch = rk3308->adc_ch; - - if (ch != 1 && ch != 2) { - dev_err(rk3308->plat_dev, - "%s: currnet ch: %d, only ch1/2 control MICBIAS1/2\n", - __func__, ch); - return -EINVAL; - } - /* 1. Enable the MICBIAS and keep the Audio Codec stable */ /* Do nothing */ @@ -949,12 +1021,20 @@ static int rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308) * 2. Configure the (ADC_ANA_CON7+0x40)[3] or * (ADC_ANA_CON7+0x80)[3] to 0x0 */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(ch), + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(1), + RK3308_ADC_MIC_BIAS_BUF_EN, + RK3308_ADC_MIC_BIAS_BUF_DIS); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(2), RK3308_ADC_MIC_BIAS_BUF_EN, RK3308_ADC_MIC_BIAS_BUF_DIS); - /* 3. Configure ACODEC_ADC_ANA_CON8[4] to 0x0 */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(ch), + /* + * 3. Configure ACODEC_ADC_ANA_CON8[4] to 0x0 + * + * Note: Only the reg (ADC_ANA_CON8+0x0)[4] represent the enable + * signal of current source for MICBIAS + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0), RK3308_ADC_MICBIAS_CURRENT_MSK, RK3308_ADC_MICBIAS_CURRENT_DIS); @@ -963,24 +1043,24 @@ static int rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308) static int rk3308_codec_alc_enable(struct rk3308_codec_priv *rk3308) { - int ch = rk3308->adc_ch; + int grp = rk3308->adc_cur_grp; /* * 1. Set he max level and min level of the ALC need to control. * * These values are estimated */ - regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON05(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON05(grp), RK3308_AGC_LO_8BITS_AGC_MIN_MSK, 0x16); - regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON05(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON05(grp), RK3308_AGC_HI_8BITS_AGC_MIN_MSK, 0x40); - regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON05(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON05(grp), RK3308_AGC_LO_8BITS_AGC_MAX_MSK, 0x26); - regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON05(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON05(grp), RK3308_AGC_HI_8BITS_AGC_MAX_MSK, 0x40); @@ -989,18 +1069,18 @@ static int rk3308_codec_alc_enable(struct rk3308_codec_priv *rk3308) * * By default is 44.1KHz for sample. */ - regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON04(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON04(grp), RK3308_AGC_APPROX_RATE_MSK, RK3308_AGC_APPROX_RATE_44_1K); - regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON04(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON04(grp), RK3308_AGC_APPROX_RATE_MSK, RK3308_AGC_APPROX_RATE_44_1K); /* 3. Set ACODEC_ALC_DIG_CON9[6] to 0x1, to enable the ALC module */ - regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), RK3308_AGC_FUNC_SEL_MSK, RK3308_AGC_FUNC_SEL_EN); - regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), RK3308_AGC_FUNC_SEL_MSK, RK3308_AGC_FUNC_SEL_EN); @@ -1009,7 +1089,7 @@ static int rk3308_codec_alc_enable(struct rk3308_codec_priv *rk3308) * (ACODEC_ADC_ANA_CON11+0x80)[1:0] and (ACODEC_ADC_ANA_CON11+0xc0)[1:0] * to 0x3, to enable the ALC module to control the gain of PGA. */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(ch), + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK | RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK, RK3308_ADC_ALCL_CON_GAIN_PGAL_EN | @@ -1018,31 +1098,23 @@ static int rk3308_codec_alc_enable(struct rk3308_codec_priv *rk3308) /* * 5.Observe the current ALC output gain by reading * ACODEC_ALC_DIG_CON12[4:0] - * - * The default GAIN is 0x0c */ - regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON12(ch), - RK3308_AGC_GAIN_MSK, - 0x0c); - regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON12(ch), - RK3308_AGC_GAIN_MSK, - 0x0c); return 0; } static int rk3308_codec_alc_disable(struct rk3308_codec_priv *rk3308) { - int ch = rk3308->adc_ch; + int grp = rk3308->adc_cur_grp; /* * 1. Set ACODEC_ALC_DIG_CON9[6] to 0x0, to disable the ALC module, * then the ALC output gain will keep to the last value */ - regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), RK3308_AGC_FUNC_SEL_MSK, RK3308_AGC_FUNC_SEL_DIS); - regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(ch), + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), RK3308_AGC_FUNC_SEL_MSK, RK3308_AGC_FUNC_SEL_DIS); @@ -1051,7 +1123,7 @@ static int rk3308_codec_alc_disable(struct rk3308_codec_priv *rk3308) * (ACODEC_ADC_ANA_CON11+0x80)[1:0] and (ACODEC_ADC_ANA_CON11+0xc0)[1:0] * to 0x0, to disable the ALC module to control the gain of PGA. */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(ch), + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK | RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK, RK3308_ADC_ALCL_CON_GAIN_PGAL_DIS | @@ -1064,7 +1136,7 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308) { unsigned int adc_aif1 = 0, adc_aif2 = 0; unsigned int agc_func_en; - int ch = rk3308->adc_ch; + int grp = rk3308->adc_cur_grp; /* * 1. Set the ACODEC_ADC_ANA_CON7[7:6] and ACODEC_ADC_ANA_CON7[5:4], @@ -1073,22 +1145,20 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308) * Note1. Please ignore the step1 for enabling ADC3, ADC4, ADC5, * ADC6, ADC7, and ADC8 */ - if (ch == 0) { - if (rk3308->adc_ch0_using_linein) { - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(ch), - RK3308_ADC_CH1_IN_SEL_MSK, - RK3308_ADC_CH1_IN_LINEIN); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(ch), - RK3308_ADC_CH2_IN_SEL_MSK, - RK3308_ADC_CH2_IN_LINEIN); + if (grp == 0) { + if (rk3308->adc_grp0_using_linein) { + adc_aif1 = RK3308_ADC_CH1_IN_LINEIN_MIC; + adc_aif2 = RK3308_ADC_CH2_IN_LINEIN_MIC; } else { - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(ch), - RK3308_ADC_CH1_IN_SEL_MSK, - RK3308_ADC_CH1_IN_MIC); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(ch), - RK3308_ADC_CH2_IN_SEL_MSK, - RK3308_ADC_CH2_IN_MIC); + adc_aif1 = RK3308_ADC_CH1_IN_MIC; + adc_aif2 = RK3308_ADC_CH2_IN_MIC; } + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(grp), + RK3308_ADC_CH1_IN_SEL_MSK, + adc_aif1); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(grp), + RK3308_ADC_CH2_IN_SEL_MSK, + adc_aif2); } /* @@ -1096,17 +1166,17 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308) * of ADC, to enable the MIC module, to enable the reference voltage * buffer, and to end the initialization of MIC */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(ch), - RK3308_ADC_CH1_CH2_MIC_ALL_MSK, - RK3308_ADC_CH1_CH2_MIC_ALL); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_CH2_MIC_ALL_MSK, + RK3308_ADC_CH1_CH2_MIC_ALL); /* * 3. Set ACODEC_ADC_ANA_CON6[0] to 0x1, to enable the current source * of audio */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(ch), - RK3308_ADC_CURRENT_MSK, - RK3308_ADC_CURRENT_EN); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp), + RK3308_ADC_CURRENT_MSK, + RK3308_ADC_CURRENT_EN); /* * 4. Set ACODEC_ADC_ANA_CON2[7:0] to 0x77, to enable the ALC module, @@ -1118,37 +1188,32 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308) */ adc_aif1 = RK3308_ADC_CH1_ALC_EN | RK3308_ADC_CH1_ALC_WORK; - regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON09(ch), &agc_func_en); + regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), &agc_func_en); + if (agc_func_en & RK3308_AGC_FUNC_SEL_EN) adc_aif1 |= RK3308_ADC_CH1_ZEROCROSS_DET_EN; - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(ch), - RK3308_ADC_CH1_ALC_ZC_MSK, - adc_aif1); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_ZC_MSK, + adc_aif1); adc_aif2 = RK3308_ADC_CH2_ALC_EN | RK3308_ADC_CH2_ALC_WORK; - regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON09(ch), &agc_func_en); + regmap_read(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), &agc_func_en); if (agc_func_en & RK3308_AGC_FUNC_SEL_EN) adc_aif2 |= RK3308_ADC_CH2_ZEROCROSS_DET_EN; - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(ch), - RK3308_ADC_CH2_ALC_ZC_MSK, - adc_aif2); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH2_ALC_ZC_MSK, + adc_aif2); /* * 5. Set ACODEC_ADC_ANA_CON5[7:0] to 0x77, to enable the clock and * ADC module, and to end the initialization of ADC */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(ch), - RK3308_ADC_CH1_ADC_CLK_MSK, - RK3308_ADC_CH1_CLK_EN | - RK3308_ADC_CH1_ADC_EN | - RK3308_ADC_CH1_ADC_WORK); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(ch), - RK3308_ADC_CH2_ADC_CLK_MSK, - RK3308_ADC_CH2_CLK_EN | - RK3308_ADC_CH2_ADC_EN | - RK3308_ADC_CH2_ADC_WORK); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_CLK_MSK | + RK3308_ADC_CH2_ADC_CLK_MSK, + 0x77); /* * 6. Set ACODEC_ADC_ANA_CON1[5:4] and ACODEC_ADC_ANA_CON1[1:0], @@ -1156,12 +1221,12 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308) * * By default is 0db. */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(ch), - RK3308_ADC_CH1_MIC_GAIN_MSK, - RK3308_ADC_CH1_MIC_GAIN_0DB); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(ch), - RK3308_ADC_CH2_MIC_GAIN_MSK, - RK3308_ADC_CH2_MIC_GAIN_0DB); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON01(grp), + RK3308_ADC_CH1_MIC_GAIN_MSK, + RK3308_ADC_CH1_MIC_GAIN_0DB); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON01(grp), + RK3308_ADC_CH2_MIC_GAIN_MSK, + RK3308_ADC_CH2_MIC_GAIN_0DB); /* * 7.Set ACODEC_ADC_ANA_CON3[4:0] and ACODEC_ADC_ANA_CON4[3:0] to @@ -1169,12 +1234,12 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308) * * By default is 0db. */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON03(ch), - RK3308_ADC_CH1_ALC_GAIN_MSK, - RK3308_ADC_CH1_ALC_GAIN_0DB); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON04(ch), - RK3308_ADC_CH2_ALC_GAIN_MSK, - RK3308_ADC_CH2_ALC_GAIN_0DB); + 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); /* 8.Begin recording */ @@ -1183,48 +1248,48 @@ static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308) static int rk3308_codec_adc_ana_disable(struct rk3308_codec_priv *rk3308) { - int ch = rk3308->adc_ch; + int grp = rk3308->adc_cur_grp; /* * 1. Set ACODEC_ADC_ANA_CON2[7:0] to 0x0, to disable the ALC module, * to disable the zero-crossing detection function, and to begin the * initialization of ALC */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(ch), - RK3308_ADC_CH1_ALC_ZC_MSK, - 0); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(ch), - RK3308_ADC_CH2_ALC_ZC_MSK, - 0); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_ZC_MSK, + 0); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH2_ALC_ZC_MSK, + 0); /* * 2. Set ACODEC_ADC_ANA_CON5[7:0] to 0x0, to disable the clock and * ADC module, and to begin the initialization of ADC */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(ch), - RK3308_ADC_CH1_ADC_CLK_MSK, - 0); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(ch), - RK3308_ADC_CH2_ADC_CLK_MSK, - 0); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_CLK_MSK, + 0); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH2_ADC_CLK_MSK, + 0); /* * 3. Set ACODEC_ADC_ANA_CON0[7:0] to 0x88, to disable the MIC module, * to disable the reference voltage buffer, and to begin the * initialization of MIC */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(ch), - RK3308_ADC_CH1_CH2_MIC_ALL_MSK, - RK3308_ADC_CH1_MIC_UNMUTE | - RK3308_ADC_CH2_MIC_UNMUTE); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_CH2_MIC_ALL_MSK, + RK3308_ADC_CH1_MIC_MUTE | + RK3308_ADC_CH2_MIC_MUTE); /* * 4. Set ACODEC_ADC_ANA_CON6[0] to 0x0, to disable the current * source of audio */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(ch), - RK3308_ADC_CURRENT_MSK, - RK3308_ADC_CURRENT_DIS); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp), + RK3308_ADC_CURRENT_MSK, + RK3308_ADC_CURRENT_DIS); return 0; } @@ -1232,9 +1297,17 @@ static int rk3308_codec_adc_ana_disable(struct rk3308_codec_priv *rk3308) static int rk3308_codec_open_capture(struct snd_soc_codec *codec) { struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); + int grp, temp_grp; - rk3308_codec_alc_enable(rk3308); - rk3308_codec_adc_ana_enable(rk3308); + rk3308_codec_micbias_enable(rk3308, RK3308_ADC_MICBIAS_VOLT_0_7); + + temp_grp = rk3308->adc_cur_grp; + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + rk3308->adc_cur_grp = grp; + rk3308_codec_alc_enable(rk3308); + rk3308_codec_adc_ana_enable(rk3308); + } + rk3308->adc_cur_grp = temp_grp; return 0; } @@ -1242,9 +1315,17 @@ static int rk3308_codec_open_capture(struct snd_soc_codec *codec) static int rk3308_codec_close_capture(struct snd_soc_codec *codec) { struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); + int grp, temp_grp; - rk3308_codec_alc_disable(rk3308); - rk3308_codec_adc_ana_disable(rk3308); + temp_grp = rk3308->adc_cur_grp; + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + rk3308->adc_cur_grp = grp; + rk3308_codec_alc_disable(rk3308); + rk3308_codec_adc_ana_disable(rk3308); + } + rk3308->adc_cur_grp = temp_grp; + + rk3308_codec_micbias_disable(rk3308); return 0; } @@ -1273,6 +1354,7 @@ static int rk3308_pcm_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); int ret = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1280,6 +1362,9 @@ static int rk3308_pcm_startup(struct snd_pcm_substream *substream, else ret = rk3308_codec_open_capture(codec); + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + return ret; } @@ -1287,11 +1372,15 @@ static void rk3308_pcm_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) rk3308_codec_close_playback(codec); else rk3308_codec_close_capture(codec); + + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); } static struct snd_soc_dai_ops rk3308_dai_ops = { @@ -1350,8 +1439,10 @@ static int rk3308_probe(struct snd_soc_codec *codec) rk3308_codec_reset(codec); rk3308_codec_power_on(codec); + rk3308_codec_headset_detect_enable(rk3308); - rk3308_codec_micbias_enable(rk3308, RK3308_ADC_MICBIAS_VOLT_0_7); + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); return 0; } @@ -1361,9 +1452,12 @@ static int rk3308_remove(struct snd_soc_codec *codec) struct rk3308_codec_priv *rk3308 = snd_soc_codec_get_drvdata(codec); rk3308_speaker_ctl(rk3308, 0); - rk3308_codec_micbias_disable(rk3308); + rk3308_codec_headset_detect_disable(rk3308); rk3308_codec_power_off(codec); + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + return 0; } @@ -1389,12 +1483,12 @@ static bool rk3308_codec_write_read_reg(struct device *dev, unsigned int reg) static bool rk3308_codec_volatile_reg(struct device *dev, unsigned int reg) { - switch (reg) { - case RK3308_GLB_CON: - return true; - default: - return false; - } + return true; +} + +static irqreturn_t rk3308_codec_headset_isr(int irq, void *dev_id) +{ + return IRQ_HANDLED; } static const struct regmap_config rk3308_codec_regmap_config = { @@ -1411,38 +1505,73 @@ static const struct regmap_config rk3308_codec_regmap_config = { }; static ssize_t adc_ch_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + + return sprintf(buf, "adc_cur_grp: %d\n", rk3308->adc_cur_grp); +} + +static ssize_t adc_ch_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + unsigned long grp; + int ret = kstrtoul(buf, 10, &grp); + + if (ret < 0 || grp > 4) { + dev_err(dev, "Invalid LR grp: %ld, ret: %d\n", grp, ret); + return -EINVAL; + } + + rk3308->adc_cur_grp = grp; + + dev_info(dev, "store grp: %d\n", rk3308->adc_cur_grp); + + return count; +} + +static ssize_t adc_grp0_in_show(struct device *dev, struct device_attribute *attr, char *buf) { struct rk3308_codec_priv *rk3308 = container_of(dev, struct rk3308_codec_priv, dev); - return sprintf(buf, "adc_ch: %d\n", rk3308->adc_ch); + return sprintf(buf, "adc ch0 using: %s\n", + rk3308->adc_grp0_using_linein ? "line in" : "mic in"); } -static ssize_t adc_ch_store(struct device *dev, +static ssize_t adc_grp0_in_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct rk3308_codec_priv *rk3308 = container_of(dev, struct rk3308_codec_priv, dev); - unsigned long ch; - int ret = kstrtoul(buf, 10, &ch); + unsigned long using_linein; + int ret = kstrtoul(buf, 10, &using_linein); - if (ret < 0 || ch > 4) { - dev_err(dev, "Invalid ch: %ld, ret: %d\n", ch, ret); + if (ret < 0 || using_linein > 1) { + dev_err(dev, "Invalid input status: %ld, ret: %d\n", + using_linein, ret); return -EINVAL; } - rk3308->adc_ch = ch; + rk3308->adc_grp0_using_linein = using_linein; - dev_info(dev, "Store ch: %d\n", rk3308->adc_ch); + dev_info(dev, "store using_linein: %d\n", + rk3308->adc_grp0_using_linein); return count; } static const struct device_attribute adc_ch_attrs[] = { - __ATTR(adc_ch, 0644, adc_ch_show, adc_ch_store), + __ATTR(adc_cur_grp, 0644, adc_ch_show, adc_ch_store), + __ATTR(adc_grp0_in, 0644, adc_grp0_in_show, adc_grp0_in_store), }; static void rk3308_codec_device_release(struct device *dev) @@ -1480,14 +1609,90 @@ static int rk3308_codec_sysfs_init(struct platform_device *pdev, return 0; } +#if defined(CONFIG_DEBUG_FS) +static int rk3308_codec_debugfs_reg_show(struct seq_file *s, void *v) +{ + struct rk3308_codec_priv *rk3308 = s->private; + unsigned int i; + unsigned int val; + + for (i = RK3308_GLB_CON; i <= RK3308_DAC_ANA_CON13; i += 4) { + regmap_read(rk3308->regmap, i, &val); + if (!(i % 16)) + seq_printf(s, "\nR:%04x: ", i); + seq_printf(s, "%08x ", val); + } + + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t rk3308_codec_debugfs_reg_operate(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct rk3308_codec_priv *rk3308 = + ((struct seq_file *)file->private_data)->private; + unsigned int reg, val; + char op; + char kbuf[32]; + int ret; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(kbuf, buf, count)) + return -EFAULT; + kbuf[count] = '\0'; + + ret = sscanf(kbuf, "%c,%x,%x", &op, ®, &val); + if (ret != 3) { + pr_err("sscanf failed: %d\n", ret); + return -EFAULT; + } + + if (op == 'w') { + pr_info("Write reg: 0x%04x with val: 0x%08x\n", reg, val); + regmap_write(rk3308->regmap, reg, val); + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + pr_info("Read back reg: 0x%04x with val: 0x%08x\n", reg, val); + } else if (op == 'r') { + regmap_read(rk3308->regmap, reg, &val); + pr_info("Read reg: 0x%04x with val: 0x%08x\n", reg, val); + } else { + pr_err("This is an invalid operation: %c\n", op); + } + + return count; +} + +static int rk3308_codec_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, + rk3308_codec_debugfs_reg_show, inode->i_private); +} + +static const struct file_operations rk3308_codec_reg_debugfs_fops = { + .owner = THIS_MODULE, + .open = rk3308_codec_debugfs_open, + .read = seq_read, + .write = rk3308_codec_debugfs_reg_operate, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_DEBUG_FS */ + static int rk3308_platform_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct rk3308_codec_priv *rk3308; struct resource *res; - void __iomem *base; - int ret = 0; struct regmap *grf; + void __iomem *base; + int irq; + int ret; grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(grf)) { @@ -1506,6 +1711,15 @@ static int rk3308_platform_probe(struct platform_device *pdev) return ret; } +#if defined(CONFIG_DEBUG_FS) + rk3308->dbg_codec = debugfs_create_dir(CODEC_DRV_NAME, NULL); + if (IS_ERR(rk3308->dbg_codec)) + dev_err(&pdev->dev, + "Failed to create debugfs dir for rk3308!\n"); + else + debugfs_create_file("reg", 0644, rk3308->dbg_codec, + rk3308, &rk3308_codec_reg_debugfs_fops); +#endif rk3308->plat_dev = &pdev->dev; rk3308->reset = devm_reset_control_get(&pdev->dev, "acodec-reset"); @@ -1533,12 +1747,36 @@ static int rk3308_platform_probe(struct platform_device *pdev) return PTR_ERR(rk3308->pclk); } + rk3308->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx"); + if (IS_ERR(rk3308->mclk_rx)) { + dev_err(&pdev->dev, "Can't get acodec mclk_rx\n"); + return PTR_ERR(rk3308->mclk_rx); + } + + rk3308->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx"); + if (IS_ERR(rk3308->mclk_tx)) { + dev_err(&pdev->dev, "Can't get acodec mclk_tx\n"); + return PTR_ERR(rk3308->mclk_tx); + } + ret = clk_prepare_enable(rk3308->pclk); if (ret < 0) { dev_err(&pdev->dev, "Failed to enable acodec pclk: %d\n", ret); return ret; } + ret = clk_prepare_enable(rk3308->mclk_rx); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable i2s mclk_rx: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(rk3308->mclk_tx); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable i2s mclk_tx: %d\n", ret); + return ret; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) { @@ -1555,10 +1793,25 @@ static int rk3308_platform_probe(struct platform_device *pdev) goto failed; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Can not get codec irq\n"); + goto failed; + } + + ret = devm_request_irq(&pdev->dev, irq, rk3308_codec_headset_isr, + 0, "headset-irq", rk3308); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request IRQ: %d\n", ret); + goto failed; + } + + rk3308->adc_grp0_using_linein = 0; + platform_set_drvdata(pdev, rk3308); ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_rk3308, - rk3308_dai, ARRAY_SIZE(rk3308_dai)); + rk3308_dai, ARRAY_SIZE(rk3308_dai)); if (ret < 0) { dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); goto failed; @@ -1567,6 +1820,8 @@ static int rk3308_platform_probe(struct platform_device *pdev) return ret; failed: + clk_disable_unprepare(rk3308->mclk_rx); + clk_disable_unprepare(rk3308->mclk_tx); clk_disable_unprepare(rk3308->pclk); return ret; @@ -1577,6 +1832,8 @@ static int rk3308_platform_remove(struct platform_device *pdev) struct rk3308_codec_priv *rk3308 = (struct rk3308_codec_priv *)platform_get_drvdata(pdev); + clk_disable_unprepare(rk3308->mclk_rx); + clk_disable_unprepare(rk3308->mclk_tx); clk_disable_unprepare(rk3308->pclk); snd_soc_unregister_codec(&pdev->dev); @@ -1591,7 +1848,7 @@ MODULE_DEVICE_TABLE(of, rk3308codec_of_match); static struct platform_driver rk3308_codec_driver = { .driver = { - .name = "rk3308-acodec", + .name = CODEC_DRV_NAME, .of_match_table = of_match_ptr(rk3308codec_of_match), }, .probe = rk3308_platform_probe, diff --git a/sound/soc/codecs/rk3308_codec.h b/sound/soc/codecs/rk3308_codec.h index 6cfa69157785..fe16fe33322c 100644 --- a/sound/soc/codecs/rk3308_codec.h +++ b/sound/soc/codecs/rk3308_codec.h @@ -773,6 +773,7 @@ #define RK3308_ADC_ALCL_CON_GAIN_PGAL_DIS (0x0 << 0) /* RK3308_DAC_ANA_CON00 - REG: 0x0440 */ +#define RK3308_DAC_HEADPHONE_DET_MSK (0x1 << 1) #define RK3308_DAC_HEADPHONE_DET_EN (0x1 << 1) #define RK3308_DAC_HEADPHONE_DET_DIS (0x0 << 1) #define RK3308_DAC_CURRENT_MSK (0x1 << 0) @@ -831,9 +832,9 @@ #define RK3308_DAC_R_GAIN_SFT 6 #define RK3308_DAC_R_GAIN_MSK (0x3 << RK3308_DAC_R_GAIN_SFT) #define RK3308_DAC_R_GAIN_0DB (0x3 << RK3308_DAC_R_GAIN_SFT) -#define RK3308_DAC_R_GAIN_PDB_1_5 (0x2 << RK3308_DAC_R_GAIN_SFT) -#define RK3308_DAC_R_GAIN_PDB_3 (0x1 << RK3308_DAC_R_GAIN_SFT) -#define RK3308_DAC_R_GAIN_PDB_6 (0x0 << RK3308_DAC_R_GAIN_SFT) +#define RK3308_DAC_R_GAIN_NDB_1_5 (0x2 << RK3308_DAC_R_GAIN_SFT) +#define RK3308_DAC_R_GAIN_NDB_3 (0x1 << RK3308_DAC_R_GAIN_SFT) +#define RK3308_DAC_R_GAIN_NDB_6 (0x0 << RK3308_DAC_R_GAIN_SFT) #define RK3308_DAC_R_LINEOUT_UNMUTE (0x1 << 5) #define RK3308_DAC_R_LINEOUT_MUTE (0x0 << 5) #define RK3308_DAC_R_LINEOUT_EN (0x1 << 4) @@ -841,9 +842,9 @@ #define RK3308_DAC_L_GAIN_SFT 2 #define RK3308_DAC_L_GAIN_MSK (0x3 << RK3308_DAC_L_GAIN_SFT) #define RK3308_DAC_L_GAIN_0DB (0x3 << RK3308_DAC_L_GAIN_SFT) -#define RK3308_DAC_L_GAIN_PDB_1_5 (0x2 << RK3308_DAC_L_GAIN_SFT) -#define RK3308_DAC_L_GAIN_PDB_3 (0x1 << RK3308_DAC_L_GAIN_SFT) -#define RK3308_DAC_L_GAIN_PDB_6 (0x0 << RK3308_DAC_L_GAIN_SFT) +#define RK3308_DAC_L_GAIN_NDB_1_5 (0x2 << RK3308_DAC_L_GAIN_SFT) +#define RK3308_DAC_L_GAIN_NDB_3 (0x1 << RK3308_DAC_L_GAIN_SFT) +#define RK3308_DAC_L_GAIN_NDB_6 (0x0 << RK3308_DAC_L_GAIN_SFT) #define RK3308_DAC_L_LINEOUT_UNMUTE (0x1 << 1) #define RK3308_DAC_L_LINEOUT_MUTE (0x0 << 1) #define RK3308_DAC_L_LINEOUT_EN (0x1 << 0)