diff options
Diffstat (limited to 'sound/soc/codecs')
182 files changed, 32548 insertions, 7162 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 8af04343cc1..3c4b10ff48c 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -16,6 +16,7 @@  #include <linux/mfd/88pm860x.h>  #include <linux/slab.h>  #include <linux/delay.h> +#include <linux/regmap.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -140,6 +141,7 @@ struct pm860x_priv {  	unsigned int		filter;  	struct snd_soc_codec	*codec;  	struct i2c_client	*i2c; +	struct regmap		*regmap;  	struct pm860x_chip	*chip;  	struct pm860x_det	det; @@ -269,54 +271,12 @@ static struct st_gain st_table[] = {  	{   -86, 29,  0}, {   -56, 30,  0}, {   -28, 31,  0}, {     0,  0,  0},  }; -static int pm860x_volatile(unsigned int reg) -{ -	BUG_ON(reg >= REG_CACHE_SIZE); - -	switch (reg) { -	case PM860X_AUDIO_SUPPLIES_2: -		return 1; -	} - -	return 0; -} - -static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec, -					  unsigned int reg) -{ -	unsigned char *cache = codec->reg_cache; - -	BUG_ON(reg >= REG_CACHE_SIZE); - -	if (pm860x_volatile(reg)) -		return cache[reg]; - -	reg += REG_CACHE_BASE; - -	return pm860x_reg_read(codec->control_data, reg); -} - -static int pm860x_write_reg_cache(struct snd_soc_codec *codec, -				  unsigned int reg, unsigned int value) -{ -	unsigned char *cache = codec->reg_cache; - -	BUG_ON(reg >= REG_CACHE_SIZE); - -	if (!pm860x_volatile(reg)) -		cache[reg] = (unsigned char)value; - -	reg += REG_CACHE_BASE; - -	return pm860x_reg_write(codec->control_data, reg, value); -} -  static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,  				   struct snd_ctl_elem_value *ucontrol)  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	int val[2], val2[2], i; @@ -340,7 +300,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	int err; @@ -349,6 +309,9 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,  	val = ucontrol->value.integer.value[0];  	val2 = ucontrol->value.integer.value[1]; +	if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table)) +		return -EINVAL; +  	err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);  	if (err < 0)  		return err; @@ -370,7 +333,7 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	unsigned int shift = mc->shift; @@ -390,7 +353,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	unsigned int shift = mc->shift; @@ -485,38 +448,38 @@ static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};  static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"}; -static const struct soc_enum pm860x_hs1_opamp_enum = -	SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum, +			    PM860X_HS1_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_hs2_opamp_enum = -	SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum, +			    PM860X_HS2_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_hs1_pa_enum = -	SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum, +			    PM860X_HS1_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_hs2_pa_enum = -	SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum, +			    PM860X_HS2_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_lo1_opamp_enum = -	SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum, +			    PM860X_LO1_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_lo2_opamp_enum = -	SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum, +			    PM860X_LO2_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_lo1_pa_enum = -	SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum, +			    PM860X_LO1_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_lo2_pa_enum = -	SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum, +			    PM860X_LO2_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_spk_pa_enum = -	SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum, +			    PM860X_EAR_CTRL_1, 5, pm860x_pa_texts); -static const struct soc_enum pm860x_ear_pa_enum = -	SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum, +			    PM860X_EAR_CTRL_2, 0, pm860x_pa_texts); -static const struct soc_enum pm860x_spk_ear_opamp_enum = -	SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum, +			    PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts);  static const struct snd_kcontrol_new pm860x_snd_controls[] = {  	SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2, @@ -598,8 +561,8 @@ static const char *aif1_text[] = {  	"PCM L", "PCM R",  }; -static const struct soc_enum aif1_enum = -	SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text); +static SOC_ENUM_SINGLE_DECL(aif1_enum, +			    PM860X_PCM_IFACE_3, 6, aif1_text);  static const struct snd_kcontrol_new aif1_mux =  	SOC_DAPM_ENUM("PCM Mux", aif1_enum); @@ -609,8 +572,8 @@ static const char *i2s_din_text[] = {  	"DIN", "DIN1",  }; -static const struct soc_enum i2s_din_enum = -	SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text); +static SOC_ENUM_SINGLE_DECL(i2s_din_enum, +			    PM860X_I2S_IFACE_3, 1, i2s_din_text);  static const struct snd_kcontrol_new i2s_din_mux =  	SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum); @@ -620,8 +583,8 @@ static const char *i2s_mic_text[] = {  	"Ex PA", "ADC",  }; -static const struct soc_enum i2s_mic_enum = -	SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text); +static SOC_ENUM_SINGLE_DECL(i2s_mic_enum, +			    PM860X_I2S_IFACE_3, 4, i2s_mic_text);  static const struct snd_kcontrol_new i2s_mic_mux =  	SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum); @@ -631,8 +594,8 @@ static const char *adcl_text[] = {  	"ADCR", "ADCL",  }; -static const struct soc_enum adcl_enum = -	SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text); +static SOC_ENUM_SINGLE_DECL(adcl_enum, +			    PM860X_PCM_IFACE_3, 4, adcl_text);  static const struct snd_kcontrol_new adcl_mux =  	SOC_DAPM_ENUM("ADC Left Mux", adcl_enum); @@ -642,8 +605,8 @@ static const char *adcr_text[] = {  	"ADCL", "ADCR",  }; -static const struct soc_enum adcr_enum = -	SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text); +static SOC_ENUM_SINGLE_DECL(adcr_enum, +			    PM860X_PCM_IFACE_3, 2, adcr_text);  static const struct snd_kcontrol_new adcr_mux =  	SOC_DAPM_ENUM("ADC Right Mux", adcr_enum); @@ -653,8 +616,8 @@ static const char *adcr_ec_text[] = {  	"ADCR", "EC",  }; -static const struct soc_enum adcr_ec_enum = -	SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text); +static SOC_ENUM_SINGLE_DECL(adcr_ec_enum, +			    PM860X_ADC_EN_2, 3, adcr_ec_text);  static const struct snd_kcontrol_new adcr_ec_mux =  	SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum); @@ -664,8 +627,8 @@ static const char *ec_text[] = {  	"Left", "Right", "Left + Right",  }; -static const struct soc_enum ec_enum = -	SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text); +static SOC_ENUM_SINGLE_DECL(ec_enum, +			    PM860X_EC_PATH, 1, ec_text);  static const struct snd_kcontrol_new ec_mux =  	SOC_DAPM_ENUM("EC Mux", ec_enum); @@ -675,36 +638,36 @@ static const char *dac_text[] = {  };  /* DAC Headset 1 Mux / Mux10 */ -static const struct soc_enum dac_hs1_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_hs1_enum, +			    PM860X_ANA_INPUT_SEL_1, 0, dac_text);  static const struct snd_kcontrol_new dac_hs1_mux =  	SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);  /* DAC Headset 2 Mux / Mux11 */ -static const struct soc_enum dac_hs2_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_hs2_enum, +			    PM860X_ANA_INPUT_SEL_1, 2, dac_text);  static const struct snd_kcontrol_new dac_hs2_mux =  	SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);  /* DAC Lineout 1 Mux / Mux12 */ -static const struct soc_enum dac_lo1_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_lo1_enum, +			    PM860X_ANA_INPUT_SEL_1, 4, dac_text);  static const struct snd_kcontrol_new dac_lo1_mux =  	SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);  /* DAC Lineout 2 Mux / Mux13 */ -static const struct soc_enum dac_lo2_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_lo2_enum, +			    PM860X_ANA_INPUT_SEL_1, 6, dac_text);  static const struct snd_kcontrol_new dac_lo2_mux =  	SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);  /* DAC Spearker Earphone Mux / Mux14 */ -static const struct soc_enum dac_spk_ear_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum, +			    PM860X_ANA_INPUT_SEL_2, 0, dac_text);  static const struct snd_kcontrol_new dac_spk_ear_mux =  	SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum); @@ -714,29 +677,29 @@ static const char *in_text[] = {  	"Digital", "Analog",  }; -static const struct soc_enum hs1_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text); +static SOC_ENUM_SINGLE_DECL(hs1_enum, +			    PM860X_ANA_TO_ANA, 0, in_text);  static const struct snd_kcontrol_new hs1_mux =  	SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);  /* Headset 2 Mux / Mux16 */ -static const struct soc_enum hs2_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text); +static SOC_ENUM_SINGLE_DECL(hs2_enum, +			    PM860X_ANA_TO_ANA, 1, in_text);  static const struct snd_kcontrol_new hs2_mux =  	SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);  /* Lineout 1 Mux / Mux17 */ -static const struct soc_enum lo1_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text); +static SOC_ENUM_SINGLE_DECL(lo1_enum, +			    PM860X_ANA_TO_ANA, 2, in_text);  static const struct snd_kcontrol_new lo1_mux =  	SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);  /* Lineout 2 Mux / Mux18 */ -static const struct soc_enum lo2_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text); +static SOC_ENUM_SINGLE_DECL(lo2_enum, +			    PM860X_ANA_TO_ANA, 3, in_text);  static const struct snd_kcontrol_new lo2_mux =  	SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum); @@ -746,8 +709,8 @@ static const char *spk_text[] = {  	"Earpiece", "Speaker",  }; -static const struct soc_enum spk_enum = -	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text); +static SOC_ENUM_SINGLE_DECL(spk_enum, +			    PM860X_ANA_TO_ANA, 6, spk_text);  static const struct snd_kcontrol_new spk_demux =  	SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum); @@ -757,8 +720,8 @@ static const char *mic_text[] = {  	"Mic 1", "Mic 2",  }; -static const struct soc_enum mic_enum = -	SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text); +static SOC_ENUM_SINGLE_DECL(mic_enum, +			    PM860X_ADC_ANA_4, 4, mic_text);  static const struct snd_kcontrol_new mic_mux =  	SOC_DAPM_ENUM("MIC Mux", mic_enum); @@ -1166,6 +1129,7 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,  static int pm860x_set_bias_level(struct snd_soc_codec *codec,  				 enum snd_soc_bias_level level)  { +	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);  	int data;  	switch (level) { @@ -1179,17 +1143,17 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {  			/* Enable Audio PLL & Audio section */  			data = AUDIO_PLL | AUDIO_SECTION_ON; -			pm860x_reg_write(codec->control_data, REG_MISC2, data); +			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);  			udelay(300);  			data = AUDIO_PLL | AUDIO_SECTION_RESET  				| AUDIO_SECTION_ON; -			pm860x_reg_write(codec->control_data, REG_MISC2, data); +			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);  		}  		break;  	case SND_SOC_BIAS_OFF:  		data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON; -		pm860x_set_bits(codec->control_data, REG_MISC2, data, 0); +		pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);  		break;  	}  	codec->dapm.bias_level = level; @@ -1319,17 +1283,17 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec,  	pm860x->det.lo_shrt = lo_shrt;  	if (det & SND_JACK_HEADPHONE) -		pm860x_set_bits(codec->control_data, REG_HS_DET, +		pm860x_set_bits(pm860x->i2c, REG_HS_DET,  				EN_HS_DET, EN_HS_DET);  	/* headset short detect */  	if (hs_shrt) {  		data = CLR_SHORT_HS2 | CLR_SHORT_HS1; -		pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); +		pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);  	}  	/* Lineout short detect */  	if (lo_shrt) {  		data = CLR_SHORT_LO2 | CLR_SHORT_LO1; -		pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); +		pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);  	}  	/* sync status */ @@ -1347,7 +1311,7 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec,  	pm860x->det.mic_det = det;  	if (det & SND_JACK_MICROPHONE) -		pm860x_set_bits(codec->control_data, REG_MIC_DET, +		pm860x_set_bits(pm860x->i2c, REG_MIC_DET,  				MICDET_MASK, MICDET_MASK);  	/* sync status */ @@ -1363,8 +1327,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)  	pm860x->codec = codec; -	codec->control_data = pm860x->i2c; -  	for (i = 0; i < 4; i++) {  		ret = request_threaded_irq(pm860x->irq[i], NULL,  					   pm860x_codec_handler, IRQF_ONESHOT, @@ -1377,14 +1339,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)  	pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE, -			       REG_CACHE_SIZE, codec->reg_cache); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to fill register cache: %d\n", -			ret); -		goto out; -	} -  	return 0;  out: @@ -1404,14 +1358,18 @@ static int pm860x_remove(struct snd_soc_codec *codec)  	return 0;  } +static struct regmap *pm860x_get_regmap(struct device *dev) +{ +	struct pm860x_priv *pm860x = dev_get_drvdata(dev); + +	return pm860x->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_pm860x = {  	.probe		= pm860x_probe,  	.remove		= pm860x_remove, -	.read		= pm860x_read_reg_cache, -	.write		= pm860x_write_reg_cache, -	.reg_cache_size	= REG_CACHE_SIZE, -	.reg_word_size	= sizeof(u8),  	.set_bias_level	= pm860x_set_bias_level, +	.get_regmap	= pm860x_get_regmap,  	.controls = pm860x_snd_controls,  	.num_controls = ARRAY_SIZE(pm860x_snd_controls), @@ -1436,6 +1394,8 @@ static int pm860x_codec_probe(struct platform_device *pdev)  	pm860x->chip = chip;  	pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client  			: chip->companion; +	pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap +			: chip->regmap_companion;  	platform_set_drvdata(pdev, pm860x);  	for (i = 0; i < 4; i++) { diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h index 3364ba4a360..f7282f4f4a7 100644 --- a/sound/soc/codecs/88pm860x-codec.h +++ b/sound/soc/codecs/88pm860x-codec.h @@ -12,67 +12,66 @@  #ifndef __88PM860X_H  #define __88PM860X_H -/* The offset of these registers are 0xb0 */ -#define PM860X_PCM_IFACE_1		0x00 -#define PM860X_PCM_IFACE_2		0x01 -#define PM860X_PCM_IFACE_3		0x02 -#define PM860X_PCM_RATE			0x03 -#define PM860X_EC_PATH			0x04 -#define PM860X_SIDETONE_L_GAIN		0x05 -#define PM860X_SIDETONE_R_GAIN		0x06 -#define PM860X_SIDETONE_SHIFT		0x07 -#define PM860X_ADC_OFFSET_1		0x08 -#define PM860X_ADC_OFFSET_2		0x09 -#define PM860X_DMIC_DELAY		0x0a +#define PM860X_PCM_IFACE_1		0xb0 +#define PM860X_PCM_IFACE_2		0xb1 +#define PM860X_PCM_IFACE_3		0xb2 +#define PM860X_PCM_RATE			0xb3 +#define PM860X_EC_PATH			0xb4 +#define PM860X_SIDETONE_L_GAIN		0xb5 +#define PM860X_SIDETONE_R_GAIN		0xb6 +#define PM860X_SIDETONE_SHIFT		0xb7 +#define PM860X_ADC_OFFSET_1		0xb8 +#define PM860X_ADC_OFFSET_2		0xb9 +#define PM860X_DMIC_DELAY		0xba -#define PM860X_I2S_IFACE_1		0x0b -#define PM860X_I2S_IFACE_2		0x0c -#define PM860X_I2S_IFACE_3		0x0d -#define PM860X_I2S_IFACE_4		0x0e -#define PM860X_EQUALIZER_N0_1		0x0f -#define PM860X_EQUALIZER_N0_2		0x10 -#define PM860X_EQUALIZER_N1_1		0x11 -#define PM860X_EQUALIZER_N1_2		0x12 -#define PM860X_EQUALIZER_D1_1		0x13 -#define PM860X_EQUALIZER_D1_2		0x14 -#define PM860X_LOFI_GAIN_LEFT		0x15 -#define PM860X_LOFI_GAIN_RIGHT		0x16 -#define PM860X_HIFIL_GAIN_LEFT		0x17 -#define PM860X_HIFIL_GAIN_RIGHT		0x18 -#define PM860X_HIFIR_GAIN_LEFT		0x19 -#define PM860X_HIFIR_GAIN_RIGHT		0x1a -#define PM860X_DAC_OFFSET		0x1b -#define PM860X_OFFSET_LEFT_1		0x1c -#define PM860X_OFFSET_LEFT_2		0x1d -#define PM860X_OFFSET_RIGHT_1		0x1e -#define PM860X_OFFSET_RIGHT_2		0x1f -#define PM860X_ADC_ANA_1		0x20 -#define PM860X_ADC_ANA_2		0x21 -#define PM860X_ADC_ANA_3		0x22 -#define PM860X_ADC_ANA_4		0x23 -#define PM860X_ANA_TO_ANA		0x24 -#define PM860X_HS1_CTRL			0x25 -#define PM860X_HS2_CTRL			0x26 -#define PM860X_LO1_CTRL			0x27 -#define PM860X_LO2_CTRL			0x28 -#define PM860X_EAR_CTRL_1		0x29 -#define PM860X_EAR_CTRL_2		0x2a -#define PM860X_AUDIO_SUPPLIES_1		0x2b -#define PM860X_AUDIO_SUPPLIES_2		0x2c -#define PM860X_ADC_EN_1			0x2d -#define PM860X_ADC_EN_2			0x2e -#define PM860X_DAC_EN_1			0x2f -#define PM860X_DAC_EN_2			0x31 -#define PM860X_AUDIO_CAL_1		0x32 -#define PM860X_AUDIO_CAL_2		0x33 -#define PM860X_AUDIO_CAL_3		0x34 -#define PM860X_AUDIO_CAL_4		0x35 -#define PM860X_AUDIO_CAL_5		0x36 -#define PM860X_ANA_INPUT_SEL_1		0x37 -#define PM860X_ANA_INPUT_SEL_2		0x38 +#define PM860X_I2S_IFACE_1		0xbb +#define PM860X_I2S_IFACE_2		0xbc +#define PM860X_I2S_IFACE_3		0xbd +#define PM860X_I2S_IFACE_4		0xbe +#define PM860X_EQUALIZER_N0_1		0xbf +#define PM860X_EQUALIZER_N0_2		0xc0 +#define PM860X_EQUALIZER_N1_1		0xc1 +#define PM860X_EQUALIZER_N1_2		0xc2 +#define PM860X_EQUALIZER_D1_1		0xc3 +#define PM860X_EQUALIZER_D1_2		0xc4 +#define PM860X_LOFI_GAIN_LEFT		0xc5 +#define PM860X_LOFI_GAIN_RIGHT		0xc6 +#define PM860X_HIFIL_GAIN_LEFT		0xc7 +#define PM860X_HIFIL_GAIN_RIGHT		0xc8 +#define PM860X_HIFIR_GAIN_LEFT		0xc9 +#define PM860X_HIFIR_GAIN_RIGHT		0xca +#define PM860X_DAC_OFFSET		0xcb +#define PM860X_OFFSET_LEFT_1		0xcc +#define PM860X_OFFSET_LEFT_2		0xcd +#define PM860X_OFFSET_RIGHT_1		0xce +#define PM860X_OFFSET_RIGHT_2		0xcf +#define PM860X_ADC_ANA_1		0xd0 +#define PM860X_ADC_ANA_2		0xd1 +#define PM860X_ADC_ANA_3		0xd2 +#define PM860X_ADC_ANA_4		0xd3 +#define PM860X_ANA_TO_ANA		0xd4 +#define PM860X_HS1_CTRL			0xd5 +#define PM860X_HS2_CTRL			0xd6 +#define PM860X_LO1_CTRL			0xd7 +#define PM860X_LO2_CTRL			0xd8 +#define PM860X_EAR_CTRL_1		0xd9 +#define PM860X_EAR_CTRL_2		0xda +#define PM860X_AUDIO_SUPPLIES_1		0xdb +#define PM860X_AUDIO_SUPPLIES_2		0xdc +#define PM860X_ADC_EN_1			0xdd +#define PM860X_ADC_EN_2			0xde +#define PM860X_DAC_EN_1			0xdf +#define PM860X_DAC_EN_2			0xe1 +#define PM860X_AUDIO_CAL_1		0xe2 +#define PM860X_AUDIO_CAL_2		0xe3 +#define PM860X_AUDIO_CAL_3		0xe4 +#define PM860X_AUDIO_CAL_4		0xe5 +#define PM860X_AUDIO_CAL_5		0xe6 +#define PM860X_ANA_INPUT_SEL_1		0xe7 +#define PM860X_ANA_INPUT_SEL_2		0xe8 -#define PM860X_PCM_IFACE_4		0x39 -#define PM860X_I2S_IFACE_5		0x3a +#define PM860X_PCM_IFACE_4		0xe9 +#define PM860X_I2S_IFACE_5		0xea  #define PM860X_SHORTS			0x3b  #define PM860X_PLL_ADJ_1		0x3c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b33b45dfcee..0b9571c858f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -8,6 +8,8 @@ config SND_SOC_I2C_AND_SPI  	default y if I2C=y  	default y if SPI_MASTER=y +menu "CODEC drivers" +  config SND_SOC_ALL_CODECS  	tristate "Build all ASoC CODEC drivers"  	depends on COMPILE_TEST @@ -16,15 +18,24 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_AB8500_CODEC if ABX500_CORE  	select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS  	select SND_SOC_AD1836 if SPI_MASTER -	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI +	select SND_SOC_AD193X_SPI if SPI_MASTER +	select SND_SOC_AD193X_I2C if I2C  	select SND_SOC_AD1980 if SND_SOC_AC97_BUS  	select SND_SOC_AD73311  	select SND_SOC_ADAU1373 if I2C -	select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI +	select SND_SOC_ADAU1761_I2C if I2C +	select SND_SOC_ADAU1761_SPI if SPI +	select SND_SOC_ADAU1781_I2C if I2C +	select SND_SOC_ADAU1781_SPI if SPI +	select SND_SOC_ADAV801 if SPI_MASTER +	select SND_SOC_ADAV803 if I2C +	select SND_SOC_ADAU1977_SPI if SPI_MASTER +	select SND_SOC_ADAU1977_I2C if I2C  	select SND_SOC_ADAU1701 if I2C  	select SND_SOC_ADS117X  	select SND_SOC_AK4104 if SPI_MASTER  	select SND_SOC_AK4535 if I2C +	select SND_SOC_AK4554  	select SND_SOC_AK4641 if I2C  	select SND_SOC_AK4642 if I2C  	select SND_SOC_AK4671 if I2C @@ -32,11 +43,13 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_ALC5623 if I2C  	select SND_SOC_ALC5632 if I2C  	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC -	select SND_SOC_CS42L51 if I2C -	select SND_SOC_CS42L52 if I2C +	select SND_SOC_CS42L51_I2C if I2C +	select SND_SOC_CS42L52 if I2C && INPUT +	select SND_SOC_CS42L56 if I2C && INPUT  	select SND_SOC_CS42L73 if I2C  	select SND_SOC_CS4270 if I2C  	select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI +	select SND_SOC_CS42XX8_I2C if I2C  	select SND_SOC_CX20442 if TTY  	select SND_SOC_DA7210 if I2C  	select SND_SOC_DA7213 if I2C @@ -59,20 +72,30 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_PCM1681 if I2C  	select SND_SOC_PCM1792A if SPI_MASTER  	select SND_SOC_PCM3008 +	select SND_SOC_PCM512x_I2C if I2C +	select SND_SOC_PCM512x_SPI if SPI_MASTER  	select SND_SOC_RT5631 if I2C  	select SND_SOC_RT5640 if I2C +	select SND_SOC_RT5645 if I2C +	select SND_SOC_RT5651 if I2C +	select SND_SOC_RT5677 if I2C  	select SND_SOC_SGTL5000 if I2C  	select SND_SOC_SI476X if MFD_SI476X_CORE +	select SND_SOC_SIRF_AUDIO_CODEC  	select SND_SOC_SN95031 if INTEL_SCU_IPC  	select SND_SOC_SPDIF  	select SND_SOC_SSM2518 if I2C -	select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI +	select SND_SOC_SSM2602_SPI if SPI_MASTER +	select SND_SOC_SSM2602_I2C if I2C  	select SND_SOC_STA32X if I2C +	select SND_SOC_STA350 if I2C  	select SND_SOC_STA529 if I2C  	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS  	select SND_SOC_TAS5086 if I2C -	select SND_SOC_TLV320AIC23 if I2C +	select SND_SOC_TLV320AIC23_I2C if I2C +	select SND_SOC_TLV320AIC23_SPI if SPI_MASTER  	select SND_SOC_TLV320AIC26 if SPI_MASTER +	select SND_SOC_TLV320AIC31XX if I2C  	select SND_SOC_TLV320AIC32X4 if I2C  	select SND_SOC_TLV320AIC3X if I2C  	select SND_SOC_TPA6130A2 if I2C @@ -113,7 +136,7 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_WM8955 if I2C  	select SND_SOC_WM8960 if I2C  	select SND_SOC_WM8961 if I2C -	select SND_SOC_WM8962 if I2C +	select SND_SOC_WM8962 if I2C && INPUT  	select SND_SOC_WM8971 if I2C  	select SND_SOC_WM8974 if I2C  	select SND_SOC_WM8978 if I2C @@ -163,8 +186,10 @@ config SND_SOC_WM_HUBS  config SND_SOC_WM_ADSP  	tristate  	default y if SND_SOC_WM5102=y +	default y if SND_SOC_WM5110=y  	default y if SND_SOC_WM2200=y  	default m if SND_SOC_WM5102=m +	default m if SND_SOC_WM5110=m  	default m if SND_SOC_WM2200=m  config SND_SOC_AB8500_CODEC @@ -180,48 +205,114 @@ config SND_SOC_AD1836  config SND_SOC_AD193X  	tristate +config SND_SOC_AD193X_SPI +	tristate +	select SND_SOC_AD193X + +config SND_SOC_AD193X_I2C +	tristate +	select SND_SOC_AD193X +  config SND_SOC_AD1980  	tristate  config SND_SOC_AD73311  	tristate +config SND_SOC_ADAU1373 +	tristate +  config SND_SOC_ADAU1701 -	select SND_SOC_SIGMADSP +	tristate "Analog Devices ADAU1701 CODEC" +	depends on I2C +	select SND_SOC_SIGMADSP_I2C + +config SND_SOC_ADAU17X1  	tristate +	select SND_SOC_SIGMADSP_REGMAP -config SND_SOC_ADAU1373 +config SND_SOC_ADAU1761 +	tristate +	select SND_SOC_ADAU17X1 + +config SND_SOC_ADAU1761_I2C +	tristate +	select SND_SOC_ADAU1761 +	select REGMAP_I2C + +config SND_SOC_ADAU1761_SPI +	tristate +	select SND_SOC_ADAU1761 +	select REGMAP_SPI + +config SND_SOC_ADAU1781 +	select SND_SOC_ADAU17X1 +	tristate + +config SND_SOC_ADAU1781_I2C +	tristate +	select SND_SOC_ADAU1781 +	select REGMAP_I2C + +config SND_SOC_ADAU1781_SPI +	tristate +	select SND_SOC_ADAU1781 +	select REGMAP_SPI + +config SND_SOC_ADAU1977 +	tristate + +config SND_SOC_ADAU1977_SPI  	tristate +	select SND_SOC_ADAU1977 +	select REGMAP_SPI + +config SND_SOC_ADAU1977_I2C +	tristate +	select SND_SOC_ADAU1977 +	select REGMAP_I2C  config SND_SOC_ADAV80X  	tristate +config SND_SOC_ADAV801 +	tristate +	select SND_SOC_ADAV80X + +config SND_SOC_ADAV803 +	tristate +	select SND_SOC_ADAV80X +  config SND_SOC_ADS117X  	tristate  config SND_SOC_AK4104 -	tristate +	tristate "AKM AK4104 CODEC" +	depends on SPI_MASTER  config SND_SOC_AK4535  	tristate  config SND_SOC_AK4554 -	tristate +	tristate "AKM AK4554 CODEC"  config SND_SOC_AK4641  	tristate  config SND_SOC_AK4642 -	tristate +	tristate "AKM AK4642 CODEC" +	depends on I2C  config SND_SOC_AK4671  	tristate  config SND_SOC_AK5386 -	tristate +	tristate "AKM AK5638 CODEC"  config SND_SOC_ALC5623 -       tristate +       tristate "Realtek ALC5623 CODEC" +	depends on I2C +  config SND_SOC_ALC5632  	tristate @@ -231,15 +322,26 @@ config SND_SOC_CQ0093VC  config SND_SOC_CS42L51  	tristate -config SND_SOC_CS42L52 +config SND_SOC_CS42L51_I2C  	tristate +	select SND_SOC_CS42L51 + +config SND_SOC_CS42L52 +	tristate "Cirrus Logic CS42L52 CODEC" +	depends on I2C && INPUT + +config SND_SOC_CS42L56 +	tristate "Cirrus Logic CS42L56 CODEC" +	depends on I2C && INPUT  config SND_SOC_CS42L73 -	tristate +	tristate "Cirrus Logic CS42L73 CODEC" +	depends on I2C  # Cirrus Logic CS4270 Codec  config SND_SOC_CS4270 -	tristate +	tristate "Cirrus Logic CS4270 CODEC" +	depends on I2C  # Cirrus Logic CS4270 Codec VD = 3.3V Errata  # Select if you are affected by the errata where the part will not function @@ -250,8 +352,18 @@ config SND_SOC_CS4270_VD33_ERRATA  	depends on SND_SOC_CS4270  config SND_SOC_CS4271 +	tristate "Cirrus Logic CS4271 CODEC" +	depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_CS42XX8  	tristate +config SND_SOC_CS42XX8_I2C +	tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)" +	depends on I2C +	select SND_SOC_CS42XX8 +	select REGMAP_I2C +  config SND_SOC_CX20442  	tristate  	depends on TTY @@ -281,6 +393,9 @@ config SND_SOC_BT_SCO  config SND_SOC_DMIC  	tristate +config SND_SOC_HDMI_CODEC +       tristate "HDMI stub CODEC" +  config SND_SOC_ISABELLE          tristate @@ -299,27 +414,60 @@ config SND_SOC_MAX98095  config SND_SOC_MAX9850  	tristate -config SND_SOC_HDMI_CODEC -       tristate -  config SND_SOC_PCM1681 -       tristate +	tristate "Texas Instruments PCM1681 CODEC" +	depends on I2C  config SND_SOC_PCM1792A -       tristate +	tristate "Texas Instruments PCM1792A CODEC" +	depends on SPI_MASTER  config SND_SOC_PCM3008         tristate +config SND_SOC_PCM512x +	tristate + +config SND_SOC_PCM512x_I2C +	tristate "Texas Instruments PCM512x CODECs - I2C" +	depends on I2C +	select SND_SOC_PCM512x +	select REGMAP_I2C + +config SND_SOC_PCM512x_SPI +	tristate "Texas Instruments PCM512x CODECs - SPI" +	depends on SPI_MASTER +	select SND_SOC_PCM512x +	select REGMAP_SPI + +config SND_SOC_RL6231 +	tristate +	default y if SND_SOC_RT5640=y +	default y if SND_SOC_RT5645=y +	default y if SND_SOC_RT5651=y +	default m if SND_SOC_RT5640=m +	default m if SND_SOC_RT5645=m +	default m if SND_SOC_RT5651=m +  config SND_SOC_RT5631  	tristate  config SND_SOC_RT5640  	tristate +config SND_SOC_RT5645 +        tristate + +config SND_SOC_RT5651 +	tristate + +config SND_SOC_RT5677 +	tristate +  #Freescale sgtl5000 codec  config SND_SOC_SGTL5000 -	tristate +	tristate "Freescale SGTL5000 CODEC" +	depends on I2C  config SND_SOC_SI476X  	tristate @@ -328,11 +476,23 @@ config SND_SOC_SIGMADSP  	tristate  	select CRC32 +config SND_SOC_SIGMADSP_I2C +	tristate +	select SND_SOC_SIGMADSP + +config SND_SOC_SIGMADSP_REGMAP +	tristate +	select SND_SOC_SIGMADSP + +config SND_SOC_SIRF_AUDIO_CODEC +	tristate "SiRF SoC internal audio codec" +	select REGMAP_MMIO +  config SND_SOC_SN95031  	tristate  config SND_SOC_SPDIF -	tristate +	tristate "S/PDIF CODEC"  config SND_SOC_SSM2518  	tristate @@ -340,9 +500,21 @@ config SND_SOC_SSM2518  config SND_SOC_SSM2602  	tristate +config SND_SOC_SSM2602_SPI +	select SND_SOC_SSM2602 +	tristate + +config SND_SOC_SSM2602_I2C +	select SND_SOC_SSM2602 +	tristate +  config SND_SOC_STA32X  	tristate +config SND_SOC_STA350 +	tristate "STA350 speaker amplifier" +	depends on I2C +  config SND_SOC_STA529  	tristate @@ -350,20 +522,33 @@ config SND_SOC_STAC9766  	tristate  config SND_SOC_TAS5086 -	tristate +	tristate "Texas Instruments TAS5086 speaker amplifier" +	depends on I2C  config SND_SOC_TLV320AIC23  	tristate +config SND_SOC_TLV320AIC23_I2C +	tristate +	select SND_SOC_TLV320AIC23 + +config SND_SOC_TLV320AIC23_SPI +	tristate +	select SND_SOC_TLV320AIC23 +  config SND_SOC_TLV320AIC26  	tristate  	depends on SPI +config SND_SOC_TLV320AIC31XX +        tristate +  config SND_SOC_TLV320AIC32X4  	tristate  config SND_SOC_TLV320AIC3X -	tristate +	tristate "Texas Instruments TLV320AIC3x CODECs" +	depends on I2C  config SND_SOC_TLV320DAC33  	tristate @@ -412,55 +597,69 @@ config SND_SOC_WM8400  	tristate  config SND_SOC_WM8510 -	tristate +	tristate "Wolfson Microelectronics WM8510 CODEC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8523 -	tristate +	tristate "Wolfson Microelectronics WM8523 DAC" +	depends on I2C  config SND_SOC_WM8580 -	tristate +	tristate "Wolfson Microelectronics WM8523 CODEC" +	depends on I2C  config SND_SOC_WM8711 -	tristate +	tristate "Wolfson Microelectronics WM8711 CODEC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8727  	tristate  config SND_SOC_WM8728 -	tristate +	tristate "Wolfson Microelectronics WM8728 DAC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8731 -	tristate +	tristate "Wolfson Microelectronics WM8731 CODEC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8737 -	tristate +	tristate "Wolfson Microelectronics WM8737 ADC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8741 -	tristate +	tristate "Wolfson Microelectronics WM8737 DAC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8750 -	tristate +	tristate "Wolfson Microelectronics WM8750 CODEC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8753 -	tristate +	tristate "Wolfson Microelectronics WM8753 CODEC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8770 -	tristate +	tristate "Wolfson Microelectronics WM8770 CODEC" +	depends on SPI_MASTER  config SND_SOC_WM8776 -	tristate +	tristate "Wolfson Microelectronics WM8776 CODEC" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8782  	tristate  config SND_SOC_WM8804 -	tristate +	tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver" +	depends on SND_SOC_I2C_AND_SPI  config SND_SOC_WM8900  	tristate  config SND_SOC_WM8903 -	tristate +	tristate "Wolfson Microelectronics WM8903 CODEC" +	depends on I2C  config SND_SOC_WM8904  	tristate @@ -478,7 +677,8 @@ config SND_SOC_WM8961  	tristate  config SND_SOC_WM8962 -	tristate +	tristate "Wolfson Microelectronics WM8962 CODEC" +	depends on I2C && INPUT  config SND_SOC_WM8971  	tristate @@ -551,4 +751,7 @@ config SND_SOC_ML26124  	tristate  config SND_SOC_TPA6130A2 -	tristate +	tristate "Texas Instruments TPA6130A2 headphone amplifier" +	depends on I2C + +endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bc126764a44..1bd6e1cf6f8 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,11 +3,25 @@ snd-soc-ab8500-codec-objs := ab8500-codec.o  snd-soc-ac97-objs := ac97.o  snd-soc-ad1836-objs := ad1836.o  snd-soc-ad193x-objs := ad193x.o +snd-soc-ad193x-spi-objs := ad193x-spi.o +snd-soc-ad193x-i2c-objs := ad193x-i2c.o  snd-soc-ad1980-objs := ad1980.o  snd-soc-ad73311-objs := ad73311.o -snd-soc-adau1701-objs := adau1701.o  snd-soc-adau1373-objs := adau1373.o +snd-soc-adau1701-objs := adau1701.o +snd-soc-adau17x1-objs := adau17x1.o +snd-soc-adau1761-objs := adau1761.o +snd-soc-adau1761-i2c-objs := adau1761-i2c.o +snd-soc-adau1761-spi-objs := adau1761-spi.o +snd-soc-adau1781-objs := adau1781.o +snd-soc-adau1781-i2c-objs := adau1781-i2c.o +snd-soc-adau1781-spi-objs := adau1781-spi.o +snd-soc-adau1977-objs := adau1977.o +snd-soc-adau1977-spi-objs := adau1977-spi.o +snd-soc-adau1977-i2c-objs := adau1977-i2c.o  snd-soc-adav80x-objs := adav80x.o +snd-soc-adav801-objs := adav801.o +snd-soc-adav803-objs := adav803.o  snd-soc-ads117x-objs := ads117x.o  snd-soc-ak4104-objs := ak4104.o  snd-soc-ak4535-objs := ak4535.o @@ -19,10 +33,14 @@ snd-soc-ak5386-objs := ak5386.o  snd-soc-arizona-objs := arizona.o  snd-soc-cq93vc-objs := cq93vc.o  snd-soc-cs42l51-objs := cs42l51.o +snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o  snd-soc-cs42l52-objs := cs42l52.o +snd-soc-cs42l56-objs := cs42l56.o  snd-soc-cs42l73-objs := cs42l73.o  snd-soc-cs4270-objs := cs4270.o  snd-soc-cs4271-objs := cs4271.o +snd-soc-cs42xx8-objs := cs42xx8.o +snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o  snd-soc-cx20442-objs := cx20442.o  snd-soc-da7210-objs := da7210.o  snd-soc-da7213-objs := da7213.o @@ -46,26 +64,42 @@ snd-soc-hdmi-codec-objs := hdmi.o  snd-soc-pcm1681-objs := pcm1681.o  snd-soc-pcm1792a-codec-objs := pcm1792a.o  snd-soc-pcm3008-objs := pcm3008.o +snd-soc-pcm512x-objs := pcm512x.o +snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o +snd-soc-pcm512x-spi-objs := pcm512x-spi.o +snd-soc-rl6231-objs := rl6231.o  snd-soc-rt5631-objs := rt5631.o  snd-soc-rt5640-objs := rt5640.o +snd-soc-rt5645-objs := rt5645.o +snd-soc-rt5651-objs := rt5651.o +snd-soc-rt5677-objs := rt5677.o  snd-soc-sgtl5000-objs := sgtl5000.o  snd-soc-alc5623-objs := alc5623.o  snd-soc-alc5632-objs := alc5632.o  snd-soc-sigmadsp-objs := sigmadsp.o +snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o +snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o  snd-soc-si476x-objs := si476x.o +snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o  snd-soc-sn95031-objs := sn95031.o  snd-soc-spdif-tx-objs := spdif_transmitter.o  snd-soc-spdif-rx-objs := spdif_receiver.o  snd-soc-ssm2518-objs := ssm2518.o  snd-soc-ssm2602-objs := ssm2602.o +snd-soc-ssm2602-spi-objs := ssm2602-spi.o +snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o  snd-soc-sta32x-objs := sta32x.o +snd-soc-sta350-objs := sta350.o  snd-soc-sta529-objs := sta529.o  snd-soc-stac9766-objs := stac9766.o  snd-soc-tas5086-objs := tas5086.o  snd-soc-tlv320aic23-objs := tlv320aic23.o +snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o +snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o  snd-soc-tlv320aic26-objs := tlv320aic26.o -snd-soc-tlv320aic3x-objs := tlv320aic3x.o +snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o  snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o +snd-soc-tlv320aic3x-objs := tlv320aic3x.o  snd-soc-tlv320dac33-objs := tlv320dac33.o  snd-soc-twl4030-objs := twl4030.o  snd-soc-twl6040-objs := twl6040.o @@ -134,11 +168,25 @@ obj-$(CONFIG_SND_SOC_AB8500_CODEC)	+= snd-soc-ab8500-codec.o  obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o  obj-$(CONFIG_SND_SOC_AD1836)	+= snd-soc-ad1836.o  obj-$(CONFIG_SND_SOC_AD193X)	+= snd-soc-ad193x.o +obj-$(CONFIG_SND_SOC_AD193X_SPI)	+= snd-soc-ad193x-spi.o +obj-$(CONFIG_SND_SOC_AD193X_I2C)	+= snd-soc-ad193x-i2c.o  obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o  obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o  obj-$(CONFIG_SND_SOC_ADAU1373)	+= snd-soc-adau1373.o -obj-$(CONFIG_SND_SOC_ADAU1701)  += snd-soc-adau1701.o +obj-$(CONFIG_SND_SOC_ADAU1701)		+= snd-soc-adau1701.o +obj-$(CONFIG_SND_SOC_ADAU17X1)		+= snd-soc-adau17x1.o +obj-$(CONFIG_SND_SOC_ADAU1761)		+= snd-soc-adau1761.o +obj-$(CONFIG_SND_SOC_ADAU1761_I2C)	+= snd-soc-adau1761-i2c.o +obj-$(CONFIG_SND_SOC_ADAU1761_SPI)	+= snd-soc-adau1761-spi.o +obj-$(CONFIG_SND_SOC_ADAU1781)		+= snd-soc-adau1781.o +obj-$(CONFIG_SND_SOC_ADAU1781_I2C)	+= snd-soc-adau1781-i2c.o +obj-$(CONFIG_SND_SOC_ADAU1781_SPI)	+= snd-soc-adau1781-spi.o +obj-$(CONFIG_SND_SOC_ADAU1977)		+= snd-soc-adau1977.o +obj-$(CONFIG_SND_SOC_ADAU1977_SPI)	+= snd-soc-adau1977-spi.o +obj-$(CONFIG_SND_SOC_ADAU1977_I2C)	+= snd-soc-adau1977-i2c.o  obj-$(CONFIG_SND_SOC_ADAV80X)  += snd-soc-adav80x.o +obj-$(CONFIG_SND_SOC_ADAV801)  += snd-soc-adav801.o +obj-$(CONFIG_SND_SOC_ADAV803)  += snd-soc-adav803.o  obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o  obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o  obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o @@ -152,10 +200,14 @@ obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o  obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o  obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o  obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o +obj-$(CONFIG_SND_SOC_CS42L51_I2C)	+= snd-soc-cs42l51-i2c.o  obj-$(CONFIG_SND_SOC_CS42L52)	+= snd-soc-cs42l52.o +obj-$(CONFIG_SND_SOC_CS42L56)	+= snd-soc-cs42l56.o  obj-$(CONFIG_SND_SOC_CS42L73)	+= snd-soc-cs42l73.o  obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o  obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o +obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o +obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o  obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o  obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o  obj-$(CONFIG_SND_SOC_DA7213)	+= snd-soc-da7213.o @@ -179,23 +231,38 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o  obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o  obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o  obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_PCM512x)	+= snd-soc-pcm512x.o +obj-$(CONFIG_SND_SOC_PCM512x_I2C)	+= snd-soc-pcm512x-i2c.o +obj-$(CONFIG_SND_SOC_PCM512x_SPI)	+= snd-soc-pcm512x-spi.o +obj-$(CONFIG_SND_SOC_RL6231)	+= snd-soc-rl6231.o  obj-$(CONFIG_SND_SOC_RT5631)	+= snd-soc-rt5631.o  obj-$(CONFIG_SND_SOC_RT5640)	+= snd-soc-rt5640.o +obj-$(CONFIG_SND_SOC_RT5645)	+= snd-soc-rt5645.o +obj-$(CONFIG_SND_SOC_RT5651)	+= snd-soc-rt5651.o +obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o  obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o  obj-$(CONFIG_SND_SOC_SIGMADSP)	+= snd-soc-sigmadsp.o +obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)	+= snd-soc-sigmadsp-i2c.o +obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP)	+= snd-soc-sigmadsp-regmap.o  obj-$(CONFIG_SND_SOC_SI476X)	+= snd-soc-si476x.o  obj-$(CONFIG_SND_SOC_SN95031)	+=snd-soc-sn95031.o  obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif-rx.o snd-soc-spdif-tx.o  obj-$(CONFIG_SND_SOC_SSM2518)	+= snd-soc-ssm2518.o  obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o +obj-$(CONFIG_SND_SOC_SSM2602_SPI)	+= snd-soc-ssm2602-spi.o +obj-$(CONFIG_SND_SOC_SSM2602_I2C)	+= snd-soc-ssm2602-i2c.o  obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o +obj-$(CONFIG_SND_SOC_STA350)   += snd-soc-sta350.o  obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o  obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o  obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o  obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o +obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)	+= snd-soc-tlv320aic23-i2c.o +obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)	+= snd-soc-tlv320aic23-spi.o  obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o -obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o +obj-$(CONFIG_SND_SOC_TLV320AIC31XX)     += snd-soc-tlv320aic31xx.o  obj-$(CONFIG_SND_SOC_TLV320AIC32X4)     += snd-soc-tlv320aic32x4.o +obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o  obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o  obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o  obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index b8ba0adacfc..1fb4402bf72 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -1139,7 +1139,7 @@ static void anc_configure(struct snd_soc_codec *codec,  static int sid_status_control_get(struct snd_kcontrol *kcontrol,  		struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);  	mutex_lock(&codec->mutex); @@ -1153,7 +1153,7 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,  static int sid_status_control_put(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);  	unsigned int param, sidconf, val;  	int status = 1; @@ -1208,7 +1208,7 @@ out:  static int anc_status_control_get(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);  	mutex_lock(&codec->mutex); @@ -1221,17 +1221,22 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,  static int anc_status_control_put(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);  	struct device *dev = codec->dev;  	bool apply_fir, apply_iir; -	int req, status; +	unsigned int req; +	int status;  	dev_dbg(dev, "%s: Enter.\n", __func__);  	mutex_lock(&drvdata->anc_lock);  	req = ucontrol->value.integer.value[0]; +	if (req >= ARRAY_SIZE(enum_anc_state)) { +		status = -EINVAL; +		goto cleanup; +	}  	if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&  		req != ANC_APPLY_IIR) {  		dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n", @@ -1301,7 +1306,7 @@ static int filter_control_info(struct snd_kcontrol *kcontrol,  static int filter_control_get(struct snd_kcontrol *kcontrol,  			struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct filter_control *fc =  			(struct filter_control *)kcontrol->private_value;  	unsigned int i; @@ -1317,7 +1322,7 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,  static int filter_control_put(struct snd_kcontrol *kcontrol,  		struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct filter_control *fc =  			(struct filter_control *)kcontrol->private_value;  	unsigned int i; @@ -2307,17 +2312,17 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,  	case 0:  		break;  	case 1: -		slot = find_first_bit((unsigned long *)&tx_mask, 32); +		slot = ffs(tx_mask);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);  		break;  	case 2: -		slot = find_first_bit((unsigned long *)&tx_mask, 32); +		slot = ffs(tx_mask);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot); -		slot = find_next_bit((unsigned long *)&tx_mask, 32, slot + 1); +		slot = fls(tx_mask);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);  		snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);  		break; @@ -2348,18 +2353,18 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,  	case 0:  		break;  	case 1: -		slot = find_first_bit((unsigned long *)&rx_mask, 32); +		slot = ffs(rx_mask);  		snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot),  				AB8500_MASK_SLOT(slot),  				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));  		break;  	case 2: -		slot = find_first_bit((unsigned long *)&rx_mask, 32); +		slot = ffs(rx_mask);  		snd_soc_update_bits(codec,  				AB8500_ADSLOTSEL(slot),  				AB8500_MASK_SLOT(slot),  				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot)); -		slot = find_next_bit((unsigned long *)&rx_mask, 32, slot + 1); +		slot = fls(rx_mask);  		snd_soc_update_bits(codec,  				AB8500_ADSLOTSEL(slot),  				AB8500_MASK_SLOT(slot), @@ -2527,12 +2532,10 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)  	}  	/* Override HW-defaults */ -	ab8500_codec_write_reg(codec, -				AB8500_ANACONF5, -				BIT(AB8500_ANACONF5_HSAUTOEN)); -	ab8500_codec_write_reg(codec, -				AB8500_SHORTCIRCONF, -				BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); +	snd_soc_write(codec, AB8500_ANACONF5, +		      BIT(AB8500_ANACONF5_HSAUTOEN)); +	snd_soc_write(codec, AB8500_SHORTCIRCONF, +		      BIT(AB8500_SHORTCIRCONF_HSZCDDIS));  	/* Add filter controls */  	status = snd_soc_add_codec_controls(codec, ab8500_filter_controls, @@ -2583,6 +2586,8 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)  	/* Create driver private-data struct */  	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata),  			GFP_KERNEL); +	if (!drvdata) +		return -ENOMEM;  	drvdata->sid_status = SID_UNCONFIGURED;  	drvdata->anc_status = ANC_UNCONFIGURED;  	dev_set_drvdata(&pdev->dev, drvdata); @@ -2601,7 +2606,7 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)  static int ab8500_codec_driver_remove(struct platform_device *pdev)  { -	dev_info(&pdev->dev, "%s Enter.\n", __func__); +	dev_dbg(&pdev->dev, "%s Enter.\n", __func__);  	snd_soc_unregister_codec(&pdev->dev); diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 9a92b7962f4..685998dd086 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -40,8 +40,8 @@ struct ad1836_priv {   */  static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; -static const struct soc_enum ad1836_deemp_enum = -	SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); +static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum, +			    AD1836_DAC_CTRL1, 8, ad1836_deemp);  #define AD1836_DAC_VOLUME(x) \  	SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ @@ -168,17 +168,19 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,  	int word_len = 0;  	/* bit size */ -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		word_len = AD1836_WORD_LEN_16;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		word_len = AD1836_WORD_LEN_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: -	case SNDRV_PCM_FORMAT_S32_LE: +	case 24: +	case 32:  		word_len = AD1836_WORD_LEN_24;  		break; +	default: +		return -EINVAL;  	}  	regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1, diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c new file mode 100644 index 00000000000..df3a1a41582 --- /dev/null +++ b/sound/soc/codecs/ad193x-i2c.c @@ -0,0 +1,54 @@ +/* + * AD1936/AD1937 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "ad193x.h" + +static const struct i2c_device_id ad193x_id[] = { +	{ "ad1936", 0 }, +	{ "ad1937", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, ad193x_id); + +static int ad193x_i2c_probe(struct i2c_client *client, +			    const struct i2c_device_id *id) +{ +	struct regmap_config config; + +	config = ad193x_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 8; + +	return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config)); +} + +static int ad193x_i2c_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static struct i2c_driver ad193x_i2c_driver = { +	.driver = { +		.name = "ad193x", +	}, +	.probe    = ad193x_i2c_probe, +	.remove   = ad193x_i2c_remove, +	.id_table = ad193x_id, +}; +module_i2c_driver(ad193x_i2c_driver); + +MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c new file mode 100644 index 00000000000..390cef9b9dc --- /dev/null +++ b/sound/soc/codecs/ad193x-spi.c @@ -0,0 +1,48 @@ +/* + * AD1938/AD1939 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "ad193x.h" + +static int ad193x_spi_probe(struct spi_device *spi) +{ +	struct regmap_config config; + +	config = ad193x_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 16; +	config.read_flag_mask = 0x09; +	config.write_flag_mask = 0x08; + +	return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); +} + +static int ad193x_spi_remove(struct spi_device *spi) +{ +	snd_soc_unregister_codec(&spi->dev); +	return 0; +} + +static struct spi_driver ad193x_spi_driver = { +	.driver = { +		.name	= "ad193x", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad193x_spi_probe, +	.remove		= ad193x_spi_remove, +}; +module_spi_driver(ad193x_spi_driver); + +MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index aea7e52cf71..6844d0b2af6 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -6,12 +6,10 @@   * Licensed under the GPL-2 or later.   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/device.h> -#include <linux/i2c.h> -#include <linux/spi/spi.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -19,6 +17,7 @@  #include <sound/initval.h>  #include <sound/soc.h>  #include <sound/tlv.h> +  #include "ad193x.h"  /* codec private data */ @@ -32,8 +31,8 @@ struct ad193x_priv {   */  static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; -static const struct soc_enum ad193x_deemp_enum = -	SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp); +static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1, +			    ad193x_deemp);  static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); @@ -249,15 +248,15 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,  	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);  	/* bit size */ -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		word_len = 3;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		word_len = 1;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: -	case SNDRV_PCM_FORMAT_S32_LE: +	case 24: +	case 32:  		word_len = 0;  		break;  	} @@ -320,17 +319,9 @@ static struct snd_soc_dai_driver ad193x_dai = {  	.ops = &ad193x_dai_ops,  }; -static int ad193x_probe(struct snd_soc_codec *codec) +static int ad193x_codec_probe(struct snd_soc_codec *codec)  {  	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = ad193x->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); -		return ret; -	}  	/* default setting for ad193x */ @@ -348,11 +339,11 @@ static int ad193x_probe(struct snd_soc_codec *codec)  	regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */  	regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04); -	return ret; +	return 0;  }  static struct snd_soc_codec_driver soc_codec_dev_ad193x = { -	.probe = 	ad193x_probe, +	.probe = ad193x_codec_probe,  	.controls = ad193x_snd_controls,  	.num_controls = ARRAY_SIZE(ad193x_snd_controls),  	.dapm_widgets = ad193x_dapm_widgets, @@ -366,140 +357,31 @@ static bool adau193x_reg_volatile(struct device *dev, unsigned int reg)  	return false;  } -#if defined(CONFIG_SPI_MASTER) - -static const struct regmap_config ad193x_spi_regmap_config = { -	.val_bits = 8, -	.reg_bits = 16, -	.read_flag_mask = 0x09, -	.write_flag_mask = 0x08, - +const struct regmap_config ad193x_regmap_config = {  	.max_register = AD193X_NUM_REGS - 1,  	.volatile_reg = adau193x_reg_volatile,  }; +EXPORT_SYMBOL_GPL(ad193x_regmap_config); -static int ad193x_spi_probe(struct spi_device *spi) +int ad193x_probe(struct device *dev, struct regmap *regmap)  {  	struct ad193x_priv *ad193x; -	ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv), -			      GFP_KERNEL); -	if (ad193x == NULL) -		return -ENOMEM; - -	ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config); -	if (IS_ERR(ad193x->regmap)) -		return PTR_ERR(ad193x->regmap); - -	spi_set_drvdata(spi, ad193x); - -	return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x, -			&ad193x_dai, 1); -} +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); -static int ad193x_spi_remove(struct spi_device *spi) -{ -	snd_soc_unregister_codec(&spi->dev); -	return 0; -} - -static struct spi_driver ad193x_spi_driver = { -	.driver = { -		.name	= "ad193x", -		.owner	= THIS_MODULE, -	}, -	.probe		= ad193x_spi_probe, -	.remove		= ad193x_spi_remove, -}; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -static const struct regmap_config ad193x_i2c_regmap_config = { -	.val_bits = 8, -	.reg_bits = 8, - -	.max_register = AD193X_NUM_REGS - 1, -	.volatile_reg = adau193x_reg_volatile, -}; - -static const struct i2c_device_id ad193x_id[] = { -	{ "ad1936", 0 }, -	{ "ad1937", 0 }, -	{ } -}; -MODULE_DEVICE_TABLE(i2c, ad193x_id); - -static int ad193x_i2c_probe(struct i2c_client *client, -			    const struct i2c_device_id *id) -{ -	struct ad193x_priv *ad193x; - -	ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv), -			      GFP_KERNEL); +	ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);  	if (ad193x == NULL)  		return -ENOMEM; -	ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config); -	if (IS_ERR(ad193x->regmap)) -		return PTR_ERR(ad193x->regmap); - -	i2c_set_clientdata(client, ad193x); - -	return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x, -			&ad193x_dai, 1); -} - -static int ad193x_i2c_remove(struct i2c_client *client) -{ -	snd_soc_unregister_codec(&client->dev); -	return 0; -} - -static struct i2c_driver ad193x_i2c_driver = { -	.driver = { -		.name = "ad193x", -	}, -	.probe    = ad193x_i2c_probe, -	.remove   = ad193x_i2c_remove, -	.id_table = ad193x_id, -}; -#endif - -static int __init ad193x_modinit(void) -{ -	int ret; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	ret =  i2c_add_driver(&ad193x_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n", -				ret); -	} -#endif - -#if defined(CONFIG_SPI_MASTER) -	ret = spi_register_driver(&ad193x_spi_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n", -				ret); -	} -#endif -	return ret; -} -module_init(ad193x_modinit); +	ad193x->regmap = regmap; -static void __exit ad193x_modexit(void) -{ -#if defined(CONFIG_SPI_MASTER) -	spi_unregister_driver(&ad193x_spi_driver); -#endif +	dev_set_drvdata(dev, ad193x); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	i2c_del_driver(&ad193x_i2c_driver); -#endif +	return snd_soc_register_codec(dev, &soc_codec_dev_ad193x, +		&ad193x_dai, 1);  } -module_exit(ad193x_modexit); +EXPORT_SYMBOL_GPL(ad193x_probe);  MODULE_DESCRIPTION("ASoC ad193x driver");  MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index 47338804999..ab9a998f15b 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h @@ -9,6 +9,13 @@  #ifndef __AD193X_H__  #define __AD193X_H__ +#include <linux/regmap.h> + +struct device; + +extern const struct regmap_config ad193x_regmap_config; +int ad193x_probe(struct device *dev, struct regmap *regmap); +  #define AD193X_PLL_CLK_CTRL0    0x00  #define AD193X_PLL_POWERDOWN           0x01  #define AD193X_PLL_INPUT_MASK   0x6 diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 7257a8885f4..304d3003339 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -57,8 +57,8 @@ static const u16 ad1980_reg[] = {  static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",  		"Stereo Mix", "Mono Mix", "Phone"}; -static const struct soc_enum ad1980_cap_src = -	SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel); +static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src, +			    AC97_REC_SEL, 8, 0, ad1980_rec_sel);  static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {  SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), @@ -189,28 +189,27 @@ static struct snd_soc_dai_driver ad1980_dai = {  static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)  { -	u16 retry_cnt = 0; +	unsigned int retry_cnt = 0; -retry: -	if (try_warm && soc_ac97_ops->warm_reset) { -		soc_ac97_ops->warm_reset(codec->ac97); -		if (ac97_read(codec, AC97_RESET) == 0x0090) -			return 1; -	} - -	soc_ac97_ops->reset(codec->ac97); -	/* Set bit 16slot in register 74h, then every slot will has only 16 -	 * bits. This command is sent out in 20bit mode, in which case the -	 * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ -	ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); - -	if (ac97_read(codec, AC97_RESET)  != 0x0090) -		goto err; -	return 0; +	do { +		if (try_warm && soc_ac97_ops->warm_reset) { +			soc_ac97_ops->warm_reset(codec->ac97); +			if (ac97_read(codec, AC97_RESET) == 0x0090) +				return 1; +		} -err: -	while (retry_cnt++ < 10) -		goto retry; +		soc_ac97_ops->reset(codec->ac97); +		/* +		 * Set bit 16slot in register 74h, then every slot will has only +		 * 16 bits. This command is sent out in 20bit mode, in which +		 * case the first nibble of data is eaten by the addr. (Tag is +		 * always 16 bit) +		 */ +		ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); + +		if (ac97_read(codec, AC97_RESET)  == 0x0090) +			return 0; +	} while (retry_cnt++ < 10);  	printk(KERN_ERR "AD1980 AC97 reset failed\n");  	return -EIO; diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 1aa10ddf3a6..1ff7d4d027e 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -32,6 +32,7 @@ struct adau1373_dai {  };  struct adau1373 { +	struct regmap *regmap;  	struct adau1373_dai dais[3];  }; @@ -73,7 +74,6 @@ struct adau1373 {  #define ADAU1373_PLL_CTRL4(x)	(0x2c + (x) * 7)  #define ADAU1373_PLL_CTRL5(x)	(0x2d + (x) * 7)  #define ADAU1373_PLL_CTRL6(x)	(0x2e + (x) * 7) -#define ADAU1373_PLL_CTRL7(x)	(0x2f + (x) * 7)  #define ADAU1373_HEADDECT	0x36  #define ADAU1373_ADC_DAC_STATUS	0x37  #define ADAU1373_ADC_CTRL	0x3c @@ -152,37 +152,172 @@ struct adau1373 {  #define ADAU1373_EP_CTRL_MICBIAS1_OFFSET 4  #define ADAU1373_EP_CTRL_MICBIAS2_OFFSET 2 -static const uint8_t adau1373_default_regs[] = { -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x30 */ -	0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, /* 0x40 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x80 */ -	0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, -	0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x90 */ -	0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, -	0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0xa0 */ -	0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, -	0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */ -	0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */ -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, /* 0xe0 */ -	0x00, 0x1f, 0x0f, 0x00, 0x00, +static const struct reg_default adau1373_reg_defaults[] = { +	{ ADAU1373_INPUT_MODE,		0x00 }, +	{ ADAU1373_AINL_CTRL(0),	0x00 }, +	{ ADAU1373_AINR_CTRL(0),	0x00 }, +	{ ADAU1373_AINL_CTRL(1),	0x00 }, +	{ ADAU1373_AINR_CTRL(1),	0x00 }, +	{ ADAU1373_AINL_CTRL(2),	0x00 }, +	{ ADAU1373_AINR_CTRL(2),	0x00 }, +	{ ADAU1373_AINL_CTRL(3),	0x00 }, +	{ ADAU1373_AINR_CTRL(3),	0x00 }, +	{ ADAU1373_LLINE_OUT(0),	0x00 }, +	{ ADAU1373_RLINE_OUT(0),	0x00 }, +	{ ADAU1373_LLINE_OUT(1),	0x00 }, +	{ ADAU1373_RLINE_OUT(1),	0x00 }, +	{ ADAU1373_LSPK_OUT,		0x00 }, +	{ ADAU1373_RSPK_OUT,		0x00 }, +	{ ADAU1373_LHP_OUT,		0x00 }, +	{ ADAU1373_RHP_OUT,		0x00 }, +	{ ADAU1373_ADC_GAIN,		0x00 }, +	{ ADAU1373_LADC_MIXER,		0x00 }, +	{ ADAU1373_RADC_MIXER,		0x00 }, +	{ ADAU1373_LLINE1_MIX,		0x00 }, +	{ ADAU1373_RLINE1_MIX,		0x00 }, +	{ ADAU1373_LLINE2_MIX,		0x00 }, +	{ ADAU1373_RLINE2_MIX,		0x00 }, +	{ ADAU1373_LSPK_MIX,		0x00 }, +	{ ADAU1373_RSPK_MIX,		0x00 }, +	{ ADAU1373_LHP_MIX,		0x00 }, +	{ ADAU1373_RHP_MIX,		0x00 }, +	{ ADAU1373_EP_MIX,		0x00 }, +	{ ADAU1373_HP_CTRL,		0x00 }, +	{ ADAU1373_HP_CTRL2,		0x00 }, +	{ ADAU1373_LS_CTRL,		0x00 }, +	{ ADAU1373_EP_CTRL,		0x00 }, +	{ ADAU1373_MICBIAS_CTRL1,	0x00 }, +	{ ADAU1373_MICBIAS_CTRL2,	0x00 }, +	{ ADAU1373_OUTPUT_CTRL,		0x00 }, +	{ ADAU1373_PWDN_CTRL1,		0x00 }, +	{ ADAU1373_PWDN_CTRL2,		0x00 }, +	{ ADAU1373_PWDN_CTRL3,		0x00 }, +	{ ADAU1373_DPLL_CTRL(0),	0x00 }, +	{ ADAU1373_PLL_CTRL1(0),	0x00 }, +	{ ADAU1373_PLL_CTRL2(0),	0x00 }, +	{ ADAU1373_PLL_CTRL3(0),	0x00 }, +	{ ADAU1373_PLL_CTRL4(0),	0x00 }, +	{ ADAU1373_PLL_CTRL5(0),	0x00 }, +	{ ADAU1373_PLL_CTRL6(0),	0x02 }, +	{ ADAU1373_DPLL_CTRL(1),	0x00 }, +	{ ADAU1373_PLL_CTRL1(1),	0x00 }, +	{ ADAU1373_PLL_CTRL2(1),	0x00 }, +	{ ADAU1373_PLL_CTRL3(1),	0x00 }, +	{ ADAU1373_PLL_CTRL4(1),	0x00 }, +	{ ADAU1373_PLL_CTRL5(1),	0x00 }, +	{ ADAU1373_PLL_CTRL6(1),	0x02 }, +	{ ADAU1373_HEADDECT,		0x00 }, +	{ ADAU1373_ADC_CTRL,		0x00 }, +	{ ADAU1373_CLK_SRC_DIV(0),	0x00 }, +	{ ADAU1373_CLK_SRC_DIV(1),	0x00 }, +	{ ADAU1373_DAI(0),		0x0a }, +	{ ADAU1373_DAI(1),		0x0a }, +	{ ADAU1373_DAI(2),		0x0a }, +	{ ADAU1373_BCLKDIV(0),		0x00 }, +	{ ADAU1373_BCLKDIV(1),		0x00 }, +	{ ADAU1373_BCLKDIV(2),		0x00 }, +	{ ADAU1373_SRC_RATIOA(0),	0x00 }, +	{ ADAU1373_SRC_RATIOB(0),	0x00 }, +	{ ADAU1373_SRC_RATIOA(1),	0x00 }, +	{ ADAU1373_SRC_RATIOB(1),	0x00 }, +	{ ADAU1373_SRC_RATIOA(2),	0x00 }, +	{ ADAU1373_SRC_RATIOB(2),	0x00 }, +	{ ADAU1373_DEEMP_CTRL,		0x00 }, +	{ ADAU1373_SRC_DAI_CTRL(0),	0x08 }, +	{ ADAU1373_SRC_DAI_CTRL(1),	0x08 }, +	{ ADAU1373_SRC_DAI_CTRL(2),	0x08 }, +	{ ADAU1373_DIN_MIX_CTRL(0),	0x00 }, +	{ ADAU1373_DIN_MIX_CTRL(1),	0x00 }, +	{ ADAU1373_DIN_MIX_CTRL(2),	0x00 }, +	{ ADAU1373_DIN_MIX_CTRL(3),	0x00 }, +	{ ADAU1373_DIN_MIX_CTRL(4),	0x00 }, +	{ ADAU1373_DOUT_MIX_CTRL(0),	0x00 }, +	{ ADAU1373_DOUT_MIX_CTRL(1),	0x00 }, +	{ ADAU1373_DOUT_MIX_CTRL(2),	0x00 }, +	{ ADAU1373_DOUT_MIX_CTRL(3),	0x00 }, +	{ ADAU1373_DOUT_MIX_CTRL(4),	0x00 }, +	{ ADAU1373_DAI_PBL_VOL(0),	0x00 }, +	{ ADAU1373_DAI_PBR_VOL(0),	0x00 }, +	{ ADAU1373_DAI_PBL_VOL(1),	0x00 }, +	{ ADAU1373_DAI_PBR_VOL(1),	0x00 }, +	{ ADAU1373_DAI_PBL_VOL(2),	0x00 }, +	{ ADAU1373_DAI_PBR_VOL(2),	0x00 }, +	{ ADAU1373_DAI_RECL_VOL(0),	0x00 }, +	{ ADAU1373_DAI_RECR_VOL(0),	0x00 }, +	{ ADAU1373_DAI_RECL_VOL(1),	0x00 }, +	{ ADAU1373_DAI_RECR_VOL(1),	0x00 }, +	{ ADAU1373_DAI_RECL_VOL(2),	0x00 }, +	{ ADAU1373_DAI_RECR_VOL(2),	0x00 }, +	{ ADAU1373_DAC1_PBL_VOL,	0x00 }, +	{ ADAU1373_DAC1_PBR_VOL,	0x00 }, +	{ ADAU1373_DAC2_PBL_VOL,	0x00 }, +	{ ADAU1373_DAC2_PBR_VOL,	0x00 }, +	{ ADAU1373_ADC_RECL_VOL,	0x00 }, +	{ ADAU1373_ADC_RECR_VOL,	0x00 }, +	{ ADAU1373_DMIC_RECL_VOL,	0x00 }, +	{ ADAU1373_DMIC_RECR_VOL,	0x00 }, +	{ ADAU1373_VOL_GAIN1,		0x00 }, +	{ ADAU1373_VOL_GAIN2,		0x00 }, +	{ ADAU1373_VOL_GAIN3,		0x00 }, +	{ ADAU1373_HPF_CTRL,		0x00 }, +	{ ADAU1373_BASS1,		0x00 }, +	{ ADAU1373_BASS2,		0x00 }, +	{ ADAU1373_DRC(0) + 0x0,	0x78 }, +	{ ADAU1373_DRC(0) + 0x1,	0x18 }, +	{ ADAU1373_DRC(0) + 0x2,	0x00 }, +	{ ADAU1373_DRC(0) + 0x3,	0x00 }, +	{ ADAU1373_DRC(0) + 0x4,	0x00 }, +	{ ADAU1373_DRC(0) + 0x5,	0xc0 }, +	{ ADAU1373_DRC(0) + 0x6,	0x00 }, +	{ ADAU1373_DRC(0) + 0x7,	0x00 }, +	{ ADAU1373_DRC(0) + 0x8,	0x00 }, +	{ ADAU1373_DRC(0) + 0x9,	0xc0 }, +	{ ADAU1373_DRC(0) + 0xa,	0x88 }, +	{ ADAU1373_DRC(0) + 0xb,	0x7a }, +	{ ADAU1373_DRC(0) + 0xc,	0xdf }, +	{ ADAU1373_DRC(0) + 0xd,	0x20 }, +	{ ADAU1373_DRC(0) + 0xe,	0x00 }, +	{ ADAU1373_DRC(0) + 0xf,	0x00 }, +	{ ADAU1373_DRC(1) + 0x0,	0x78 }, +	{ ADAU1373_DRC(1) + 0x1,	0x18 }, +	{ ADAU1373_DRC(1) + 0x2,	0x00 }, +	{ ADAU1373_DRC(1) + 0x3,	0x00 }, +	{ ADAU1373_DRC(1) + 0x4,	0x00 }, +	{ ADAU1373_DRC(1) + 0x5,	0xc0 }, +	{ ADAU1373_DRC(1) + 0x6,	0x00 }, +	{ ADAU1373_DRC(1) + 0x7,	0x00 }, +	{ ADAU1373_DRC(1) + 0x8,	0x00 }, +	{ ADAU1373_DRC(1) + 0x9,	0xc0 }, +	{ ADAU1373_DRC(1) + 0xa,	0x88 }, +	{ ADAU1373_DRC(1) + 0xb,	0x7a }, +	{ ADAU1373_DRC(1) + 0xc,	0xdf }, +	{ ADAU1373_DRC(1) + 0xd,	0x20 }, +	{ ADAU1373_DRC(1) + 0xe,	0x00 }, +	{ ADAU1373_DRC(1) + 0xf,	0x00 }, +	{ ADAU1373_DRC(2) + 0x0,	0x78 }, +	{ ADAU1373_DRC(2) + 0x1,	0x18 }, +	{ ADAU1373_DRC(2) + 0x2,	0x00 }, +	{ ADAU1373_DRC(2) + 0x3,	0x00 }, +	{ ADAU1373_DRC(2) + 0x4,	0x00 }, +	{ ADAU1373_DRC(2) + 0x5,	0xc0 }, +	{ ADAU1373_DRC(2) + 0x6,	0x00 }, +	{ ADAU1373_DRC(2) + 0x7,	0x00 }, +	{ ADAU1373_DRC(2) + 0x8,	0x00 }, +	{ ADAU1373_DRC(2) + 0x9,	0xc0 }, +	{ ADAU1373_DRC(2) + 0xa,	0x88 }, +	{ ADAU1373_DRC(2) + 0xb,	0x7a }, +	{ ADAU1373_DRC(2) + 0xc,	0xdf }, +	{ ADAU1373_DRC(2) + 0xd,	0x20 }, +	{ ADAU1373_DRC(2) + 0xe,	0x00 }, +	{ ADAU1373_DRC(2) + 0xf,	0x00 }, +	{ ADAU1373_3D_CTRL1,		0x00 }, +	{ ADAU1373_3D_CTRL2,		0x00 }, +	{ ADAU1373_FDSP_SEL1,		0x00 }, +	{ ADAU1373_FDSP_SEL2,		0x00 }, +	{ ADAU1373_FDSP_SEL2,		0x00 }, +	{ ADAU1373_FDSP_SEL4,		0x00 }, +	{ ADAU1373_DIGMICCTRL,		0x00 }, +	{ ADAU1373_DIGEN,		0x00 },  };  static const unsigned int adau1373_out_tlv[] = { @@ -210,15 +345,15 @@ static const char *adau1373_fdsp_sel_text[] = {  	"Channel 5",  }; -static const SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum,  	ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum,  	ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum,  	ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum,  	ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum,  	ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text);  static const char *adau1373_hpf_cutoff_text[] = { @@ -227,7 +362,7 @@ static const char *adau1373_hpf_cutoff_text[] = {  	"800Hz",  }; -static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum,  	ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text);  static const char *adau1373_bass_lpf_cutoff_text[] = { @@ -253,14 +388,14 @@ static const unsigned int adau1373_bass_tlv[] = {  	5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0),  }; -static const SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,  	ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text); -static const SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum, +static SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum,  	ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text,  	adau1373_bass_clip_level_values); -static const SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum,  	ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text);  static const char *adau1373_3d_level_text[] = { @@ -274,9 +409,9 @@ static const char *adau1373_3d_cutoff_text[] = {  	"0.16875 fs", "0.27083 fs"  }; -static const SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,  	ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,  	ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text);  static const unsigned int adau1373_3d_tlv[] = { @@ -292,11 +427,11 @@ static const char *adau1373_lr_mux_text[] = {  	"Stereo",  }; -static const SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum,  	ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum,  	ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum,  	ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text);  static const struct snd_kcontrol_new adau1373_controls[] = { @@ -384,8 +519,7 @@ static const struct snd_kcontrol_new adau1373_controls[] = {  	SOC_ENUM("HPF Channel", adau1373_hpf_channel_enum),  	SOC_ENUM("Bass HPF Cutoff", adau1373_bass_hpf_cutoff_enum), -	SOC_VALUE_ENUM("Bass Clip Level Threshold", -	    adau1373_bass_clip_level_enum), +	SOC_ENUM("Bass Clip Level Threshold", adau1373_bass_clip_level_enum),  	SOC_ENUM("Bass LPF Cutoff", adau1373_bass_lpf_cutoff_enum),  	SOC_DOUBLE("Bass Playback Switch", ADAU1373_BASS2, 0, 1, 1, 0),  	SOC_SINGLE_TLV("Bass Playback Volume", ADAU1373_BASS2, 2, 7, 0, @@ -418,6 +552,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w,  	struct snd_kcontrol *kcontrol, int event)  {  	struct snd_soc_codec *codec = w->codec; +	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);  	unsigned int pll_id = w->name[3] - '1';  	unsigned int val; @@ -426,7 +561,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w,  	else  		val = 0; -	snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), +	regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),  		ADAU1373_PLL_CTRL6_PLL_EN, val);  	if (SND_SOC_DAPM_EVENT_ON(event)) @@ -440,11 +575,11 @@ static const char *adau1373_decimator_text[] = {  	"DMIC1",  }; -static const struct soc_enum adau1373_decimator_enum = -	SOC_ENUM_SINGLE(0, 0, 2, adau1373_decimator_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum, +	adau1373_decimator_text);  static const struct snd_kcontrol_new adau1373_decimator_mux = -	SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum); +	SOC_DAPM_ENUM("Decimator Mux", adau1373_decimator_enum);  static const struct snd_kcontrol_new adau1373_left_adc_mixer_controls[] = {  	SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_LADC_MIXER, 4, 1, 0), @@ -558,7 +693,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {  	SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1373_DIGMICCTRL, 0, 0),  	SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1373_DIGMICCTRL, 2, 0), -	SND_SOC_DAPM_VIRT_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0, +	SND_SOC_DAPM_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0,  		&adau1373_decimator_mux),  	SND_SOC_DAPM_SUPPLY("MICBIAS2", ADAU1373_PWDN_CTRL1, 5, 0, NULL, 0), @@ -938,28 +1073,28 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,  	adau1373_dai->enable_src = (div != 0); -	snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id), +	regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),  		ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,  		(div << 2) | ADAU1373_BCLKDIV_64); -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		ctrl = ADAU1373_DAI_WLEN_16;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		ctrl = ADAU1373_DAI_WLEN_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		ctrl = ADAU1373_DAI_WLEN_24;  		break; -	case SNDRV_PCM_FORMAT_S32_LE: +	case 32:  		ctrl = ADAU1373_DAI_WLEN_32;  		break;  	default:  		return -EINVAL;  	} -	return snd_soc_update_bits(codec, ADAU1373_DAI(dai->id), +	return regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),  			ADAU1373_DAI_WLEN_MASK, ctrl);  } @@ -1016,7 +1151,7 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  		return -EINVAL;  	} -	snd_soc_update_bits(codec, ADAU1373_DAI(dai->id), +	regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),  		~ADAU1373_DAI_WLEN_MASK, ctrl);  	return 0; @@ -1039,7 +1174,7 @@ static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai,  	adau1373_dai->sysclk = freq;  	adau1373_dai->clk_src = clk_id; -	snd_soc_update_bits(dai->codec, ADAU1373_BCLKDIV(dai->id), +	regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),  		ADAU1373_BCLKDIV_SOURCE, clk_id << 5);  	return 0; @@ -1120,6 +1255,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {  static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,  	int source, unsigned int freq_in, unsigned int freq_out)  { +	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);  	unsigned int dpll_div = 0;  	unsigned int x, r, n, m, i, j, mode; @@ -1187,36 +1323,36 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,  	if (dpll_div) {  		dpll_div = 11 - dpll_div; -		snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), +		regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),  			ADAU1373_PLL_CTRL6_DPLL_BYPASS, 0);  	} else { -		snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), +		regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),  			ADAU1373_PLL_CTRL6_DPLL_BYPASS,  			ADAU1373_PLL_CTRL6_DPLL_BYPASS);  	} -	snd_soc_write(codec, ADAU1373_DPLL_CTRL(pll_id), +	regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),  		(source << 4) | dpll_div); -	snd_soc_write(codec, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); -	snd_soc_write(codec, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); -	snd_soc_write(codec, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); -	snd_soc_write(codec, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); -	snd_soc_write(codec, ADAU1373_PLL_CTRL5(pll_id), +	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); +	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); +	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); +	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); +	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),  		(r << 3) | (x << 1) | mode);  	/* Set sysclk to pll_rate / 4 */ -	snd_soc_update_bits(codec, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); +	regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);  	return 0;  } -static void adau1373_load_drc_settings(struct snd_soc_codec *codec, +static void adau1373_load_drc_settings(struct adau1373 *adau1373,  	unsigned int nr, uint8_t *drc)  {  	unsigned int i;  	for (i = 0; i < ADAU1373_DRC_SIZE; ++i) -		snd_soc_write(codec, ADAU1373_DRC(nr) + i, drc[i]); +		regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]);  }  static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias) @@ -1235,18 +1371,12 @@ static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)  static int adau1373_probe(struct snd_soc_codec *codec)  { +	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);  	struct adau1373_platform_data *pdata = codec->dev->platform_data;  	bool lineout_differential = false;  	unsigned int val; -	int ret;  	int i; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); -	if (ret) { -		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	if (pdata) {  		if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))  			return -EINVAL; @@ -1256,7 +1386,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)  			return -EINVAL;  		for (i = 0; i < pdata->num_drc; ++i) { -			adau1373_load_drc_settings(codec, i, +			adau1373_load_drc_settings(adau1373, i,  				pdata->drc_setting[i]);  		} @@ -1268,18 +1398,18 @@ static int adau1373_probe(struct snd_soc_codec *codec)  			if (pdata->input_differential[i])  				val |= BIT(i);  		} -		snd_soc_write(codec, ADAU1373_INPUT_MODE, val); +		regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);  		val = 0;  		if (pdata->lineout_differential)  			val |= ADAU1373_OUTPUT_CTRL_LDIFF;  		if (pdata->lineout_ground_sense)  			val |= ADAU1373_OUTPUT_CTRL_LNFBEN; -		snd_soc_write(codec, ADAU1373_OUTPUT_CTRL, val); +		regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);  		lineout_differential = pdata->lineout_differential; -		snd_soc_write(codec, ADAU1373_EP_CTRL, +		regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,  			(pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |  			(pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));  	} @@ -1289,7 +1419,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)  			ARRAY_SIZE(adau1373_lineout2_controls));  	} -	snd_soc_write(codec, ADAU1373_ADC_CTRL, +	regmap_write(adau1373->regmap, ADAU1373_ADC_CTRL,  	    ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT);  	return 0; @@ -1298,17 +1428,19 @@ static int adau1373_probe(struct snd_soc_codec *codec)  static int adau1373_set_bias_level(struct snd_soc_codec *codec,  	enum snd_soc_bias_level level)  { +	struct adau1373 *adau1373 = 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: -		snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3, +		regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,  			ADAU1373_PWDN_CTRL3_PWR_EN, ADAU1373_PWDN_CTRL3_PWR_EN);  		break;  	case SND_SOC_BIAS_OFF: -		snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3, +		regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,  			ADAU1373_PWDN_CTRL3_PWR_EN, 0);  		break;  	} @@ -1324,17 +1456,49 @@ static int adau1373_remove(struct snd_soc_codec *codec)  static int adau1373_suspend(struct snd_soc_codec *codec)  { -	return adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); +	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); +	int ret; + +	ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); +	regcache_cache_only(adau1373->regmap, true); + +	return ret;  }  static int adau1373_resume(struct snd_soc_codec *codec)  { +	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(adau1373->regmap, false);  	adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	snd_soc_cache_sync(codec); +	regcache_sync(adau1373->regmap);  	return 0;  } +static bool adau1373_register_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case ADAU1373_SOFT_RESET: +	case ADAU1373_ADC_DAC_STATUS: +		return true; +	default: +		return false; +	} +} + +static const struct regmap_config adau1373_regmap_config = { +	.val_bits = 8, +	.reg_bits = 8, + +	.volatile_reg = adau1373_register_volatile, +	.max_register = ADAU1373_SOFT_RESET, + +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults = adau1373_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults), +}; +  static struct snd_soc_codec_driver adau1373_codec_driver = {  	.probe =	adau1373_probe,  	.remove =	adau1373_remove, @@ -1342,9 +1506,6 @@ static struct snd_soc_codec_driver adau1373_codec_driver = {  	.resume =	adau1373_resume,  	.set_bias_level = adau1373_set_bias_level,  	.idle_bias_off = true, -	.reg_cache_size = ARRAY_SIZE(adau1373_default_regs), -	.reg_cache_default = adau1373_default_regs, -	.reg_word_size = sizeof(uint8_t),  	.set_pll = adau1373_set_pll, @@ -1366,6 +1527,13 @@ static int adau1373_i2c_probe(struct i2c_client *client,  	if (!adau1373)  		return -ENOMEM; +	adau1373->regmap = devm_regmap_init_i2c(client, +		&adau1373_regmap_config); +	if (IS_ERR(adau1373->regmap)) +		return PTR_ERR(adau1373->regmap); + +	regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00); +  	dev_set_drvdata(&client->dev, adau1373);  	ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver, diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index ebff1128be5..d71c59cf7bd 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -71,7 +71,7 @@  #define ADAU1701_SEROCTL_WORD_LEN_24	0x0000  #define ADAU1701_SEROCTL_WORD_LEN_20	0x0001 -#define ADAU1701_SEROCTL_WORD_LEN_16	0x0010 +#define ADAU1701_SEROCTL_WORD_LEN_16	0x0002  #define ADAU1701_SEROCTL_WORD_LEN_MASK	0x0003  #define ADAU1701_AUXNPOW_VBPD		0x40 @@ -299,20 +299,20 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)  }  static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec, -		snd_pcm_format_t format) +					   struct snd_pcm_hw_params *params)  {  	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);  	unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK;  	unsigned int val; -	switch (format) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		val = ADAU1701_SEROCTL_WORD_LEN_16;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		val = ADAU1701_SEROCTL_WORD_LEN_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		val = ADAU1701_SEROCTL_WORD_LEN_24;  		break;  	default: @@ -320,14 +320,14 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,  	}  	if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) { -		switch (format) { -		case SNDRV_PCM_FORMAT_S16_LE: +		switch (params_width(params)) { +		case 16:  			val |= ADAU1701_SEROCTL_MSB_DEALY16;  			break; -		case SNDRV_PCM_FORMAT_S20_3LE: +		case 20:  			val |= ADAU1701_SEROCTL_MSB_DEALY12;  			break; -		case SNDRV_PCM_FORMAT_S24_LE: +		case 24:  			val |= ADAU1701_SEROCTL_MSB_DEALY8;  			break;  		} @@ -340,7 +340,7 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,  }  static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec, -			snd_pcm_format_t format) +					    struct snd_pcm_hw_params *params)  {  	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);  	unsigned int val; @@ -348,14 +348,14 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,  	if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)  		return 0; -	switch (format) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		val = ADAU1701_SERICTL_RIGHTJ_16;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		val = ADAU1701_SERICTL_RIGHTJ_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		val = ADAU1701_SERICTL_RIGHTJ_24;  		break;  	default: @@ -374,7 +374,6 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,  	struct snd_soc_codec *codec = dai->codec;  	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);  	unsigned int clkdiv = adau1701->sysclk / params_rate(params); -	snd_pcm_format_t format;  	unsigned int val;  	int ret; @@ -406,11 +405,10 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,  	regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,  		ADAU1701_DSPCTRL_SR_MASK, val); -	format = params_format(params);  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -		return adau1701_set_playback_pcm_format(codec, format); +		return adau1701_set_playback_pcm_format(codec, params);  	else -		return adau1701_set_capture_pcm_format(codec, format); +		return adau1701_set_capture_pcm_format(codec, params);  }  static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c new file mode 100644 index 00000000000..862796dec69 --- /dev/null +++ b/sound/soc/codecs/adau1761-i2c.c @@ -0,0 +1,60 @@ +/* + * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "adau1761.h" + +static int adau1761_i2c_probe(struct i2c_client *client, +	const struct i2c_device_id *id) +{ +	struct regmap_config config; + +	config = adau1761_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 16; + +	return adau1761_probe(&client->dev, +		devm_regmap_init_i2c(client, &config), +		id->driver_data, NULL); +} + +static int adau1761_i2c_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static const struct i2c_device_id adau1761_i2c_ids[] = { +	{ "adau1361", ADAU1361 }, +	{ "adau1461", ADAU1761 }, +	{ "adau1761", ADAU1761 }, +	{ "adau1961", ADAU1361 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids); + +static struct i2c_driver adau1761_i2c_driver = { +	.driver = { +		.name = "adau1761", +		.owner = THIS_MODULE, +	}, +	.probe = adau1761_i2c_probe, +	.remove = adau1761_i2c_remove, +	.id_table = adau1761_i2c_ids, +}; +module_i2c_driver(adau1761_i2c_driver); + +MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC I2C driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c new file mode 100644 index 00000000000..cce2f11f1ff --- /dev/null +++ b/sound/soc/codecs/adau1761-spi.c @@ -0,0 +1,77 @@ +/* + * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <sound/soc.h> + +#include "adau1761.h" + +static void adau1761_spi_switch_mode(struct device *dev) +{ +	struct spi_device *spi = to_spi_device(dev); + +	/* +	 * To get the device into SPI mode CLATCH has to be pulled low three +	 * times.  Do this by issuing three dummy reads. +	 */ +	spi_w8r8(spi, 0x00); +	spi_w8r8(spi, 0x00); +	spi_w8r8(spi, 0x00); +} + +static int adau1761_spi_probe(struct spi_device *spi) +{ +	const struct spi_device_id *id = spi_get_device_id(spi); +	struct regmap_config config; + +	if (!id) +		return -EINVAL; + +	config = adau1761_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 24; +	config.read_flag_mask = 0x1; + +	return adau1761_probe(&spi->dev, +		devm_regmap_init_spi(spi, &config), +		id->driver_data, adau1761_spi_switch_mode); +} + +static int adau1761_spi_remove(struct spi_device *spi) +{ +	snd_soc_unregister_codec(&spi->dev); +	return 0; +} + +static const struct spi_device_id adau1761_spi_id[] = { +	{ "adau1361", ADAU1361 }, +	{ "adau1461", ADAU1761 }, +	{ "adau1761", ADAU1761 }, +	{ "adau1961", ADAU1361 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, adau1761_spi_id); + +static struct spi_driver adau1761_spi_driver = { +	.driver = { +		.name = "adau1761", +		.owner = THIS_MODULE, +	}, +	.probe = adau1761_spi_probe, +	.remove = adau1761_spi_remove, +	.id_table = adau1761_spi_id, +}; +module_spi_driver(adau1761_spi_driver); + +MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC SPI driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c new file mode 100644 index 00000000000..848cab83955 --- /dev/null +++ b/sound/soc/codecs/adau1761.c @@ -0,0 +1,803 @@ +/* + * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec + * + * Copyright 2011-2013 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include <linux/platform_data/adau17x1.h> + +#include "adau17x1.h" +#include "adau1761.h" + +#define ADAU1761_DIGMIC_JACKDETECT	0x4008 +#define ADAU1761_REC_MIXER_LEFT0	0x400a +#define ADAU1761_REC_MIXER_LEFT1	0x400b +#define ADAU1761_REC_MIXER_RIGHT0	0x400c +#define ADAU1761_REC_MIXER_RIGHT1	0x400d +#define ADAU1761_LEFT_DIFF_INPUT_VOL	0x400e +#define ADAU1761_RIGHT_DIFF_INPUT_VOL	0x400f +#define ADAU1761_PLAY_LR_MIXER_LEFT	0x4020 +#define ADAU1761_PLAY_MIXER_LEFT0	0x401c +#define ADAU1761_PLAY_MIXER_LEFT1	0x401d +#define ADAU1761_PLAY_MIXER_RIGHT0	0x401e +#define ADAU1761_PLAY_MIXER_RIGHT1	0x401f +#define ADAU1761_PLAY_LR_MIXER_RIGHT	0x4021 +#define ADAU1761_PLAY_MIXER_MONO	0x4022 +#define ADAU1761_PLAY_HP_LEFT_VOL	0x4023 +#define ADAU1761_PLAY_HP_RIGHT_VOL	0x4024 +#define ADAU1761_PLAY_LINE_LEFT_VOL	0x4025 +#define ADAU1761_PLAY_LINE_RIGHT_VOL	0x4026 +#define ADAU1761_PLAY_MONO_OUTPUT_VOL	0x4027 +#define ADAU1761_POP_CLICK_SUPPRESS	0x4028 +#define ADAU1761_JACK_DETECT_PIN	0x4031 +#define ADAU1761_DEJITTER		0x4036 +#define ADAU1761_CLK_ENABLE0		0x40f9 +#define ADAU1761_CLK_ENABLE1		0x40fa + +#define ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW	BIT(0) +#define ADAU1761_DIGMIC_JACKDETECT_DIGMIC	BIT(5) + +#define ADAU1761_DIFF_INPUT_VOL_LDEN		BIT(0) + +#define ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP	BIT(0) +#define ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE	BIT(1) + +#define ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP	BIT(0) + +#define ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP	BIT(0) + +#define ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP	BIT(0) + + +#define ADAU1761_FIRMWARE "adau1761.bin" + +static const struct reg_default adau1761_reg_defaults[] = { +	{ ADAU1761_DEJITTER,			0x03 }, +	{ ADAU1761_DIGMIC_JACKDETECT,		0x00 }, +	{ ADAU1761_REC_MIXER_LEFT0,		0x00 }, +	{ ADAU1761_REC_MIXER_LEFT1,		0x00 }, +	{ ADAU1761_REC_MIXER_RIGHT0,		0x00 }, +	{ ADAU1761_REC_MIXER_RIGHT1,		0x00 }, +	{ ADAU1761_LEFT_DIFF_INPUT_VOL,		0x00 }, +	{ ADAU1761_RIGHT_DIFF_INPUT_VOL,	0x00 }, +	{ ADAU1761_PLAY_LR_MIXER_LEFT,		0x00 }, +	{ ADAU1761_PLAY_MIXER_LEFT0,		0x00 }, +	{ ADAU1761_PLAY_MIXER_LEFT1,		0x00 }, +	{ ADAU1761_PLAY_MIXER_RIGHT0,		0x00 }, +	{ ADAU1761_PLAY_MIXER_RIGHT1,		0x00 }, +	{ ADAU1761_PLAY_LR_MIXER_RIGHT,		0x00 }, +	{ ADAU1761_PLAY_MIXER_MONO,		0x00 }, +	{ ADAU1761_PLAY_HP_LEFT_VOL,		0x00 }, +	{ ADAU1761_PLAY_HP_RIGHT_VOL,		0x00 }, +	{ ADAU1761_PLAY_LINE_LEFT_VOL,		0x00 }, +	{ ADAU1761_PLAY_LINE_RIGHT_VOL,		0x00 }, +	{ ADAU1761_PLAY_MONO_OUTPUT_VOL,	0x00 }, +	{ ADAU1761_POP_CLICK_SUPPRESS,		0x00 }, +	{ ADAU1761_JACK_DETECT_PIN,		0x00 }, +	{ ADAU1761_CLK_ENABLE0,			0x00 }, +	{ ADAU1761_CLK_ENABLE1,			0x00 }, +	{ ADAU17X1_CLOCK_CONTROL,		0x00 }, +	{ ADAU17X1_PLL_CONTROL,			0x00 }, +	{ ADAU17X1_REC_POWER_MGMT,		0x00 }, +	{ ADAU17X1_MICBIAS,			0x00 }, +	{ ADAU17X1_SERIAL_PORT0,		0x00 }, +	{ ADAU17X1_SERIAL_PORT1,		0x00 }, +	{ ADAU17X1_CONVERTER0,			0x00 }, +	{ ADAU17X1_CONVERTER1,			0x00 }, +	{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL,	0x00 }, +	{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,	0x00 }, +	{ ADAU17X1_ADC_CONTROL,			0x00 }, +	{ ADAU17X1_PLAY_POWER_MGMT,		0x00 }, +	{ ADAU17X1_DAC_CONTROL0,		0x00 }, +	{ ADAU17X1_DAC_CONTROL1,		0x00 }, +	{ ADAU17X1_DAC_CONTROL2,		0x00 }, +	{ ADAU17X1_SERIAL_PORT_PAD,		0xaa }, +	{ ADAU17X1_CONTROL_PORT_PAD0,		0xaa }, +	{ ADAU17X1_CONTROL_PORT_PAD1,		0x00 }, +	{ ADAU17X1_DSP_SAMPLING_RATE,		0x01 }, +	{ ADAU17X1_SERIAL_INPUT_ROUTE,		0x00 }, +	{ ADAU17X1_SERIAL_OUTPUT_ROUTE,		0x00 }, +	{ ADAU17X1_DSP_ENABLE,			0x00 }, +	{ ADAU17X1_DSP_RUN,			0x00 }, +	{ ADAU17X1_SERIAL_SAMPLING_RATE,	0x00 }, +}; + +static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1); +static const DECLARE_TLV_DB_SCALE(adau1761_diff_in_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(adau1761_out_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1); +static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1); +static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1); + +static const unsigned int adau1761_bias_select_values[] = { +	0, 2, 3, +}; + +static const char * const adau1761_bias_select_text[] = { +	"Normal operation", "Enhanced performance", "Power saving", +}; + +static const char * const adau1761_bias_select_extreme_text[] = { +	"Normal operation", "Extreme power saving", "Enhanced performance", +	"Power saving", +}; + +static SOC_ENUM_SINGLE_DECL(adau1761_adc_bias_enum, +		ADAU17X1_REC_POWER_MGMT, 3, adau1761_bias_select_extreme_text); +static SOC_ENUM_SINGLE_DECL(adau1761_hp_bias_enum, +		ADAU17X1_PLAY_POWER_MGMT, 6, adau1761_bias_select_extreme_text); +static SOC_ENUM_SINGLE_DECL(adau1761_dac_bias_enum, +		ADAU17X1_PLAY_POWER_MGMT, 4, adau1761_bias_select_extreme_text); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_playback_bias_enum, +		ADAU17X1_PLAY_POWER_MGMT, 2, 0x3, adau1761_bias_select_text, +		adau1761_bias_select_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum, +		ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text, +		adau1761_bias_select_values); + +static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = { +	SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT, +		4, 1, 0), +}; + +static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = { +	SOC_DOUBLE_R_TLV("Capture Volume", ADAU1761_LEFT_DIFF_INPUT_VOL, +		ADAU1761_RIGHT_DIFF_INPUT_VOL, 2, 0x3f, 0, +		adau1761_diff_in_tlv), +	SOC_DOUBLE_R("Capture Switch", ADAU1761_LEFT_DIFF_INPUT_VOL, +		ADAU1761_RIGHT_DIFF_INPUT_VOL, 1, 1, 0), + +	SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1, +		ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv), +}; + +static const struct snd_kcontrol_new adau1761_single_mode_controls[] = { +	SOC_SINGLE_TLV("Input 1 Capture Volume", ADAU1761_REC_MIXER_LEFT0, +		4, 7, 0, adau1761_sing_in_tlv), +	SOC_SINGLE_TLV("Input 2 Capture Volume", ADAU1761_REC_MIXER_LEFT0, +		1, 7, 0, adau1761_sing_in_tlv), +	SOC_SINGLE_TLV("Input 3 Capture Volume", ADAU1761_REC_MIXER_RIGHT0, +		4, 7, 0, adau1761_sing_in_tlv), +	SOC_SINGLE_TLV("Input 4 Capture Volume", ADAU1761_REC_MIXER_RIGHT0, +		1, 7, 0, adau1761_sing_in_tlv), +}; + +static const struct snd_kcontrol_new adau1761_controls[] = { +	SOC_DOUBLE_R_TLV("Aux Capture Volume", ADAU1761_REC_MIXER_LEFT1, +		ADAU1761_REC_MIXER_RIGHT1, 0, 7, 0, adau1761_sing_in_tlv), + +	SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1761_PLAY_HP_LEFT_VOL, +		ADAU1761_PLAY_HP_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv), +	SOC_DOUBLE_R("Headphone Playback Switch", ADAU1761_PLAY_HP_LEFT_VOL, +		ADAU1761_PLAY_HP_RIGHT_VOL, 1, 1, 0), +	SOC_DOUBLE_R_TLV("Lineout Playback Volume", ADAU1761_PLAY_LINE_LEFT_VOL, +		ADAU1761_PLAY_LINE_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv), +	SOC_DOUBLE_R("Lineout Playback Switch", ADAU1761_PLAY_LINE_LEFT_VOL, +		ADAU1761_PLAY_LINE_RIGHT_VOL, 1, 1, 0), + +	SOC_ENUM("ADC Bias", adau1761_adc_bias_enum), +	SOC_ENUM("DAC Bias", adau1761_dac_bias_enum), +	SOC_ENUM("Capture Bias", adau1761_capture_bias_enum), +	SOC_ENUM("Playback Bias", adau1761_playback_bias_enum), +	SOC_ENUM("Headphone Bias", adau1761_hp_bias_enum), +}; + +static const struct snd_kcontrol_new adau1761_mono_controls[] = { +	SOC_SINGLE_TLV("Mono Playback Volume", ADAU1761_PLAY_MONO_OUTPUT_VOL, +		2, 0x3f, 0, adau1761_out_tlv), +	SOC_SINGLE("Mono Playback Switch", ADAU1761_PLAY_MONO_OUTPUT_VOL, +		1, 1, 0), +}; + +static const struct snd_kcontrol_new adau1761_left_mixer_controls[] = { +	SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch", +		ADAU1761_PLAY_MIXER_LEFT0, 5, 1, 0), +	SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch", +		ADAU1761_PLAY_MIXER_LEFT0, 6, 1, 0), +	SOC_DAPM_SINGLE_TLV("Aux Bypass Volume", +		ADAU1761_PLAY_MIXER_LEFT0, 1, 8, 0, adau1761_sidetone_tlv), +	SOC_DAPM_SINGLE_TLV("Right Bypass Volume", +		ADAU1761_PLAY_MIXER_LEFT1, 4, 8, 0, adau1761_sidetone_tlv), +	SOC_DAPM_SINGLE_TLV("Left Bypass Volume", +		ADAU1761_PLAY_MIXER_LEFT1, 0, 8, 0, adau1761_sidetone_tlv), +}; + +static const struct snd_kcontrol_new adau1761_right_mixer_controls[] = { +	SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch", +		ADAU1761_PLAY_MIXER_RIGHT0, 5, 1, 0), +	SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch", +		ADAU1761_PLAY_MIXER_RIGHT0, 6, 1, 0), +	SOC_DAPM_SINGLE_TLV("Aux Bypass Volume", +		ADAU1761_PLAY_MIXER_RIGHT0, 1, 8, 0, adau1761_sidetone_tlv), +	SOC_DAPM_SINGLE_TLV("Right Bypass Volume", +		ADAU1761_PLAY_MIXER_RIGHT1, 4, 8, 0, adau1761_sidetone_tlv), +	SOC_DAPM_SINGLE_TLV("Left Bypass Volume", +		ADAU1761_PLAY_MIXER_RIGHT1, 0, 8, 0, adau1761_sidetone_tlv), +}; + +static const struct snd_kcontrol_new adau1761_left_lr_mixer_controls[] = { +	SOC_DAPM_SINGLE_TLV("Left Volume", +		ADAU1761_PLAY_LR_MIXER_LEFT, 1, 2, 0, adau1761_boost_tlv), +	SOC_DAPM_SINGLE_TLV("Right Volume", +		ADAU1761_PLAY_LR_MIXER_LEFT, 3, 2, 0, adau1761_boost_tlv), +}; + +static const struct snd_kcontrol_new adau1761_right_lr_mixer_controls[] = { +	SOC_DAPM_SINGLE_TLV("Left Volume", +		ADAU1761_PLAY_LR_MIXER_RIGHT, 1, 2, 0, adau1761_boost_tlv), +	SOC_DAPM_SINGLE_TLV("Right Volume", +		ADAU1761_PLAY_LR_MIXER_RIGHT, 3, 2, 0, adau1761_boost_tlv), +}; + +static const char * const adau1761_input_mux_text[] = { +	"ADC", "DMIC", +}; + +static SOC_ENUM_SINGLE_DECL(adau1761_input_mux_enum, +	ADAU17X1_ADC_CONTROL, 2, adau1761_input_mux_text); + +static const struct snd_kcontrol_new adau1761_input_mux_control = +	SOC_DAPM_ENUM("Input Select", adau1761_input_mux_enum); + +static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(w->codec); + +	/* After any power changes have been made the dejitter circuit +	 * has to be reinitialized. */ +	regmap_write(adau->regmap, ADAU1761_DEJITTER, 0); +	if (!adau->master) +		regmap_write(adau->regmap, ADAU1761_DEJITTER, 3); + +	return 0; +} + +static const struct snd_soc_dapm_widget adau1x61_dapm_widgets[] = { +	SND_SOC_DAPM_MIXER("Left Input Mixer", ADAU1761_REC_MIXER_LEFT0, 0, 0, +		NULL, 0), +	SND_SOC_DAPM_MIXER("Right Input Mixer", ADAU1761_REC_MIXER_RIGHT0, 0, 0, +		NULL, 0), + +	SOC_MIXER_ARRAY("Left Playback Mixer", ADAU1761_PLAY_MIXER_LEFT0, +		0, 0, adau1761_left_mixer_controls), +	SOC_MIXER_ARRAY("Right Playback Mixer", ADAU1761_PLAY_MIXER_RIGHT0, +		0, 0, adau1761_right_mixer_controls), +	SOC_MIXER_ARRAY("Left LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_LEFT, +		0, 0, adau1761_left_lr_mixer_controls), +	SOC_MIXER_ARRAY("Right LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_RIGHT, +		0, 0, adau1761_right_lr_mixer_controls), + +	SND_SOC_DAPM_SUPPLY("Headphone", ADAU1761_PLAY_HP_LEFT_VOL, +		0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY_S("SYSCLK", 2, SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_POST("Dejitter fixup", adau1761_dejitter_fixup), + +	SND_SOC_DAPM_INPUT("LAUX"), +	SND_SOC_DAPM_INPUT("RAUX"), +	SND_SOC_DAPM_INPUT("LINP"), +	SND_SOC_DAPM_INPUT("LINN"), +	SND_SOC_DAPM_INPUT("RINP"), +	SND_SOC_DAPM_INPUT("RINN"), + +	SND_SOC_DAPM_OUTPUT("LOUT"), +	SND_SOC_DAPM_OUTPUT("ROUT"), +	SND_SOC_DAPM_OUTPUT("LHP"), +	SND_SOC_DAPM_OUTPUT("RHP"), +}; + +static const struct snd_soc_dapm_widget adau1761_mono_dapm_widgets[] = { +	SND_SOC_DAPM_MIXER("Mono Playback Mixer", ADAU1761_PLAY_MIXER_MONO, +		0, 0, NULL, 0), + +	SND_SOC_DAPM_OUTPUT("MONOOUT"), +}; + +static const struct snd_soc_dapm_widget adau1761_capless_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY_S("Headphone VGND", 1, ADAU1761_PLAY_MIXER_MONO, +		0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route adau1x61_dapm_routes[] = { +	{ "Left Input Mixer", NULL, "LINP" }, +	{ "Left Input Mixer", NULL, "LINN" }, +	{ "Left Input Mixer", NULL, "LAUX" }, + +	{ "Right Input Mixer", NULL, "RINP" }, +	{ "Right Input Mixer", NULL, "RINN" }, +	{ "Right Input Mixer", NULL, "RAUX" }, + +	{ "Left Playback Mixer", NULL, "Left Playback Enable"}, +	{ "Right Playback Mixer", NULL, "Right Playback Enable"}, +	{ "Left LR Playback Mixer", NULL, "Left Playback Enable"}, +	{ "Right LR Playback Mixer", NULL, "Right Playback Enable"}, + +	{ "Left Playback Mixer", "Left DAC Switch", "Left DAC" }, +	{ "Left Playback Mixer", "Right DAC Switch", "Right DAC" }, + +	{ "Right Playback Mixer", "Left DAC Switch", "Left DAC" }, +	{ "Right Playback Mixer", "Right DAC Switch", "Right DAC" }, + +	{ "Left LR Playback Mixer", "Left Volume", "Left Playback Mixer" }, +	{ "Left LR Playback Mixer", "Right Volume", "Right Playback Mixer" }, + +	{ "Right LR Playback Mixer", "Left Volume", "Left Playback Mixer" }, +	{ "Right LR Playback Mixer", "Right Volume", "Right Playback Mixer" }, + +	{ "LHP", NULL, "Left Playback Mixer" }, +	{ "RHP", NULL, "Right Playback Mixer" }, + +	{ "LHP", NULL, "Headphone" }, +	{ "RHP", NULL, "Headphone" }, + +	{ "LOUT", NULL, "Left LR Playback Mixer" }, +	{ "ROUT", NULL, "Right LR Playback Mixer" }, + +	{ "Left Playback Mixer", "Aux Bypass Volume", "LAUX" }, +	{ "Left Playback Mixer", "Left Bypass Volume", "Left Input Mixer" }, +	{ "Left Playback Mixer", "Right Bypass Volume", "Right Input Mixer" }, +	{ "Right Playback Mixer", "Aux Bypass Volume", "RAUX" }, +	{ "Right Playback Mixer", "Left Bypass Volume", "Left Input Mixer" }, +	{ "Right Playback Mixer", "Right Bypass Volume", "Right Input Mixer" }, +}; + +static const struct snd_soc_dapm_route adau1761_mono_dapm_routes[] = { +	{ "Mono Playback Mixer", NULL, "Left Playback Mixer" }, +	{ "Mono Playback Mixer", NULL, "Right Playback Mixer" }, + +	{ "MONOOUT", NULL, "Mono Playback Mixer" }, +}; + +static const struct snd_soc_dapm_route adau1761_capless_dapm_routes[] = { +	{ "Headphone", NULL, "Headphone VGND" }, +}; + +static const struct snd_soc_dapm_widget adau1761_dmic_widgets[] = { +	SND_SOC_DAPM_MUX("Left Decimator Mux", SND_SOC_NOPM, 0, 0, +		&adau1761_input_mux_control), +	SND_SOC_DAPM_MUX("Right Decimator Mux", SND_SOC_NOPM, 0, 0, +		&adau1761_input_mux_control), + +	SND_SOC_DAPM_INPUT("DMIC"), +}; + +static const struct snd_soc_dapm_route adau1761_dmic_routes[] = { +	{ "Left Decimator Mux", "ADC", "Left Input Mixer" }, +	{ "Left Decimator Mux", "DMIC", "DMIC" }, +	{ "Right Decimator Mux", "ADC", "Right Input Mixer" }, +	{ "Right Decimator Mux", "DMIC", "DMIC" }, + +	{ "Left Decimator", NULL, "Left Decimator Mux" }, +	{ "Right Decimator", NULL, "Right Decimator Mux" }, +}; + +static const struct snd_soc_dapm_route adau1761_no_dmic_routes[] = { +	{ "Left Decimator", NULL, "Left Input Mixer" }, +	{ "Right Decimator", NULL, "Right Input Mixer" }, +}; + +static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY("Serial Port Clock", ADAU1761_CLK_ENABLE0, +		0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Serial Input Routing Clock", ADAU1761_CLK_ENABLE0, +		1, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Serial Output Routing Clock", ADAU1761_CLK_ENABLE0, +		3, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("Decimator Resync Clock", ADAU1761_CLK_ENABLE0, +		4, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Interpolator Resync Clock", ADAU1761_CLK_ENABLE0, +		2, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1, +		0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("Digital Clock 1", 1, ADAU1761_CLK_ENABLE1, +		1, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route adau1761_dapm_routes[] = { +	{ "Left Decimator", NULL, "Digital Clock 0", }, +	{ "Right Decimator", NULL, "Digital Clock 0", }, +	{ "Left DAC", NULL, "Digital Clock 0", }, +	{ "Right DAC", NULL, "Digital Clock 0", }, + +	{ "AIFCLK", NULL, "Digital Clock 1" }, + +	{ "Playback", NULL, "Serial Port Clock" }, +	{ "Capture", NULL, "Serial Port Clock" }, +	{ "Playback", NULL, "Serial Input Routing Clock" }, +	{ "Capture", NULL, "Serial Output Routing Clock" }, + +	{ "Left Decimator", NULL, "Decimator Resync Clock" }, +	{ "Right Decimator", NULL, "Decimator Resync Clock" }, +	{ "Left DAC", NULL, "Interpolator Resync Clock" }, +	{ "Right DAC", NULL, "Interpolator Resync Clock" }, + +	{ "DSP", NULL, "Digital Clock 0" }, + +	{ "Slew Clock", NULL, "Digital Clock 0" }, +	{ "Right Playback Mixer", NULL, "Slew Clock" }, +	{ "Left Playback Mixer", NULL, "Slew Clock" }, + +	{ "Digital Clock 0", NULL, "SYSCLK" }, +	{ "Digital Clock 1", NULL, "SYSCLK" }, +}; + +static int adau1761_set_bias_level(struct snd_soc_codec *codec, +				 enum snd_soc_bias_level level) +{ +	struct adau *adau = 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: +		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, +			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, +			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN); +		break; +	case SND_SOC_BIAS_OFF: +		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, +			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0); +		break; + +	} +	codec->dapm.bias_level = level; +	return 0; +} + +static enum adau1761_output_mode adau1761_get_lineout_mode( +	struct snd_soc_codec *codec) +{ +	struct adau1761_platform_data *pdata = codec->dev->platform_data; + +	if (pdata) +		return pdata->lineout_mode; + +	return ADAU1761_OUTPUT_MODE_LINE; +} + +static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec) +{ +	struct adau1761_platform_data *pdata = codec->dev->platform_data; +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	enum adau1761_digmic_jackdet_pin_mode mode; +	unsigned int val = 0; +	int ret; + +	if (pdata) +		mode = pdata->digmic_jackdetect_pin_mode; +	else +		mode = ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE; + +	switch (mode) { +	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT: +		switch (pdata->jackdetect_debounce_time) { +		case ADAU1761_JACKDETECT_DEBOUNCE_5MS: +		case ADAU1761_JACKDETECT_DEBOUNCE_10MS: +		case ADAU1761_JACKDETECT_DEBOUNCE_20MS: +		case ADAU1761_JACKDETECT_DEBOUNCE_40MS: +			val |= pdata->jackdetect_debounce_time << 6; +			break; +		default: +			return -EINVAL; +		} +		if (pdata->jackdetect_active_low) +			val |= ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW; + +		ret = snd_soc_add_codec_controls(codec, +			adau1761_jack_detect_controls, +			ARRAY_SIZE(adau1761_jack_detect_controls)); +		if (ret) +			return ret; +	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */ +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau1761_no_dmic_routes, +			ARRAY_SIZE(adau1761_no_dmic_routes)); +		if (ret) +			return ret; +		break; +	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC: +		ret = snd_soc_dapm_new_controls(&codec->dapm, +			adau1761_dmic_widgets, +			ARRAY_SIZE(adau1761_dmic_widgets)); +		if (ret) +			return ret; + +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau1761_dmic_routes, +			ARRAY_SIZE(adau1761_dmic_routes)); +		if (ret) +			return ret; + +		val |= ADAU1761_DIGMIC_JACKDETECT_DIGMIC; +		break; +	default: +		return -EINVAL; +	} + +	regmap_write(adau->regmap, ADAU1761_DIGMIC_JACKDETECT, val); + +	return 0; +} + +static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	struct adau1761_platform_data *pdata = codec->dev->platform_data; +	enum adau1761_output_mode mode; +	int ret; + +	if (pdata) +		mode = pdata->headphone_mode; +	else +		mode = ADAU1761_OUTPUT_MODE_HEADPHONE; + +	switch (mode) { +	case ADAU1761_OUTPUT_MODE_LINE: +		break; +	case ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS: +		regmap_update_bits(adau->regmap, ADAU1761_PLAY_MONO_OUTPUT_VOL, +			ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP | +			ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE, +			ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP | +			ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE); +		/* fallthrough */ +	case ADAU1761_OUTPUT_MODE_HEADPHONE: +		regmap_update_bits(adau->regmap, ADAU1761_PLAY_HP_RIGHT_VOL, +			ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP, +			ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP); +		break; +	default: +		return -EINVAL; +	} + +	if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) { +		ret = snd_soc_dapm_new_controls(&codec->dapm, +			adau1761_capless_dapm_widgets, +			ARRAY_SIZE(adau1761_capless_dapm_widgets)); +		if (ret) +			return ret; +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau1761_capless_dapm_routes, +			ARRAY_SIZE(adau1761_capless_dapm_routes)); +	} else { +		ret = snd_soc_add_codec_controls(codec, adau1761_mono_controls, +			ARRAY_SIZE(adau1761_mono_controls)); +		if (ret) +			return ret; +		ret = snd_soc_dapm_new_controls(&codec->dapm, +			adau1761_mono_dapm_widgets, +			ARRAY_SIZE(adau1761_mono_dapm_widgets)); +		if (ret) +			return ret; +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau1761_mono_dapm_routes, +			ARRAY_SIZE(adau1761_mono_dapm_routes)); +	} + +	return ret; +} + +static bool adau1761_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case ADAU1761_DIGMIC_JACKDETECT: +	case ADAU1761_REC_MIXER_LEFT0: +	case ADAU1761_REC_MIXER_LEFT1: +	case ADAU1761_REC_MIXER_RIGHT0: +	case ADAU1761_REC_MIXER_RIGHT1: +	case ADAU1761_LEFT_DIFF_INPUT_VOL: +	case ADAU1761_RIGHT_DIFF_INPUT_VOL: +	case ADAU1761_PLAY_LR_MIXER_LEFT: +	case ADAU1761_PLAY_MIXER_LEFT0: +	case ADAU1761_PLAY_MIXER_LEFT1: +	case ADAU1761_PLAY_MIXER_RIGHT0: +	case ADAU1761_PLAY_MIXER_RIGHT1: +	case ADAU1761_PLAY_LR_MIXER_RIGHT: +	case ADAU1761_PLAY_MIXER_MONO: +	case ADAU1761_PLAY_HP_LEFT_VOL: +	case ADAU1761_PLAY_HP_RIGHT_VOL: +	case ADAU1761_PLAY_LINE_LEFT_VOL: +	case ADAU1761_PLAY_LINE_RIGHT_VOL: +	case ADAU1761_PLAY_MONO_OUTPUT_VOL: +	case ADAU1761_POP_CLICK_SUPPRESS: +	case ADAU1761_JACK_DETECT_PIN: +	case ADAU1761_DEJITTER: +	case ADAU1761_CLK_ENABLE0: +	case ADAU1761_CLK_ENABLE1: +		return true; +	default: +		break; +	} + +	return adau17x1_readable_register(dev, reg); +} + +static int adau1761_codec_probe(struct snd_soc_codec *codec) +{ +	struct adau1761_platform_data *pdata = codec->dev->platform_data; +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	int ret; + +	ret = adau17x1_add_widgets(codec); +	if (ret < 0) +		return ret; + +	if (pdata && pdata->input_differential) { +		regmap_update_bits(adau->regmap, ADAU1761_LEFT_DIFF_INPUT_VOL, +			ADAU1761_DIFF_INPUT_VOL_LDEN, +			ADAU1761_DIFF_INPUT_VOL_LDEN); +		regmap_update_bits(adau->regmap, ADAU1761_RIGHT_DIFF_INPUT_VOL, +			ADAU1761_DIFF_INPUT_VOL_LDEN, +			ADAU1761_DIFF_INPUT_VOL_LDEN); +		ret = snd_soc_add_codec_controls(codec, +			adau1761_differential_mode_controls, +			ARRAY_SIZE(adau1761_differential_mode_controls)); +		if (ret) +			return ret; +	} else { +		ret = snd_soc_add_codec_controls(codec, +			adau1761_single_mode_controls, +			ARRAY_SIZE(adau1761_single_mode_controls)); +		if (ret) +			return ret; +	} + +	switch (adau1761_get_lineout_mode(codec)) { +	case ADAU1761_OUTPUT_MODE_LINE: +		break; +	case ADAU1761_OUTPUT_MODE_HEADPHONE: +		regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_LEFT_VOL, +			ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP, +			ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP); +		regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_RIGHT_VOL, +			ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP, +			ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP); +		break; +	default: +		return -EINVAL; +	} + +	ret = adau1761_setup_headphone_mode(codec); +	if (ret) +		return ret; + +	ret = adau1761_setup_digmic_jackdetect(codec); +	if (ret) +		return ret; + +	if (adau->type == ADAU1761) { +		ret = snd_soc_dapm_new_controls(&codec->dapm, +			adau1761_dapm_widgets, +			ARRAY_SIZE(adau1761_dapm_widgets)); +		if (ret) +			return ret; + +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau1761_dapm_routes, +			ARRAY_SIZE(adau1761_dapm_routes)); +		if (ret) +			return ret; + +		ret = adau17x1_load_firmware(adau, codec->dev, +			ADAU1761_FIRMWARE); +		if (ret) +			dev_warn(codec->dev, "Failed to firmware\n"); +	} + +	ret = adau17x1_add_routes(codec); +	if (ret < 0) +		return ret; + +	return 0; +} + +static const struct snd_soc_codec_driver adau1761_codec_driver = { +	.probe = adau1761_codec_probe, +	.suspend = adau17x1_suspend, +	.resume	= adau17x1_resume, +	.set_bias_level	= adau1761_set_bias_level, + +	.controls = adau1761_controls, +	.num_controls = ARRAY_SIZE(adau1761_controls), +	.dapm_widgets = adau1x61_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets), +	.dapm_routes = adau1x61_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes), +}; + +#define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ +	SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver adau1361_dai_driver = { +	.name = "adau-hifi", +	.playback = { +		.stream_name = "Playback", +		.channels_min = 2, +		.channels_max = 4, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = ADAU1761_FORMATS, +	}, +	.capture = { +		.stream_name = "Capture", +		.channels_min = 2, +		.channels_max = 4, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = ADAU1761_FORMATS, +	}, +	.ops = &adau17x1_dai_ops, +}; + +static struct snd_soc_dai_driver adau1761_dai_driver = { +	.name = "adau-hifi", +	.playback = { +		.stream_name = "Playback", +		.channels_min = 2, +		.channels_max = 8, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = ADAU1761_FORMATS, +	}, +	.capture = { +		.stream_name = "Capture", +		.channels_min = 2, +		.channels_max = 8, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = ADAU1761_FORMATS, +	}, +	.ops = &adau17x1_dai_ops, +}; + +int adau1761_probe(struct device *dev, struct regmap *regmap, +	enum adau17x1_type type, void (*switch_mode)(struct device *dev)) +{ +	struct snd_soc_dai_driver *dai_drv; +	int ret; + +	ret = adau17x1_probe(dev, regmap, type, switch_mode); +	if (ret) +		return ret; + +	if (type == ADAU1361) +		dai_drv = &adau1361_dai_driver; +	else +		dai_drv = &adau1761_dai_driver; + +	return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); +} +EXPORT_SYMBOL_GPL(adau1761_probe); + +const struct regmap_config adau1761_regmap_config = { +	.val_bits = 8, +	.reg_bits = 16, +	.max_register = 0x40fa, +	.reg_defaults = adau1761_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults), +	.readable_reg = adau1761_readable_register, +	.volatile_reg = adau17x1_volatile_register, +	.cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(adau1761_regmap_config); + +MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1761.h b/sound/soc/codecs/adau1761.h new file mode 100644 index 00000000000..a9e0d288301 --- /dev/null +++ b/sound/soc/codecs/adau1761.h @@ -0,0 +1,23 @@ +/* + * ADAU1361/ADAU1461/ADAU1761/ADAU1961 driver + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#ifndef __SOUND_SOC_CODECS_ADAU1761_H__ +#define __SOUND_SOC_CODECS_ADAU1761_H__ + +#include <linux/regmap.h> +#include "adau17x1.h" + +struct device; + +int adau1761_probe(struct device *dev, struct regmap *regmap, +	enum adau17x1_type type, void (*switch_mode)(struct device *dev)); + +extern const struct regmap_config adau1761_regmap_config; + +#endif diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c new file mode 100644 index 00000000000..2ce4362ccec --- /dev/null +++ b/sound/soc/codecs/adau1781-i2c.c @@ -0,0 +1,58 @@ +/* + * Driver for ADAU1381/ADAU1781 CODEC + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "adau1781.h" + +static int adau1781_i2c_probe(struct i2c_client *client, +	const struct i2c_device_id *id) +{ +	struct regmap_config config; + +	config = adau1781_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 16; + +	return adau1781_probe(&client->dev, +		devm_regmap_init_i2c(client, &config), +		id->driver_data, NULL); +} + +static int adau1781_i2c_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static const struct i2c_device_id adau1781_i2c_ids[] = { +	{ "adau1381", ADAU1381 }, +	{ "adau1781", ADAU1781 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids); + +static struct i2c_driver adau1781_i2c_driver = { +	.driver = { +		.name = "adau1781", +		.owner = THIS_MODULE, +	}, +	.probe = adau1781_i2c_probe, +	.remove = adau1781_i2c_remove, +	.id_table = adau1781_i2c_ids, +}; +module_i2c_driver(adau1781_i2c_driver); + +MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC I2C driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c new file mode 100644 index 00000000000..194686716bb --- /dev/null +++ b/sound/soc/codecs/adau1781-spi.c @@ -0,0 +1,75 @@ +/* + * Driver for ADAU1381/ADAU1781 CODEC + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <sound/soc.h> + +#include "adau1781.h" + +static void adau1781_spi_switch_mode(struct device *dev) +{ +	struct spi_device *spi = to_spi_device(dev); + +	/* +	 * To get the device into SPI mode CLATCH has to be pulled low three +	 * times.  Do this by issuing three dummy reads. +	 */ +	spi_w8r8(spi, 0x00); +	spi_w8r8(spi, 0x00); +	spi_w8r8(spi, 0x00); +} + +static int adau1781_spi_probe(struct spi_device *spi) +{ +	const struct spi_device_id *id = spi_get_device_id(spi); +	struct regmap_config config; + +	if (!id) +		return -EINVAL; + +	config = adau1781_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 24; +	config.read_flag_mask = 0x1; + +	return adau1781_probe(&spi->dev, +		devm_regmap_init_spi(spi, &config), +		id->driver_data, adau1781_spi_switch_mode); +} + +static int adau1781_spi_remove(struct spi_device *spi) +{ +	snd_soc_unregister_codec(&spi->dev); +	return 0; +} + +static const struct spi_device_id adau1781_spi_id[] = { +	{ "adau1381", ADAU1381 }, +	{ "adau1781", ADAU1781 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, adau1781_spi_id); + +static struct spi_driver adau1781_spi_driver = { +	.driver = { +		.name = "adau1781", +		.owner = THIS_MODULE, +	}, +	.probe = adau1781_spi_probe, +	.remove = adau1781_spi_remove, +	.id_table = adau1781_spi_id, +}; +module_spi_driver(adau1781_spi_driver); + +MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC SPI driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c new file mode 100644 index 00000000000..045a6141384 --- /dev/null +++ b/sound/soc/codecs/adau1781.c @@ -0,0 +1,511 @@ +/* + * Driver for ADAU1781/ADAU1781 codec + * + * Copyright 2011-2013 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include <linux/platform_data/adau17x1.h> + +#include "adau17x1.h" +#include "adau1781.h" + +#define ADAU1781_DMIC_BEEP_CTRL		0x4008 +#define ADAU1781_LEFT_PGA		0x400e +#define ADAU1781_RIGHT_PGA		0x400f +#define ADAU1781_LEFT_PLAYBACK_MIXER	0x401c +#define ADAU1781_RIGHT_PLAYBACK_MIXER	0x401e +#define ADAU1781_MONO_PLAYBACK_MIXER	0x401f +#define ADAU1781_LEFT_LINEOUT		0x4025 +#define ADAU1781_RIGHT_LINEOUT		0x4026 +#define ADAU1781_SPEAKER		0x4027 +#define ADAU1781_BEEP_ZC		0x4028 +#define ADAU1781_DEJITTER		0x4032 +#define ADAU1781_DIG_PWDN0		0x4080 +#define ADAU1781_DIG_PWDN1		0x4081 + +#define ADAU1781_INPUT_DIFFERNTIAL BIT(3) + +#define ADAU1381_FIRMWARE "adau1381.bin" +#define ADAU1781_FIRMWARE "adau1781.bin" + +static const struct reg_default adau1781_reg_defaults[] = { +	{ ADAU1781_DMIC_BEEP_CTRL,		0x00 }, +	{ ADAU1781_LEFT_PGA,			0xc7 }, +	{ ADAU1781_RIGHT_PGA,			0xc7 }, +	{ ADAU1781_LEFT_PLAYBACK_MIXER,		0x00 }, +	{ ADAU1781_RIGHT_PLAYBACK_MIXER,	0x00 }, +	{ ADAU1781_MONO_PLAYBACK_MIXER,		0x00 }, +	{ ADAU1781_LEFT_LINEOUT,		0x00 }, +	{ ADAU1781_RIGHT_LINEOUT,		0x00 }, +	{ ADAU1781_SPEAKER,			0x00 }, +	{ ADAU1781_BEEP_ZC,			0x19 }, +	{ ADAU1781_DEJITTER,			0x60 }, +	{ ADAU1781_DIG_PWDN1,			0x0c }, +	{ ADAU1781_DIG_PWDN1,			0x00 }, +	{ ADAU17X1_CLOCK_CONTROL,		0x00 }, +	{ ADAU17X1_PLL_CONTROL,			0x00 }, +	{ ADAU17X1_REC_POWER_MGMT,		0x00 }, +	{ ADAU17X1_MICBIAS,			0x04 }, +	{ ADAU17X1_SERIAL_PORT0,		0x00 }, +	{ ADAU17X1_SERIAL_PORT1,		0x00 }, +	{ ADAU17X1_CONVERTER0,			0x00 }, +	{ ADAU17X1_CONVERTER1,			0x00 }, +	{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL,	0x00 }, +	{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,	0x00 }, +	{ ADAU17X1_ADC_CONTROL,			0x00 }, +	{ ADAU17X1_PLAY_POWER_MGMT,		0x00 }, +	{ ADAU17X1_DAC_CONTROL0,		0x00 }, +	{ ADAU17X1_DAC_CONTROL1,		0x00 }, +	{ ADAU17X1_DAC_CONTROL2,		0x00 }, +	{ ADAU17X1_SERIAL_PORT_PAD,		0x00 }, +	{ ADAU17X1_CONTROL_PORT_PAD0,		0x00 }, +	{ ADAU17X1_CONTROL_PORT_PAD1,		0x00 }, +	{ ADAU17X1_DSP_SAMPLING_RATE,		0x01 }, +	{ ADAU17X1_SERIAL_INPUT_ROUTE,		0x00 }, +	{ ADAU17X1_SERIAL_OUTPUT_ROUTE,		0x00 }, +	{ ADAU17X1_DSP_ENABLE,			0x00 }, +	{ ADAU17X1_DSP_RUN,			0x00 }, +	{ ADAU17X1_SERIAL_SAMPLING_RATE,	0x00 }, +}; + +static const DECLARE_TLV_DB_SCALE(adau1781_speaker_tlv, 0, 200, 0); + +static const DECLARE_TLV_DB_RANGE(adau1781_pga_tlv, +	0, 1, TLV_DB_SCALE_ITEM(0, 600, 0), +	2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0), +	4, 4, TLV_DB_SCALE_ITEM(1700, 0, 0), +	5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0) +); + +static const DECLARE_TLV_DB_RANGE(adau1781_beep_tlv, +	0, 1, TLV_DB_SCALE_ITEM(0, 600, 0), +	2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0), +	4, 4, TLV_DB_SCALE_ITEM(-2300, 0, 0), +	5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0) +); + +static const DECLARE_TLV_DB_SCALE(adau1781_sidetone_tlv, -1800, 300, 1); + +static const char * const adau1781_speaker_bias_select_text[] = { +	"Normal operation", "Power saving", "Enhanced performance", +}; + +static const char * const adau1781_bias_select_text[] = { +	"Normal operation", "Extreme power saving", "Power saving", +	"Enhanced performance", +}; + +static SOC_ENUM_SINGLE_DECL(adau1781_adc_bias_enum, +		ADAU17X1_REC_POWER_MGMT, 3, adau1781_bias_select_text); +static SOC_ENUM_SINGLE_DECL(adau1781_speaker_bias_enum, +		ADAU17X1_PLAY_POWER_MGMT, 6, adau1781_speaker_bias_select_text); +static SOC_ENUM_SINGLE_DECL(adau1781_dac_bias_enum, +		ADAU17X1_PLAY_POWER_MGMT, 4, adau1781_bias_select_text); +static SOC_ENUM_SINGLE_DECL(adau1781_playback_bias_enum, +		ADAU17X1_PLAY_POWER_MGMT, 2, adau1781_bias_select_text); +static SOC_ENUM_SINGLE_DECL(adau1781_capture_bias_enum, +		ADAU17X1_REC_POWER_MGMT, 1, adau1781_bias_select_text); + +static const struct snd_kcontrol_new adau1781_controls[] = { +	SOC_SINGLE_TLV("Beep Capture Volume", ADAU1781_DMIC_BEEP_CTRL, 0, 7, 0, +		adau1781_beep_tlv), +	SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAU1781_LEFT_PGA, +		ADAU1781_RIGHT_PGA, 5, 7, 0, adau1781_pga_tlv), +	SOC_DOUBLE_R("PGA Capture Switch", ADAU1781_LEFT_PGA, +		ADAU1781_RIGHT_PGA, 1, 1, 0), + +	SOC_DOUBLE_R("Lineout Playback Switch", ADAU1781_LEFT_LINEOUT, +		ADAU1781_RIGHT_LINEOUT, 1, 1, 0), +	SOC_SINGLE("Beep ZC Switch", ADAU1781_BEEP_ZC, 0, 1, 0), + +	SOC_SINGLE("Mono Playback Switch", ADAU1781_MONO_PLAYBACK_MIXER, +		0, 1, 0), +	SOC_SINGLE_TLV("Mono Playback Volume", ADAU1781_SPEAKER, 6, 3, 0, +		adau1781_speaker_tlv), + +	SOC_ENUM("ADC Bias", adau1781_adc_bias_enum), +	SOC_ENUM("DAC Bias", adau1781_dac_bias_enum), +	SOC_ENUM("Capture Bias", adau1781_capture_bias_enum), +	SOC_ENUM("Playback Bias", adau1781_playback_bias_enum), +	SOC_ENUM("Speaker Bias", adau1781_speaker_bias_enum), +}; + +static const struct snd_kcontrol_new adau1781_beep_mixer_controls[] = { +	SOC_DAPM_SINGLE("Beep Capture Switch", ADAU1781_DMIC_BEEP_CTRL, +		3, 1, 0), +}; + +static const struct snd_kcontrol_new adau1781_left_mixer_controls[] = { +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", +		ADAU1781_LEFT_PLAYBACK_MIXER, 5, 1, 0), +	SOC_DAPM_SINGLE_TLV("Beep Playback Volume", +		ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv), +}; + +static const struct snd_kcontrol_new adau1781_right_mixer_controls[] = { +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", +		ADAU1781_RIGHT_PLAYBACK_MIXER, 6, 1, 0), +	SOC_DAPM_SINGLE_TLV("Beep Playback Volume", +		ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv), +}; + +static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = { +	SOC_DAPM_SINGLE_AUTODISABLE("Left Switch", +		ADAU1781_MONO_PLAYBACK_MIXER, 7, 1, 0), +	SOC_DAPM_SINGLE_AUTODISABLE("Right Switch", +		 ADAU1781_MONO_PLAYBACK_MIXER, 6, 1, 0), +	SOC_DAPM_SINGLE_TLV("Beep Playback Volume", +		ADAU1781_MONO_PLAYBACK_MIXER, 2, 8, 0, adau1781_sidetone_tlv), +}; + +static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct adau *adau = snd_soc_codec_get_drvdata(codec); + +	/* After any power changes have been made the dejitter circuit +	 * has to be reinitialized. */ +	regmap_write(adau->regmap, ADAU1781_DEJITTER, 0); +	if (!adau->master) +		regmap_write(adau->regmap, ADAU1781_DEJITTER, 5); + +	return 0; +} + +static const struct snd_soc_dapm_widget adau1781_dapm_widgets[] = { +	SND_SOC_DAPM_PGA("Left PGA", ADAU1781_LEFT_PGA, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Right PGA", ADAU1781_RIGHT_PGA, 0, 0, NULL, 0), + +	SND_SOC_DAPM_OUT_DRV("Speaker", ADAU1781_SPEAKER, 0, 0, NULL, 0), + +	SOC_MIXER_NAMED_CTL_ARRAY("Beep Mixer", ADAU17X1_MICBIAS, 4, 0, +		adau1781_beep_mixer_controls), + +	SOC_MIXER_ARRAY("Left Lineout Mixer", SND_SOC_NOPM, 0, 0, +		adau1781_left_mixer_controls), +	SOC_MIXER_ARRAY("Right Lineout Mixer", SND_SOC_NOPM, 0, 0, +		adau1781_right_mixer_controls), +	SOC_MIXER_ARRAY("Mono Mixer", SND_SOC_NOPM, 0, 0, +		adau1781_mono_mixer_controls), + +	SND_SOC_DAPM_SUPPLY("Serial Input Routing", ADAU1781_DIG_PWDN0, +		2, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Serial Output Routing", ADAU1781_DIG_PWDN0, +		3, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Clock Domain Transfer", ADAU1781_DIG_PWDN0, +		5, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Serial Ports", ADAU1781_DIG_PWDN0, 4, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC Engine", ADAU1781_DIG_PWDN0, 7, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC Engine", ADAU1781_DIG_PWDN1, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Digital Mic", ADAU1781_DIG_PWDN1, 1, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("Sound Engine", ADAU1781_DIG_PWDN0, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, ADAU1781_DIG_PWDN0, 1, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("Zero Crossing Detector", ADAU1781_DIG_PWDN1, 2, 0, +		NULL, 0), + +	SND_SOC_DAPM_POST("Dejitter fixup", adau1781_dejitter_fixup), + +	SND_SOC_DAPM_INPUT("BEEP"), + +	SND_SOC_DAPM_OUTPUT("AOUTL"), +	SND_SOC_DAPM_OUTPUT("AOUTR"), +	SND_SOC_DAPM_OUTPUT("SP"), +	SND_SOC_DAPM_INPUT("LMIC"), +	SND_SOC_DAPM_INPUT("RMIC"), +}; + +static const struct snd_soc_dapm_route adau1781_dapm_routes[] = { +	{ "Left Lineout Mixer", NULL, "Left Playback Enable" }, +	{ "Right Lineout Mixer", NULL, "Right Playback Enable" }, + +	{ "Left Lineout Mixer", "Beep Playback Volume", "Beep Mixer" }, +	{ "Left Lineout Mixer", "Switch", "Left DAC" }, + +	{ "Right Lineout Mixer", "Beep Playback Volume", "Beep Mixer" }, +	{ "Right Lineout Mixer", "Switch", "Right DAC" }, + +	{ "Mono Mixer", "Beep Playback Volume", "Beep Mixer" }, +	{ "Mono Mixer", "Right Switch", "Right DAC" }, +	{ "Mono Mixer", "Left Switch", "Left DAC" }, +	{ "Speaker", NULL, "Mono Mixer" }, + +	{ "Mono Mixer", NULL, "SYSCLK" }, +	{ "Left Lineout Mixer", NULL, "SYSCLK" }, +	{ "Left Lineout Mixer", NULL, "SYSCLK" }, + +	{ "Beep Mixer", "Beep Capture Switch", "BEEP" }, +	{ "Beep Mixer", NULL, "Zero Crossing Detector" }, + +	{ "Left DAC", NULL, "DAC Engine" }, +	{ "Right DAC", NULL, "DAC Engine" }, + +	{ "Sound Engine", NULL, "SYSCLK" }, +	{ "DSP", NULL, "Sound Engine" }, + +	{ "Left Decimator", NULL, "ADC Engine" }, +	{ "Right Decimator", NULL, "ADC Engine" }, + +	{ "AIFCLK", NULL, "SYSCLK" }, + +	{ "Playback", NULL, "Serial Input Routing" }, +	{ "Playback", NULL, "Serial Ports" }, +	{ "Playback", NULL, "Clock Domain Transfer" }, +	{ "Capture", NULL, "Serial Output Routing" }, +	{ "Capture", NULL, "Serial Ports" }, +	{ "Capture", NULL, "Clock Domain Transfer" }, + +	{ "AOUTL", NULL, "Left Lineout Mixer" }, +	{ "AOUTR", NULL, "Right Lineout Mixer" }, +	{ "SP", NULL, "Speaker" }, +}; + +static const struct snd_soc_dapm_route adau1781_adc_dapm_routes[] = { +	{ "Left PGA", NULL, "LMIC" }, +	{ "Right PGA", NULL, "RMIC" }, + +	{ "Left Decimator", NULL, "Left PGA" }, +	{ "Right Decimator", NULL, "Right PGA" }, +}; + +static const char * const adau1781_dmic_select_text[] = { +	"DMIC1", "DMIC2", +}; + +static SOC_ENUM_SINGLE_VIRT_DECL(adau1781_dmic_select_enum, +	adau1781_dmic_select_text); + +static const struct snd_kcontrol_new adau1781_dmic_mux = +	SOC_DAPM_ENUM("DMIC Select", adau1781_dmic_select_enum); + +static const struct snd_soc_dapm_widget adau1781_dmic_dapm_widgets[] = { +	SND_SOC_DAPM_MUX("DMIC Select", SND_SOC_NOPM, 0, 0, &adau1781_dmic_mux), + +	SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1781_DMIC_BEEP_CTRL, 4, 0), +	SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1781_DMIC_BEEP_CTRL, 5, 0), +}; + +static const struct snd_soc_dapm_route adau1781_dmic_dapm_routes[] = { +	{ "DMIC1", NULL, "LMIC" }, +	{ "DMIC2", NULL, "RMIC" }, + +	{ "DMIC1", NULL, "Digital Mic" }, +	{ "DMIC2", NULL, "Digital Mic" }, + +	{ "DMIC Select", "DMIC1", "DMIC1" }, +	{ "DMIC Select", "DMIC2", "DMIC2" }, + +	{ "Left Decimator", NULL, "DMIC Select" }, +	{ "Right Decimator", NULL, "DMIC Select" }, +}; + +static int adau1781_set_bias_level(struct snd_soc_codec *codec, +		enum snd_soc_bias_level level) +{ +	struct adau *adau = 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: +		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, +			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, +			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN); + +		/* Precharge */ +		regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0x8, 0x8); +		break; +	case SND_SOC_BIAS_OFF: +		regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0xc, 0x0); +		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, +			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0); +		break; +	} + +	codec->dapm.bias_level = level; +	return 0; +} + +static bool adau1781_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case ADAU1781_DMIC_BEEP_CTRL: +	case ADAU1781_LEFT_PGA: +	case ADAU1781_RIGHT_PGA: +	case ADAU1781_LEFT_PLAYBACK_MIXER: +	case ADAU1781_RIGHT_PLAYBACK_MIXER: +	case ADAU1781_MONO_PLAYBACK_MIXER: +	case ADAU1781_LEFT_LINEOUT: +	case ADAU1781_RIGHT_LINEOUT: +	case ADAU1781_SPEAKER: +	case ADAU1781_BEEP_ZC: +	case ADAU1781_DEJITTER: +	case ADAU1781_DIG_PWDN0: +	case ADAU1781_DIG_PWDN1: +		return true; +	default: +		break; +	} + +	return adau17x1_readable_register(dev, reg); +} + +static int adau1781_set_input_mode(struct adau *adau, unsigned int reg, +	bool differential) +{ +	unsigned int val; + +	if (differential) +		val = ADAU1781_INPUT_DIFFERNTIAL; +	else +		val = 0; + +	return regmap_update_bits(adau->regmap, reg, +		ADAU1781_INPUT_DIFFERNTIAL, val); +} + +static int adau1781_codec_probe(struct snd_soc_codec *codec) +{ +	struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	const char *firmware; +	int ret; + +	ret = adau17x1_add_widgets(codec); +	if (ret) +		return ret; + +	if (pdata) { +		ret = adau1781_set_input_mode(adau, ADAU1781_LEFT_PGA, +			pdata->left_input_differential); +		if (ret) +			return ret; +		ret = adau1781_set_input_mode(adau, ADAU1781_RIGHT_PGA, +			pdata->right_input_differential); +		if (ret) +			return ret; +	} + +	if (pdata && pdata->use_dmic) { +		ret = snd_soc_dapm_new_controls(&codec->dapm, +			adau1781_dmic_dapm_widgets, +			ARRAY_SIZE(adau1781_dmic_dapm_widgets)); +		if (ret) +			return ret; +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau1781_dmic_dapm_routes, +			ARRAY_SIZE(adau1781_dmic_dapm_routes)); +		if (ret) +			return ret; +	} else { +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau1781_adc_dapm_routes, +			ARRAY_SIZE(adau1781_adc_dapm_routes)); +		if (ret) +			return ret; +	} + +	switch (adau->type) { +	case ADAU1381: +		firmware = ADAU1381_FIRMWARE; +		break; +	case ADAU1781: +		firmware = ADAU1781_FIRMWARE; +		break; +	default: +		return -EINVAL; +	} + +	ret = adau17x1_add_routes(codec); +	if (ret < 0) +		return ret; + +	ret = adau17x1_load_firmware(adau, codec->dev, firmware); +	if (ret) +		dev_warn(codec->dev, "Failed to load firmware\n"); + +	return 0; +} + +static const struct snd_soc_codec_driver adau1781_codec_driver = { +	.probe = adau1781_codec_probe, +	.suspend = adau17x1_suspend, +	.resume = adau17x1_resume, +	.set_bias_level = adau1781_set_bias_level, + +	.controls = adau1781_controls, +	.num_controls = ARRAY_SIZE(adau1781_controls), +	.dapm_widgets = adau1781_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets), +	.dapm_routes = adau1781_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes), +}; + +#define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ +	SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver adau1781_dai_driver = { +	.name = "adau-hifi", +	.playback = { +		.stream_name = "Playback", +		.channels_min = 2, +		.channels_max = 8, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = ADAU1781_FORMATS, +	}, +	.capture = { +		.stream_name = "Capture", +		.channels_min = 2, +		.channels_max = 8, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = ADAU1781_FORMATS, +	}, +	.ops = &adau17x1_dai_ops, +}; + +const struct regmap_config adau1781_regmap_config = { +	.val_bits		= 8, +	.reg_bits		= 16, +	.max_register		= 0x40f8, +	.reg_defaults		= adau1781_reg_defaults, +	.num_reg_defaults	= ARRAY_SIZE(adau1781_reg_defaults), +	.readable_reg		= adau1781_readable_register, +	.volatile_reg		= adau17x1_volatile_register, +	.cache_type		= REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(adau1781_regmap_config); + +int adau1781_probe(struct device *dev, struct regmap *regmap, +	enum adau17x1_type type, void (*switch_mode)(struct device *dev)) +{ +	int ret; + +	ret = adau17x1_probe(dev, regmap, type, switch_mode); +	if (ret) +		return ret; + +	return snd_soc_register_codec(dev, &adau1781_codec_driver, +		&adau1781_dai_driver, 1); +} +EXPORT_SYMBOL_GPL(adau1781_probe); + +MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1781.h b/sound/soc/codecs/adau1781.h new file mode 100644 index 00000000000..2b96e0a9ff2 --- /dev/null +++ b/sound/soc/codecs/adau1781.h @@ -0,0 +1,23 @@ +/* + * ADAU1381/ADAU1781 driver + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#ifndef __SOUND_SOC_CODECS_ADAU1781_H__ +#define __SOUND_SOC_CODECS_ADAU1781_H__ + +#include <linux/regmap.h> +#include "adau17x1.h" + +struct device; + +int adau1781_probe(struct device *dev, struct regmap *regmap, +	enum adau17x1_type type, void (*switch_mode)(struct device *dev)); + +extern const struct regmap_config adau1781_regmap_config; + +#endif diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c new file mode 100644 index 00000000000..2961fae9670 --- /dev/null +++ b/sound/soc/codecs/adau17x1.c @@ -0,0 +1,866 @@ +/* + * Common code for ADAU1X61 and ADAU1X81 codecs + * + * Copyright 2011-2014 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include <linux/gcd.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> + +#include "sigmadsp.h" +#include "adau17x1.h" + +static const char * const adau17x1_capture_mixer_boost_text[] = { +	"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", +}; + +static SOC_ENUM_SINGLE_DECL(adau17x1_capture_boost_enum, +	ADAU17X1_REC_POWER_MGMT, 5, adau17x1_capture_mixer_boost_text); + +static const char * const adau17x1_mic_bias_mode_text[] = { +	"Normal operation", "High performance", +}; + +static SOC_ENUM_SINGLE_DECL(adau17x1_mic_bias_mode_enum, +	ADAU17X1_MICBIAS, 3, adau17x1_mic_bias_mode_text); + +static const DECLARE_TLV_DB_MINMAX(adau17x1_digital_tlv, -9563, 0); + +static const struct snd_kcontrol_new adau17x1_controls[] = { +	SOC_DOUBLE_R_TLV("Digital Capture Volume", +		ADAU17X1_LEFT_INPUT_DIGITAL_VOL, +		ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, +		0, 0xff, 1, adau17x1_digital_tlv), +	SOC_DOUBLE_R_TLV("Digital Playback Volume", ADAU17X1_DAC_CONTROL1, +		ADAU17X1_DAC_CONTROL2, 0, 0xff, 1, adau17x1_digital_tlv), + +	SOC_SINGLE("ADC High Pass Filter Switch", ADAU17X1_ADC_CONTROL, +		5, 1, 0), +	SOC_SINGLE("Playback De-emphasis Switch", ADAU17X1_DAC_CONTROL0, +		2, 1, 0), + +	SOC_ENUM("Capture Boost", adau17x1_capture_boost_enum), + +	SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum), +}; + +static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(w->codec); +	int ret; + +	if (SND_SOC_DAPM_EVENT_ON(event)) { +		adau->pll_regs[5] = 1; +	} else { +		adau->pll_regs[5] = 0; +		/* Bypass the PLL when disabled, otherwise registers will become +		 * inaccessible. */ +		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, +			ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL, 0); +	} + +	/* The PLL register is 6 bytes long and can only be written at once. */ +	ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL, +			adau->pll_regs, ARRAY_SIZE(adau->pll_regs)); + +	if (SND_SOC_DAPM_EVENT_ON(event)) { +		mdelay(5); +		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, +			ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL, +			ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL); +	} + +	return 0; +} + +static const char * const adau17x1_mono_stereo_text[] = { +	"Stereo", +	"Mono Left Channel (L+R)", +	"Mono Right Channel (L+R)", +	"Mono (L+R)", +}; + +static SOC_ENUM_SINGLE_DECL(adau17x1_dac_mode_enum, +	ADAU17X1_DAC_CONTROL0, 6, adau17x1_mono_stereo_text); + +static const struct snd_kcontrol_new adau17x1_dac_mode_mux = +	SOC_DAPM_ENUM("DAC Mono-Stereo-Mode", adau17x1_dac_mode_enum); + +static const struct snd_soc_dapm_widget adau17x1_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY_S("PLL", 3, SND_SOC_NOPM, 0, 0, adau17x1_pll_event, +		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +	SND_SOC_DAPM_SUPPLY("AIFCLK", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU17X1_MICBIAS, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("Left Playback Enable", ADAU17X1_PLAY_POWER_MGMT, +		0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Right Playback Enable", ADAU17X1_PLAY_POWER_MGMT, +		1, 0, NULL, 0), + +	SND_SOC_DAPM_MUX("Left DAC Mode Mux", SND_SOC_NOPM, 0, 0, +		&adau17x1_dac_mode_mux), +	SND_SOC_DAPM_MUX("Right DAC Mode Mux", SND_SOC_NOPM, 0, 0, +		&adau17x1_dac_mode_mux), + +	SND_SOC_DAPM_ADC("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0), +	SND_SOC_DAPM_ADC("Right Decimator", NULL, ADAU17X1_ADC_CONTROL, 1, 0), +	SND_SOC_DAPM_DAC("Left DAC", NULL, ADAU17X1_DAC_CONTROL0, 0, 0), +	SND_SOC_DAPM_DAC("Right DAC", NULL, ADAU17X1_DAC_CONTROL0, 1, 0), +}; + +static const struct snd_soc_dapm_route adau17x1_dapm_routes[] = { +	{ "Left Decimator", NULL, "SYSCLK" }, +	{ "Right Decimator", NULL, "SYSCLK" }, +	{ "Left DAC", NULL, "SYSCLK" }, +	{ "Right DAC", NULL, "SYSCLK" }, +	{ "Capture", NULL, "SYSCLK" }, +	{ "Playback", NULL, "SYSCLK" }, + +	{ "Left DAC", NULL, "Left DAC Mode Mux" }, +	{ "Right DAC", NULL, "Right DAC Mode Mux" }, + +	{ "Capture", NULL, "AIFCLK" }, +	{ "Playback", NULL, "AIFCLK" }, +}; + +static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = { +	"SYSCLK", NULL, "PLL", +}; + +/* + * The MUX register for the Capture and Playback MUXs selects either DSP as + * source/destination or one of the TDM slots. The TDM slot is selected via + * snd_soc_dai_set_tdm_slot(), so we only expose whether to go to the DSP or + * directly to the DAI interface with this control. + */ +static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; +	struct snd_soc_dapm_update update; +	unsigned int stream = e->shift_l; +	unsigned int val, change; +	int reg; + +	if (ucontrol->value.enumerated.item[0] >= e->items) +		return -EINVAL; + +	switch (ucontrol->value.enumerated.item[0]) { +	case 0: +		val = 0; +		adau->dsp_bypass[stream] = false; +		break; +	default: +		val = (adau->tdm_slot[stream] * 2) + 1; +		adau->dsp_bypass[stream] = true; +		break; +	} + +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) +		reg = ADAU17X1_SERIAL_INPUT_ROUTE; +	else +		reg = ADAU17X1_SERIAL_OUTPUT_ROUTE; + +	change = snd_soc_test_bits(codec, reg, 0xff, val); +	if (change) { +		update.kcontrol = kcontrol; +		update.mask = 0xff; +		update.reg = reg; +		update.val = val; + +		snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol, +				ucontrol->value.enumerated.item[0], e, &update); +	} + +	return change; +} + +static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; +	unsigned int stream = e->shift_l; +	unsigned int reg, val; +	int ret; + +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) +		reg = ADAU17X1_SERIAL_INPUT_ROUTE; +	else +		reg = ADAU17X1_SERIAL_OUTPUT_ROUTE; + +	ret = regmap_read(adau->regmap, reg, &val); +	if (ret) +		return ret; + +	if (val != 0) +		val = 1; +	ucontrol->value.enumerated.item[0] = val; + +	return 0; +} + +#define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \ +	const struct snd_kcontrol_new _name = \ +		SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\ +			SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \ +				ARRAY_SIZE(_text), _text), \ +			adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put) + +static const char * const adau17x1_dac_mux_text[] = { +	"DSP", +	"AIFIN", +}; + +static const char * const adau17x1_capture_mux_text[] = { +	"DSP", +	"Decimator", +}; + +static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_dac_mux, "DAC Playback Mux", +	SNDRV_PCM_STREAM_PLAYBACK, adau17x1_dac_mux_text); + +static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_capture_mux, "Capture Mux", +	SNDRV_PCM_STREAM_CAPTURE, adau17x1_capture_mux_text); + +static const struct snd_soc_dapm_widget adau17x1_dsp_dapm_widgets[] = { +	SND_SOC_DAPM_PGA("DSP", ADAU17X1_DSP_RUN, 0, 0, NULL, 0), +	SND_SOC_DAPM_SIGGEN("DSP Siggen"), + +	SND_SOC_DAPM_MUX("DAC Playback Mux", SND_SOC_NOPM, 0, 0, +		&adau17x1_dac_mux), +	SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, +		&adau17x1_capture_mux), +}; + +static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = { +	{ "DAC Playback Mux", "DSP", "DSP" }, +	{ "DAC Playback Mux", "AIFIN", "Playback" }, + +	{ "Left DAC Mode Mux", "Stereo", "DAC Playback Mux" }, +	{ "Left DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" }, +	{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "DAC Playback Mux" }, +	{ "Right DAC Mode Mux", "Stereo", "DAC Playback Mux" }, +	{ "Right DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" }, +	{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "DAC Playback Mux" }, + +	{ "Capture Mux", "DSP", "DSP" }, +	{ "Capture Mux", "Decimator", "Left Decimator" }, +	{ "Capture Mux", "Decimator", "Right Decimator" }, + +	{ "Capture", NULL, "Capture Mux" }, + +	{ "DSP", NULL, "DSP Siggen" }, + +	{ "DSP", NULL, "Left Decimator" }, +	{ "DSP", NULL, "Right Decimator" }, +}; + +static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = { +	{ "Left DAC Mode Mux", "Stereo", "Playback" }, +	{ "Left DAC Mode Mux", "Mono (L+R)", "Playback" }, +	{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "Playback" }, +	{ "Right DAC Mode Mux", "Stereo", "Playback" }, +	{ "Right DAC Mode Mux", "Mono (L+R)", "Playback" }, +	{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "Playback" }, +	{ "Capture", NULL, "Left Decimator" }, +	{ "Capture", NULL, "Right Decimator" }, +}; + +bool adau17x1_has_dsp(struct adau *adau) +{ +	switch (adau->type) { +	case ADAU1761: +	case ADAU1381: +	case ADAU1781: +		return true; +	default: +		return false; +	} +} +EXPORT_SYMBOL_GPL(adau17x1_has_dsp); + +static int adau17x1_hw_params(struct snd_pcm_substream *substream, +	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	unsigned int val, div, dsp_div; +	unsigned int freq; + +	if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) +		freq = adau->pll_freq; +	else +		freq = adau->sysclk; + +	if (freq % params_rate(params) != 0) +		return -EINVAL; + +	switch (freq / params_rate(params)) { +	case 1024: /* fs */ +		div = 0; +		dsp_div = 1; +		break; +	case 6144: /* fs / 6 */ +		div = 1; +		dsp_div = 6; +		break; +	case 4096: /* fs / 4 */ +		div = 2; +		dsp_div = 5; +		break; +	case 3072: /* fs / 3 */ +		div = 3; +		dsp_div = 4; +		break; +	case 2048: /* fs / 2 */ +		div = 4; +		dsp_div = 3; +		break; +	case 1536: /* fs / 1.5 */ +		div = 5; +		dsp_div = 2; +		break; +	case 512: /* fs / 0.5 */ +		div = 6; +		dsp_div = 0; +		break; +	default: +		return -EINVAL; +	} + +	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0, +		ADAU17X1_CONVERTER0_CONVSR_MASK, div); +	if (adau17x1_has_dsp(adau)) { +		regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div); +		regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); +	} + +	if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) +		return 0; + +	switch (params_format(params)) { +	case SNDRV_PCM_FORMAT_S16_LE: +		val = ADAU17X1_SERIAL_PORT1_DELAY16; +		break; +	case SNDRV_PCM_FORMAT_S24_LE: +		val = ADAU17X1_SERIAL_PORT1_DELAY8; +		break; +	case SNDRV_PCM_FORMAT_S32_LE: +		val = ADAU17X1_SERIAL_PORT1_DELAY0; +		break; +	default: +		return -EINVAL; +	} + +	return regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1, +			ADAU17X1_SERIAL_PORT1_DELAY_MASK, val); +} + +static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, +	int source, unsigned int freq_in, unsigned int freq_out) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	unsigned int r, n, m, i, j; +	unsigned int div; +	int ret; + +	if (freq_in < 8000000 || freq_in > 27000000) +		return -EINVAL; + +	if (!freq_out) { +		r = 0; +		n = 0; +		m = 0; +		div = 0; +	} else { +		if (freq_out % freq_in != 0) { +			div = DIV_ROUND_UP(freq_in, 13500000); +			freq_in /= div; +			r = freq_out / freq_in; +			i = freq_out % freq_in; +			j = gcd(i, freq_in); +			n = i / j; +			m = freq_in / j; +			div--; +		} else { +			r = freq_out / freq_in; +			n = 0; +			m = 0; +			div = 0; +		} +		if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2) +			return -EINVAL; +	} + +	adau->pll_regs[0] = m >> 8; +	adau->pll_regs[1] = m & 0xff; +	adau->pll_regs[2] = n >> 8; +	adau->pll_regs[3] = n & 0xff; +	adau->pll_regs[4] = (r << 3) | (div << 1); +	if (m != 0) +		adau->pll_regs[4] |= 1; /* Fractional mode */ + +	/* The PLL register is 6 bytes long and can only be written at once. */ +	ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL, +			adau->pll_regs, ARRAY_SIZE(adau->pll_regs)); +	if (ret) +		return ret; + +	adau->pll_freq = freq_out; + +	return 0; +} + +static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai, +		int clk_id, unsigned int freq, int dir) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); +	struct snd_soc_dapm_context *dapm = &dai->codec->dapm; + +	switch (clk_id) { +	case ADAU17X1_CLK_SRC_MCLK: +	case ADAU17X1_CLK_SRC_PLL: +		break; +	default: +		return -EINVAL; +	} + +	adau->sysclk = freq; + +	if (adau->clk_src != clk_id) { +		if (clk_id == ADAU17X1_CLK_SRC_PLL) { +			snd_soc_dapm_add_routes(dapm, +				&adau17x1_dapm_pll_route, 1); +		} else { +			snd_soc_dapm_del_routes(dapm, +				&adau17x1_dapm_pll_route, 1); +		} +	} + +	adau->clk_src = clk_id; + +	return 0; +} + +static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, +		unsigned int fmt) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); +	unsigned int ctrl0, ctrl1; +	int lrclk_pol; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		ctrl0 = ADAU17X1_SERIAL_PORT0_MASTER; +		adau->master = true; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		ctrl0 = 0; +		adau->master = false; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		lrclk_pol = 0; +		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1; +		break; +	case SND_SOC_DAIFMT_LEFT_J: +	case SND_SOC_DAIFMT_RIGHT_J: +		lrclk_pol = 1; +		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0; +		break; +	case SND_SOC_DAIFMT_DSP_A: +		lrclk_pol = 1; +		ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE; +		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1; +		break; +	case SND_SOC_DAIFMT_DSP_B: +		lrclk_pol = 1; +		ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE; +		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		break; +	case SND_SOC_DAIFMT_IB_NF: +		ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL; +		break; +	case SND_SOC_DAIFMT_NB_IF: +		lrclk_pol = !lrclk_pol; +		break; +	case SND_SOC_DAIFMT_IB_IF: +		ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL; +		lrclk_pol = !lrclk_pol; +		break; +	default: +		return -EINVAL; +	} + +	if (lrclk_pol) +		ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL; + +	regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0); +	regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1); + +	adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + +	return 0; +} + +static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, +	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); +	unsigned int ser_ctrl0, ser_ctrl1; +	unsigned int conv_ctrl0, conv_ctrl1; + +	/* I2S mode */ +	if (slots == 0) { +		slots = 2; +		rx_mask = 3; +		tx_mask = 3; +		slot_width = 32; +	} + +	switch (slots) { +	case 2: +		ser_ctrl0 = ADAU17X1_SERIAL_PORT0_STEREO; +		break; +	case 4: +		ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM4; +		break; +	case 8: +		if (adau->type == ADAU1361) +			return -EINVAL; + +		ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM8; +		break; +	default: +		return -EINVAL; +	} + +	switch (slot_width * slots) { +	case 32: +		if (adau->type == ADAU1761) +			return -EINVAL; + +		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32; +		break; +	case 64: +		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK64; +		break; +	case 48: +		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK48; +		break; +	case 128: +		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK128; +		break; +	case 256: +		if (adau->type == ADAU1361) +			return -EINVAL; + +		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK256; +		break; +	default: +		return -EINVAL; +	} + +	switch (rx_mask) { +	case 0x03: +		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(1); +		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 0; +		break; +	case 0x0c: +		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(2); +		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 1; +		break; +	case 0x30: +		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(3); +		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 2; +		break; +	case 0xc0: +		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(4); +		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 3; +		break; +	default: +		return -EINVAL; +	} + +	switch (tx_mask) { +	case 0x03: +		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(1); +		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 0; +		break; +	case 0x0c: +		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(2); +		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 1; +		break; +	case 0x30: +		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(3); +		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 2; +		break; +	case 0xc0: +		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(4); +		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 3; +		break; +	default: +		return -EINVAL; +	} + +	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0, +		ADAU17X1_CONVERTER0_DAC_PAIR_MASK, conv_ctrl0); +	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER1, +		ADAU17X1_CONVERTER1_ADC_PAIR_MASK, conv_ctrl1); +	regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0, +		ADAU17X1_SERIAL_PORT0_TDM_MASK, ser_ctrl0); +	regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1, +		ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1); + +	if (!adau17x1_has_dsp(adau)) +		return 0; + +	if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) { +		regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE, +			(adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] * 2) + 1); +	} + +	if (adau->dsp_bypass[SNDRV_PCM_STREAM_CAPTURE]) { +		regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE, +			(adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] * 2) + 1); +	} + +	return 0; +} + +const struct snd_soc_dai_ops adau17x1_dai_ops = { +	.hw_params	= adau17x1_hw_params, +	.set_sysclk	= adau17x1_set_dai_sysclk, +	.set_fmt	= adau17x1_set_dai_fmt, +	.set_pll	= adau17x1_set_dai_pll, +	.set_tdm_slot	= adau17x1_set_dai_tdm_slot, +}; +EXPORT_SYMBOL_GPL(adau17x1_dai_ops); + +int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, +	enum adau17x1_micbias_voltage micbias) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(codec); + +	switch (micbias) { +	case ADAU17X1_MICBIAS_0_90_AVDD: +	case ADAU17X1_MICBIAS_0_65_AVDD: +		break; +	default: +		return -EINVAL; +	} + +	return regmap_write(adau->regmap, ADAU17X1_MICBIAS, micbias << 2); +} +EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage); + +bool adau17x1_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case ADAU17X1_CLOCK_CONTROL: +	case ADAU17X1_PLL_CONTROL: +	case ADAU17X1_REC_POWER_MGMT: +	case ADAU17X1_MICBIAS: +	case ADAU17X1_SERIAL_PORT0: +	case ADAU17X1_SERIAL_PORT1: +	case ADAU17X1_CONVERTER0: +	case ADAU17X1_CONVERTER1: +	case ADAU17X1_LEFT_INPUT_DIGITAL_VOL: +	case ADAU17X1_RIGHT_INPUT_DIGITAL_VOL: +	case ADAU17X1_ADC_CONTROL: +	case ADAU17X1_PLAY_POWER_MGMT: +	case ADAU17X1_DAC_CONTROL0: +	case ADAU17X1_DAC_CONTROL1: +	case ADAU17X1_DAC_CONTROL2: +	case ADAU17X1_SERIAL_PORT_PAD: +	case ADAU17X1_CONTROL_PORT_PAD0: +	case ADAU17X1_CONTROL_PORT_PAD1: +	case ADAU17X1_DSP_SAMPLING_RATE: +	case ADAU17X1_SERIAL_INPUT_ROUTE: +	case ADAU17X1_SERIAL_OUTPUT_ROUTE: +	case ADAU17X1_DSP_ENABLE: +	case ADAU17X1_DSP_RUN: +	case ADAU17X1_SERIAL_SAMPLING_RATE: +		return true; +	default: +		break; +	} +	return false; +} +EXPORT_SYMBOL_GPL(adau17x1_readable_register); + +bool adau17x1_volatile_register(struct device *dev, unsigned int reg) +{ +	/* SigmaDSP parameter and program memory */ +	if (reg < 0x4000) +		return true; + +	switch (reg) { +	/* The PLL register is 6 bytes long */ +	case ADAU17X1_PLL_CONTROL: +	case ADAU17X1_PLL_CONTROL + 1: +	case ADAU17X1_PLL_CONTROL + 2: +	case ADAU17X1_PLL_CONTROL + 3: +	case ADAU17X1_PLL_CONTROL + 4: +	case ADAU17X1_PLL_CONTROL + 5: +		return true; +	default: +		break; +	} + +	return false; +} +EXPORT_SYMBOL_GPL(adau17x1_volatile_register); + +int adau17x1_load_firmware(struct adau *adau, struct device *dev, +	const char *firmware) +{ +	int ret; +	int dspsr; + +	ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr); +	if (ret) +		return ret; + +	regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1); +	regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf); + +	ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware); +	if (ret) { +		regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0); +		return ret; +	} +	regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dspsr); + +	return 0; +} +EXPORT_SYMBOL_GPL(adau17x1_load_firmware); + +int adau17x1_add_widgets(struct snd_soc_codec *codec) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	int ret; + +	ret = snd_soc_add_codec_controls(codec, adau17x1_controls, +		ARRAY_SIZE(adau17x1_controls)); +	if (ret) +		return ret; +	ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets, +		ARRAY_SIZE(adau17x1_dapm_widgets)); +	if (ret) +		return ret; + +	if (adau17x1_has_dsp(adau)) { +		ret = snd_soc_dapm_new_controls(&codec->dapm, +			adau17x1_dsp_dapm_widgets, +			ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); +	} +	return ret; +} +EXPORT_SYMBOL_GPL(adau17x1_add_widgets); + +int adau17x1_add_routes(struct snd_soc_codec *codec) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(codec); +	int ret; + +	ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes, +		ARRAY_SIZE(adau17x1_dapm_routes)); +	if (ret) +		return ret; + +	if (adau17x1_has_dsp(adau)) { +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau17x1_dsp_dapm_routes, +			ARRAY_SIZE(adau17x1_dsp_dapm_routes)); +	} else { +		ret = snd_soc_dapm_add_routes(&codec->dapm, +			adau17x1_no_dsp_dapm_routes, +			ARRAY_SIZE(adau17x1_no_dsp_dapm_routes)); +	} +	return ret; +} +EXPORT_SYMBOL_GPL(adau17x1_add_routes); + +int adau17x1_suspend(struct snd_soc_codec *codec) +{ +	codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF); +	return 0; +} +EXPORT_SYMBOL_GPL(adau17x1_suspend); + +int adau17x1_resume(struct snd_soc_codec *codec) +{ +	struct adau *adau = snd_soc_codec_get_drvdata(codec); + +	if (adau->switch_mode) +		adau->switch_mode(codec->dev); + +	codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY); +	regcache_sync(adau->regmap); + +	return 0; +} +EXPORT_SYMBOL_GPL(adau17x1_resume); + +int adau17x1_probe(struct device *dev, struct regmap *regmap, +	enum adau17x1_type type, void (*switch_mode)(struct device *dev)) +{ +	struct adau *adau; + +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); + +	adau = devm_kzalloc(dev, sizeof(*adau), GFP_KERNEL); +	if (!adau) +		return -ENOMEM; + +	adau->regmap = regmap; +	adau->switch_mode = switch_mode; +	adau->type = type; + +	dev_set_drvdata(dev, adau); + +	if (switch_mode) +		switch_mode(dev); + +	return 0; +} +EXPORT_SYMBOL_GPL(adau17x1_probe); + +MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h new file mode 100644 index 00000000000..3ffabaf4c7a --- /dev/null +++ b/sound/soc/codecs/adau17x1.h @@ -0,0 +1,124 @@ +#ifndef __ADAU17X1_H__ +#define __ADAU17X1_H__ + +#include <linux/regmap.h> +#include <linux/platform_data/adau17x1.h> + +enum adau17x1_type { +	ADAU1361, +	ADAU1761, +	ADAU1381, +	ADAU1781, +}; + +enum adau17x1_pll { +	ADAU17X1_PLL, +}; + +enum adau17x1_pll_src { +	ADAU17X1_PLL_SRC_MCLK, +}; + +enum adau17x1_clk_src { +	ADAU17X1_CLK_SRC_MCLK, +	ADAU17X1_CLK_SRC_PLL, +}; + +struct adau { +	unsigned int sysclk; +	unsigned int pll_freq; + +	enum adau17x1_clk_src clk_src; +	enum adau17x1_type type; +	void (*switch_mode)(struct device *dev); + +	unsigned int dai_fmt; + +	uint8_t pll_regs[6]; + +	bool master; + +	unsigned int tdm_slot[2]; +	bool dsp_bypass[2]; + +	struct regmap *regmap; +}; + +int adau17x1_add_widgets(struct snd_soc_codec *codec); +int adau17x1_add_routes(struct snd_soc_codec *codec); +int adau17x1_probe(struct device *dev, struct regmap *regmap, +	enum adau17x1_type type, void (*switch_mode)(struct device *dev)); +int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, +	enum adau17x1_micbias_voltage micbias); +bool adau17x1_readable_register(struct device *dev, unsigned int reg); +bool adau17x1_volatile_register(struct device *dev, unsigned int reg); +int adau17x1_suspend(struct snd_soc_codec *codec); +int adau17x1_resume(struct snd_soc_codec *codec); + +extern const struct snd_soc_dai_ops adau17x1_dai_ops; + +int adau17x1_load_firmware(struct adau *adau, struct device *dev, +	const char *firmware); +bool adau17x1_has_dsp(struct adau *adau); + +#define ADAU17X1_CLOCK_CONTROL			0x4000 +#define ADAU17X1_PLL_CONTROL			0x4002 +#define ADAU17X1_REC_POWER_MGMT			0x4009 +#define ADAU17X1_MICBIAS			0x4010 +#define ADAU17X1_SERIAL_PORT0			0x4015 +#define ADAU17X1_SERIAL_PORT1			0x4016 +#define ADAU17X1_CONVERTER0			0x4017 +#define ADAU17X1_CONVERTER1			0x4018 +#define ADAU17X1_LEFT_INPUT_DIGITAL_VOL		0x401a +#define ADAU17X1_RIGHT_INPUT_DIGITAL_VOL	0x401b +#define ADAU17X1_ADC_CONTROL			0x4019 +#define ADAU17X1_PLAY_POWER_MGMT		0x4029 +#define ADAU17X1_DAC_CONTROL0			0x402a +#define ADAU17X1_DAC_CONTROL1			0x402b +#define ADAU17X1_DAC_CONTROL2			0x402c +#define ADAU17X1_SERIAL_PORT_PAD		0x402d +#define ADAU17X1_CONTROL_PORT_PAD0		0x402f +#define ADAU17X1_CONTROL_PORT_PAD1		0x4030 +#define ADAU17X1_DSP_SAMPLING_RATE		0x40eb +#define ADAU17X1_SERIAL_INPUT_ROUTE		0x40f2 +#define ADAU17X1_SERIAL_OUTPUT_ROUTE		0x40f3 +#define ADAU17X1_DSP_ENABLE			0x40f5 +#define ADAU17X1_DSP_RUN			0x40f6 +#define ADAU17X1_SERIAL_SAMPLING_RATE		0x40f8 + +#define ADAU17X1_SERIAL_PORT0_BCLK_POL		BIT(4) +#define ADAU17X1_SERIAL_PORT0_LRCLK_POL		BIT(3) +#define ADAU17X1_SERIAL_PORT0_MASTER		BIT(0) + +#define ADAU17X1_SERIAL_PORT1_DELAY1		0x00 +#define ADAU17X1_SERIAL_PORT1_DELAY0		0x01 +#define ADAU17X1_SERIAL_PORT1_DELAY8		0x02 +#define ADAU17X1_SERIAL_PORT1_DELAY16		0x03 +#define ADAU17X1_SERIAL_PORT1_DELAY_MASK	0x03 + +#define ADAU17X1_CLOCK_CONTROL_INFREQ_MASK	0x6 +#define ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL	BIT(3) +#define ADAU17X1_CLOCK_CONTROL_SYSCLK_EN	BIT(0) + +#define ADAU17X1_SERIAL_PORT1_BCLK32		(0x0 << 5) +#define ADAU17X1_SERIAL_PORT1_BCLK48		(0x1 << 5) +#define ADAU17X1_SERIAL_PORT1_BCLK64		(0x2 << 5) +#define ADAU17X1_SERIAL_PORT1_BCLK128		(0x3 << 5) +#define ADAU17X1_SERIAL_PORT1_BCLK256		(0x4 << 5) +#define ADAU17X1_SERIAL_PORT1_BCLK_MASK		(0x7 << 5) + +#define ADAU17X1_SERIAL_PORT0_STEREO		(0x0 << 1) +#define ADAU17X1_SERIAL_PORT0_TDM4		(0x1 << 1) +#define ADAU17X1_SERIAL_PORT0_TDM8		(0x2 << 1) +#define ADAU17X1_SERIAL_PORT0_TDM_MASK		(0x3 << 1) +#define ADAU17X1_SERIAL_PORT0_PULSE_MODE	BIT(5) + +#define ADAU17X1_CONVERTER0_DAC_PAIR(x)		(((x) - 1) << 5) +#define ADAU17X1_CONVERTER0_DAC_PAIR_MASK	(0x3 << 5) +#define ADAU17X1_CONVERTER1_ADC_PAIR(x)		((x) - 1) +#define ADAU17X1_CONVERTER1_ADC_PAIR_MASK	0x3 + +#define ADAU17X1_CONVERTER0_CONVSR_MASK		0x7 + + +#endif diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c new file mode 100644 index 00000000000..9700e8c838c --- /dev/null +++ b/sound/soc/codecs/adau1977-i2c.c @@ -0,0 +1,59 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "adau1977.h" + +static int adau1977_i2c_probe(struct i2c_client *client, +	const struct i2c_device_id *id) +{ +	struct regmap_config config; + +	config = adau1977_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 8; + +	return adau1977_probe(&client->dev, +		devm_regmap_init_i2c(client, &config), +		id->driver_data, NULL); +} + +static int adau1977_i2c_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static const struct i2c_device_id adau1977_i2c_ids[] = { +	{ "adau1977", ADAU1977 }, +	{ "adau1978", ADAU1978 }, +	{ "adau1979", ADAU1978 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); + +static struct i2c_driver adau1977_i2c_driver = { +	.driver = { +		.name = "adau1977", +		.owner = THIS_MODULE, +	}, +	.probe = adau1977_i2c_probe, +	.remove = adau1977_i2c_remove, +	.id_table = adau1977_i2c_ids, +}; +module_i2c_driver(adau1977_i2c_driver); + +MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c new file mode 100644 index 00000000000..b05cf5da3a9 --- /dev/null +++ b/sound/soc/codecs/adau1977-spi.c @@ -0,0 +1,76 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <sound/soc.h> + +#include "adau1977.h" + +static void adau1977_spi_switch_mode(struct device *dev) +{ +	struct spi_device *spi = to_spi_device(dev); + +	/* +	 * To get the device into SPI mode CLATCH has to be pulled low three +	 * times.  Do this by issuing three dummy reads. +	 */ +	spi_w8r8(spi, 0x00); +	spi_w8r8(spi, 0x00); +	spi_w8r8(spi, 0x00); +} + +static int adau1977_spi_probe(struct spi_device *spi) +{ +	const struct spi_device_id *id = spi_get_device_id(spi); +	struct regmap_config config; + +	if (!id) +		return -EINVAL; + +	config = adau1977_regmap_config; +	config.val_bits = 8; +	config.reg_bits = 16; +	config.read_flag_mask = 0x1; + +	return adau1977_probe(&spi->dev, +		devm_regmap_init_spi(spi, &config), +		id->driver_data, adau1977_spi_switch_mode); +} + +static int adau1977_spi_remove(struct spi_device *spi) +{ +	snd_soc_unregister_codec(&spi->dev); +	return 0; +} + +static const struct spi_device_id adau1977_spi_ids[] = { +	{ "adau1977", ADAU1977 }, +	{ "adau1978", ADAU1978 }, +	{ "adau1979", ADAU1978 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, adau1977_spi_ids); + +static struct spi_driver adau1977_spi_driver = { +	.driver = { +		.name = "adau1977", +		.owner = THIS_MODULE, +	}, +	.probe = adau1977_spi_probe, +	.remove = adau1977_spi_remove, +	.id_table = adau1977_spi_ids, +}; +module_spi_driver(adau1977_spi_driver); + +MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c new file mode 100644 index 00000000000..fd55da7cb9d --- /dev/null +++ b/sound/soc/codecs/adau1977.c @@ -0,0 +1,1018 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_data/adau1977.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "adau1977.h" + +#define ADAU1977_REG_POWER		0x00 +#define ADAU1977_REG_PLL		0x01 +#define ADAU1977_REG_BOOST		0x02 +#define ADAU1977_REG_MICBIAS		0x03 +#define ADAU1977_REG_BLOCK_POWER_SAI	0x04 +#define ADAU1977_REG_SAI_CTRL0		0x05 +#define ADAU1977_REG_SAI_CTRL1		0x06 +#define ADAU1977_REG_CMAP12		0x07 +#define ADAU1977_REG_CMAP34		0x08 +#define ADAU1977_REG_SAI_OVERTEMP	0x09 +#define ADAU1977_REG_POST_ADC_GAIN(x)	(0x0a + (x)) +#define ADAU1977_REG_MISC_CONTROL	0x0e +#define ADAU1977_REG_DIAG_CONTROL	0x10 +#define ADAU1977_REG_STATUS(x)		(0x11 + (x)) +#define ADAU1977_REG_DIAG_IRQ1		0x15 +#define ADAU1977_REG_DIAG_IRQ2		0x16 +#define ADAU1977_REG_ADJUST1		0x17 +#define ADAU1977_REG_ADJUST2		0x18 +#define ADAU1977_REG_ADC_CLIP		0x19 +#define ADAU1977_REG_DC_HPF_CAL		0x1a + +#define ADAU1977_POWER_RESET			BIT(7) +#define ADAU1977_POWER_PWUP			BIT(0) + +#define ADAU1977_PLL_CLK_S			BIT(4) +#define ADAU1977_PLL_MCS_MASK			0x7 + +#define ADAU1977_MICBIAS_MB_VOLTS_MASK		0xf0 +#define ADAU1977_MICBIAS_MB_VOLTS_OFFSET	4 + +#define ADAU1977_BLOCK_POWER_SAI_LR_POL		BIT(7) +#define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE	BIT(6) +#define ADAU1977_BLOCK_POWER_SAI_LDO_EN		BIT(5) + +#define ADAU1977_SAI_CTRL0_FMT_MASK		(0x3 << 6) +#define ADAU1977_SAI_CTRL0_FMT_I2S		(0x0 << 6) +#define ADAU1977_SAI_CTRL0_FMT_LJ		(0x1 << 6) +#define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT		(0x2 << 6) +#define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT		(0x3 << 6) + +#define ADAU1977_SAI_CTRL0_SAI_MASK		(0x7 << 3) +#define ADAU1977_SAI_CTRL0_SAI_I2S		(0x0 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_2		(0x1 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_4		(0x2 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_8		(0x3 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_16		(0x4 << 3) + +#define ADAU1977_SAI_CTRL0_FS_MASK		(0x7) +#define ADAU1977_SAI_CTRL0_FS_8000_12000	(0x0) +#define ADAU1977_SAI_CTRL0_FS_16000_24000	(0x1) +#define ADAU1977_SAI_CTRL0_FS_32000_48000	(0x2) +#define ADAU1977_SAI_CTRL0_FS_64000_96000	(0x3) +#define ADAU1977_SAI_CTRL0_FS_128000_192000	(0x4) + +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK	(0x3 << 5) +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32	(0x0 << 5) +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24	(0x1 << 5) +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16	(0x2 << 5) +#define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK	(0x1 << 4) +#define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT	(0x1 << 4) +#define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT	(0x0 << 4) +#define ADAU1977_SAI_CTRL1_LRCLK_PULSE		BIT(3) +#define ADAU1977_SAI_CTRL1_MSB			BIT(2) +#define ADAU1977_SAI_CTRL1_BCLKRATE_16		(0x1 << 1) +#define ADAU1977_SAI_CTRL1_BCLKRATE_32		(0x0 << 1) +#define ADAU1977_SAI_CTRL1_BCLKRATE_MASK	(0x1 << 1) +#define ADAU1977_SAI_CTRL1_MASTER		BIT(0) + +#define ADAU1977_SAI_OVERTEMP_DRV_C(x)		BIT(4 + (x)) +#define ADAU1977_SAI_OVERTEMP_DRV_HIZ		BIT(3) + +#define ADAU1977_MISC_CONTROL_SUM_MODE_MASK	(0x3 << 6) +#define ADAU1977_MISC_CONTROL_SUM_MODE_1CH	(0x2 << 6) +#define ADAU1977_MISC_CONTROL_SUM_MODE_2CH	(0x1 << 6) +#define ADAU1977_MISC_CONTROL_SUM_MODE_4CH	(0x0 << 6) +#define ADAU1977_MISC_CONTROL_MMUTE		BIT(4) +#define ADAU1977_MISC_CONTROL_DC_CAL		BIT(0) + +#define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET	4 +#define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET	0 + +struct adau1977 { +	struct regmap *regmap; +	bool right_j; +	unsigned int sysclk; +	enum adau1977_sysclk_src sysclk_src; +	struct gpio_desc *reset_gpio; +	enum adau1977_type type; + +	struct regulator *avdd_reg; +	struct regulator *dvdd_reg; + +	struct snd_pcm_hw_constraint_list constraints; + +	struct device *dev; +	void (*switch_mode)(struct device *dev); + +	unsigned int max_master_fs; +	unsigned int slot_width; +	bool enabled; +	bool master; +}; + +static const struct reg_default adau1977_reg_defaults[] = { +	{ 0x00, 0x00 }, +	{ 0x01, 0x41 }, +	{ 0x02, 0x4a }, +	{ 0x03, 0x7d }, +	{ 0x04, 0x3d }, +	{ 0x05, 0x02 }, +	{ 0x06, 0x00 }, +	{ 0x07, 0x10 }, +	{ 0x08, 0x32 }, +	{ 0x09, 0xf0 }, +	{ 0x0a, 0xa0 }, +	{ 0x0b, 0xa0 }, +	{ 0x0c, 0xa0 }, +	{ 0x0d, 0xa0 }, +	{ 0x0e, 0x02 }, +	{ 0x10, 0x0f }, +	{ 0x15, 0x20 }, +	{ 0x16, 0x00 }, +	{ 0x17, 0x00 }, +	{ 0x18, 0x00 }, +	{ 0x1a, 0x00 }, +}; + +static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000); + +static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS, +		3, 0, NULL, 0) +}; + +static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI, +		4, 0, NULL, 0), + +	SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0), +	SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0), +	SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0), +	SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0), + +	SND_SOC_DAPM_INPUT("AIN1"), +	SND_SOC_DAPM_INPUT("AIN2"), +	SND_SOC_DAPM_INPUT("AIN3"), +	SND_SOC_DAPM_INPUT("AIN4"), + +	SND_SOC_DAPM_OUTPUT("VREF"), +}; + +static const struct snd_soc_dapm_route adau1977_dapm_routes[] = { +	{ "ADC1", NULL, "AIN1" }, +	{ "ADC2", NULL, "AIN2" }, +	{ "ADC3", NULL, "AIN3" }, +	{ "ADC4", NULL, "AIN4" }, + +	{ "ADC1", NULL, "Vref" }, +	{ "ADC2", NULL, "Vref" }, +	{ "ADC3", NULL, "Vref" }, +	{ "ADC4", NULL, "Vref" }, + +	{ "VREF", NULL, "Vref" }, +}; + +#define ADAU1977_VOLUME(x) \ +	SOC_SINGLE_TLV("ADC" #x " Capture Volume", \ +		ADAU1977_REG_POST_ADC_GAIN((x) - 1), \ +		0, 255, 1, adau1977_adc_gain) + +#define ADAU1977_HPF_SWITCH(x) \ +	SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \ +		ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) + +#define ADAU1977_DC_SUB_SWITCH(x) \ +	SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \ +		ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) + +static const struct snd_kcontrol_new adau1977_snd_controls[] = { +	ADAU1977_VOLUME(1), +	ADAU1977_VOLUME(2), +	ADAU1977_VOLUME(3), +	ADAU1977_VOLUME(4), + +	ADAU1977_HPF_SWITCH(1), +	ADAU1977_HPF_SWITCH(2), +	ADAU1977_HPF_SWITCH(3), +	ADAU1977_HPF_SWITCH(4), + +	ADAU1977_DC_SUB_SWITCH(1), +	ADAU1977_DC_SUB_SWITCH(2), +	ADAU1977_DC_SUB_SWITCH(3), +	ADAU1977_DC_SUB_SWITCH(4), +}; + +static int adau1977_reset(struct adau1977 *adau1977) +{ +	int ret; + +	/* +	 * The reset bit is obviously volatile, but we need to be able to cache +	 * the other bits in the register, so we can't just mark the whole +	 * register as volatile. Since this is the only place where we'll ever +	 * touch the reset bit just bypass the cache for this operation. +	 */ +	regcache_cache_bypass(adau1977->regmap, true); +	ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER, +			ADAU1977_POWER_RESET); +	regcache_cache_bypass(adau1977->regmap, false); +	if (ret) +		return ret; + +	return ret; +} + +/* + * Returns the appropriate setting for ths FS field in the CTRL0 register + * depending on the rate. + */ +static int adau1977_lookup_fs(unsigned int rate) +{ +	if (rate >= 8000 && rate <= 12000) +		return ADAU1977_SAI_CTRL0_FS_8000_12000; +	else if (rate >= 16000 && rate <= 24000) +		return ADAU1977_SAI_CTRL0_FS_16000_24000; +	else if (rate >= 32000 && rate <= 48000) +		return ADAU1977_SAI_CTRL0_FS_32000_48000; +	else if (rate >= 64000 && rate <= 96000) +		return ADAU1977_SAI_CTRL0_FS_64000_96000; +	else if (rate >= 128000 && rate <= 192000) +		return ADAU1977_SAI_CTRL0_FS_128000_192000; +	else +		return -EINVAL; +} + +static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate, +	unsigned int fs) +{ +	unsigned int mcs; + +	/* +	 * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs +	 * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs +	 * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate) +	 */ + +	rate *= 512 >> fs; + +	if (adau1977->sysclk % rate != 0) +		return -EINVAL; + +	mcs = adau1977->sysclk / rate; + +	/* The factors configured by MCS are 1, 2, 3, 4, 6 */ +	if (mcs < 1 || mcs > 6 || mcs == 5) +		return -EINVAL; + +	mcs = mcs - 1; +	if (mcs == 5) +		mcs = 4; + +	return mcs; +} + +static int adau1977_hw_params(struct snd_pcm_substream *substream, +	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); +	unsigned int rate = params_rate(params); +	unsigned int slot_width; +	unsigned int ctrl0, ctrl0_mask; +	unsigned int ctrl1; +	int mcs, fs; +	int ret; + +	fs = adau1977_lookup_fs(rate); +	if (fs < 0) +		return fs; + +	if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) { +		mcs = adau1977_lookup_mcs(adau1977, rate, fs); +		if (mcs < 0) +			return mcs; +	} else { +		mcs = 0; +	} + +	ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK; +	ctrl0 = fs; + +	if (adau1977->right_j) { +		switch (params_width(params)) { +		case 16: +			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT; +			break; +		case 24: +			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; +			break; +		default: +			return -EINVAL; +		} +		ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK; +	} + +	if (adau1977->master) { +		switch (params_width(params)) { +		case 16: +			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT; +			slot_width = 16; +			break; +		case 24: +		case 32: +			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT; +			slot_width = 32; +			break; +		default: +			return -EINVAL; +		} + +		/* In TDM mode there is a fixed slot width */ +		if (adau1977->slot_width) +			slot_width = adau1977->slot_width; + +		if (slot_width == 16) +			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16; +		else +			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32; + +		ret = regmap_update_bits(adau1977->regmap, +			ADAU1977_REG_SAI_CTRL1, +			ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK | +			ADAU1977_SAI_CTRL1_BCLKRATE_MASK, +			ctrl1); +		if (ret < 0) +			return ret; +	} + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, +				ctrl0_mask, ctrl0); +	if (ret < 0) +		return ret; + +	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, +				ADAU1977_PLL_MCS_MASK, mcs); +} + +static int adau1977_power_disable(struct adau1977 *adau1977) +{ +	int ret = 0; + +	if (!adau1977->enabled) +		return 0; + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, +		ADAU1977_POWER_PWUP, 0); +	if (ret) +		return ret; + +	regcache_mark_dirty(adau1977->regmap); + +	if (adau1977->reset_gpio) +		gpiod_set_value_cansleep(adau1977->reset_gpio, 0); + +	regcache_cache_only(adau1977->regmap, true); + +	regulator_disable(adau1977->avdd_reg); +	if (adau1977->dvdd_reg) +		regulator_disable(adau1977->dvdd_reg); + +	adau1977->enabled = false; + +	return 0; +} + +static int adau1977_power_enable(struct adau1977 *adau1977) +{ +	unsigned int val; +	int ret = 0; + +	if (adau1977->enabled) +		return 0; + +	ret = regulator_enable(adau1977->avdd_reg); +	if (ret) +		return ret; + +	if (adau1977->dvdd_reg) { +		ret = regulator_enable(adau1977->dvdd_reg); +		if (ret) +			goto err_disable_avdd; +	} + +	if (adau1977->reset_gpio) +		gpiod_set_value_cansleep(adau1977->reset_gpio, 1); + +	regcache_cache_only(adau1977->regmap, false); + +	if (adau1977->switch_mode) +		adau1977->switch_mode(adau1977->dev); + +	ret = adau1977_reset(adau1977); +	if (ret) +		goto err_disable_dvdd; + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, +		ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP); +	if (ret) +		goto err_disable_dvdd; + +	ret = regcache_sync(adau1977->regmap); +	if (ret) +		goto err_disable_dvdd; + +	/* +	 * The PLL register is not affected by the software reset. It is +	 * possible that the value of the register was changed to the +	 * default value while we were in cache only mode. In this case +	 * regcache_sync will skip over it and we have to manually sync +	 * it. +	 */ +	ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val); +	if (ret) +		goto err_disable_dvdd; + +	if (val == 0x41) { +		regcache_cache_bypass(adau1977->regmap, true); +		ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL, +			0x41); +		if (ret) +			goto err_disable_dvdd; +		regcache_cache_bypass(adau1977->regmap, false); +	} + +	adau1977->enabled = true; + +	return ret; + +err_disable_dvdd: +	if (adau1977->dvdd_reg) +		regulator_disable(adau1977->dvdd_reg); +err_disable_avdd: +		regulator_disable(adau1977->avdd_reg); +	return ret; +} + +static int adau1977_set_bias_level(struct snd_soc_codec *codec, +	enum snd_soc_bias_level level) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); +	int ret = 0; + +	switch (level) { +	case SND_SOC_BIAS_ON: +		break; +	case SND_SOC_BIAS_PREPARE: +		break; +	case SND_SOC_BIAS_STANDBY: +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) +			ret = adau1977_power_enable(adau1977); +		break; +	case SND_SOC_BIAS_OFF: +		ret = adau1977_power_disable(adau1977); +		break; +	} + +	if (ret) +		return ret; + +	codec->dapm.bias_level = level; + +	return 0; +} + +static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, +	unsigned int rx_mask, int slots, int width) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); +	unsigned int ctrl0, ctrl1, drv; +	unsigned int slot[4]; +	unsigned int i; +	int ret; + +	if (slots == 0) { +		/* 0 = No fixed slot width */ +		adau1977->slot_width = 0; +		adau1977->max_master_fs = 192000; +		return regmap_update_bits(adau1977->regmap, +			ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK, +			ADAU1977_SAI_CTRL0_SAI_I2S); +	} + +	if (rx_mask == 0 || tx_mask != 0) +		return -EINVAL; + +	drv = 0; +	for (i = 0; i < 4; i++) { +		slot[i] = __ffs(rx_mask); +		drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i); +		rx_mask &= ~(1 << slot[i]); +		if (slot[i] >= slots) +			return -EINVAL; +		if (rx_mask == 0) +			break; +	} + +	if (rx_mask != 0) +		return -EINVAL; + +	switch (width) { +	case 16: +		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16; +		break; +	case 24: +		/* We can only generate 16 bit or 32 bit wide slots */ +		if (adau1977->master) +			return -EINVAL; +		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24; +		break; +	case 32: +		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32; +		break; +	default: +		return -EINVAL; +	} + +	switch (slots) { +	case 2: +		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2; +		break; +	case 4: +		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4; +		break; +	case 8: +		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8; +		break; +	case 16: +		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16; +		break; +	default: +		return -EINVAL; +	} + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, +		ADAU1977_SAI_OVERTEMP_DRV_C(0) | +		ADAU1977_SAI_OVERTEMP_DRV_C(1) | +		ADAU1977_SAI_OVERTEMP_DRV_C(2) | +		ADAU1977_SAI_OVERTEMP_DRV_C(3), drv); +	if (ret) +		return ret; + +	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12, +		(slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | +		(slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); +	if (ret) +		return ret; + +	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34, +		(slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | +		(slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); +	if (ret) +		return ret; + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, +		ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0); +	if (ret) +		return ret; + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, +		ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1); +	if (ret) +		return ret; + +	adau1977->slot_width = width; + +	/* In master mode the maximum bitclock is 24.576 MHz */ +	adau1977->max_master_fs = min(192000, 24576000 / width / slots); + +	return 0; +} + +static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); +	unsigned int val; + +	if (mute) +		val = ADAU1977_MISC_CONTROL_MMUTE; +	else +		val = 0; + +	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL, +			ADAU1977_MISC_CONTROL_MMUTE, val); +} + +static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); +	unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0; +	bool invert_lrclk; +	int ret; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBS_CFS: +		adau1977->master = false; +		break; +	case SND_SOC_DAIFMT_CBM_CFM: +		ctrl1 |= ADAU1977_SAI_CTRL1_MASTER; +		adau1977->master = true; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		invert_lrclk = false; +		break; +	case SND_SOC_DAIFMT_IB_NF: +		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; +		invert_lrclk = false; +		break; +	case SND_SOC_DAIFMT_NB_IF: +		invert_lrclk = true; +		break; +	case SND_SOC_DAIFMT_IB_IF: +		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; +		invert_lrclk = true; +		break; +	default: +		return -EINVAL; +	} + +	adau1977->right_j = false; +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; +		invert_lrclk = !invert_lrclk; +		break; +	case SND_SOC_DAIFMT_RIGHT_J: +		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; +		adau1977->right_j = true; +		invert_lrclk = !invert_lrclk; +		break; +	case SND_SOC_DAIFMT_DSP_A: +		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; +		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; +		invert_lrclk = false; +		break; +	case SND_SOC_DAIFMT_DSP_B: +		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; +		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; +		invert_lrclk = false; +		break; +	default: +		return -EINVAL; +	} + +	if (invert_lrclk) +		block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL; + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, +		ADAU1977_BLOCK_POWER_SAI_LR_POL | +		ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power); +	if (ret) +		return ret; + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, +		ADAU1977_SAI_CTRL0_FMT_MASK, +		ctrl0); +	if (ret) +		return ret; + +	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, +		ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE, +		ctrl1); +} + +static int adau1977_startup(struct snd_pcm_substream *substream, +	struct snd_soc_dai *dai) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); +	u64 formats = 0; + +	if (adau1977->slot_width == 16) +		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE; +	else if (adau1977->right_j || adau1977->slot_width == 24) +		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE; + +	snd_pcm_hw_constraint_list(substream->runtime, 0, +		SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints); + +	if (adau1977->master) +		snd_pcm_hw_constraint_minmax(substream->runtime, +			SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs); + +	if (formats != 0) +		snd_pcm_hw_constraint_mask64(substream->runtime, +			SNDRV_PCM_HW_PARAM_FORMAT, formats); + +	return 0; +} + +static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); +	unsigned int val; + +	if (tristate) +		val = ADAU1977_SAI_OVERTEMP_DRV_HIZ; +	else +		val = 0; + +	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, +		ADAU1977_SAI_OVERTEMP_DRV_HIZ, val); +} + +static const struct snd_soc_dai_ops adau1977_dai_ops = { +	.startup	= adau1977_startup, +	.hw_params	= adau1977_hw_params, +	.mute_stream	= adau1977_mute, +	.set_fmt	= adau1977_set_dai_fmt, +	.set_tdm_slot	= adau1977_set_tdm_slot, +	.set_tristate	= adau1977_set_tristate, +}; + +static struct snd_soc_dai_driver adau1977_dai = { +	.name = "adau1977-hifi", +	.capture = { +		.stream_name = "Capture", +		.channels_min = 1, +		.channels_max = 4, +		.rates = SNDRV_PCM_RATE_KNOT, +		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | +		    SNDRV_PCM_FMTBIT_S32_LE, +		.sig_bits = 24, +	}, +	.ops = &adau1977_dai_ops, +}; + +static const unsigned int adau1977_rates[] = { +	8000, 16000, 32000, 64000, 128000, +	11025, 22050, 44100, 88200, 172400, +	12000, 24000, 48000, 96000, 192000, +}; + +#define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f +#define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0 +#define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00 +/* All rates >= 32000 */ +#define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c + +static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq) +{ +	unsigned int mcs; + +	if (mclk % (base_freq * 128) != 0) +		return false; + +	mcs = mclk / (128 * base_freq); +	if (mcs < 1 || mcs > 6 || mcs == 5) +		return false; + +	return true; +} + +static int adau1977_set_sysclk(struct snd_soc_codec *codec, +	int clk_id, int source, unsigned int freq, int dir) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); +	unsigned int mask = 0; +	unsigned int clk_src; +	unsigned int ret; + +	if (dir != SND_SOC_CLOCK_IN) +		return -EINVAL; + +	if (clk_id != ADAU1977_SYSCLK) +		return -EINVAL; + +	switch (source) { +	case ADAU1977_SYSCLK_SRC_MCLK: +		clk_src = 0; +		break; +	case ADAU1977_SYSCLK_SRC_LRCLK: +		clk_src = ADAU1977_PLL_CLK_S; +		break; +	default: +		return -EINVAL; +	} + +	if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) { +		if (freq < 4000000 || freq > 36864000) +			return -EINVAL; + +		if (adau1977_check_sysclk(freq, 32000)) +			mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000; +		if (adau1977_check_sysclk(freq, 44100)) +			mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100; +		if (adau1977_check_sysclk(freq, 48000)) +			mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000; + +		if (mask == 0) +			return -EINVAL; +	} else if (source == ADAU1977_SYSCLK_SRC_LRCLK) { +		mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK; +	} + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, +		ADAU1977_PLL_CLK_S, clk_src); +	if (ret) +		return ret; + +	adau1977->constraints.mask = mask; +	adau1977->sysclk_src = source; +	adau1977->sysclk = freq; + +	return 0; +} + +static int adau1977_codec_probe(struct snd_soc_codec *codec) +{ +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); +	int ret; + +	switch (adau1977->type) { +	case ADAU1977: +		ret = snd_soc_dapm_new_controls(&codec->dapm, +			adau1977_micbias_dapm_widgets, +			ARRAY_SIZE(adau1977_micbias_dapm_widgets)); +		if (ret < 0) +			return ret; +		break; +	default: +		break; +	} + +	return 0; +} + +static struct snd_soc_codec_driver adau1977_codec_driver = { +	.probe = adau1977_codec_probe, +	.set_bias_level = adau1977_set_bias_level, +	.set_sysclk = adau1977_set_sysclk, +	.idle_bias_off = true, + +	.controls = adau1977_snd_controls, +	.num_controls = ARRAY_SIZE(adau1977_snd_controls), +	.dapm_widgets = adau1977_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets), +	.dapm_routes = adau1977_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), +}; + +static int adau1977_setup_micbias(struct adau1977 *adau1977) +{ +	struct adau1977_platform_data *pdata = adau1977->dev->platform_data; +	unsigned int micbias; + +	if (pdata) { +		micbias = pdata->micbias; +		if (micbias > ADAU1977_MICBIAS_9V0) +			return -EINVAL; + +	} else { +		micbias = ADAU1977_MICBIAS_8V5; +	} + +	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS, +		ADAU1977_MICBIAS_MB_VOLTS_MASK, +		micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET); +} + +int adau1977_probe(struct device *dev, struct regmap *regmap, +	enum adau1977_type type, void (*switch_mode)(struct device *dev)) +{ +	unsigned int power_off_mask; +	struct adau1977 *adau1977; +	int ret; + +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); + +	adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL); +	if (adau1977 == NULL) +		return -ENOMEM; + +	adau1977->dev = dev; +	adau1977->type = type; +	adau1977->regmap = regmap; +	adau1977->switch_mode = switch_mode; +	adau1977->max_master_fs = 192000; + +	adau1977->constraints.list = adau1977_rates; +	adau1977->constraints.count = ARRAY_SIZE(adau1977_rates); + +	adau1977->avdd_reg = devm_regulator_get(dev, "AVDD"); +	if (IS_ERR(adau1977->avdd_reg)) +		return PTR_ERR(adau1977->avdd_reg); + +	adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD"); +	if (IS_ERR(adau1977->dvdd_reg)) { +		if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV) +			return PTR_ERR(adau1977->dvdd_reg); +		adau1977->dvdd_reg = NULL; +	} + +	adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); +	if (IS_ERR(adau1977->reset_gpio)) { +		ret = PTR_ERR(adau1977->reset_gpio); +		if (ret != -ENOENT && ret != -ENOSYS) +			return PTR_ERR(adau1977->reset_gpio); +		adau1977->reset_gpio = NULL; +	} + +	dev_set_drvdata(dev, adau1977); + +	if (adau1977->reset_gpio) { +		ret = gpiod_direction_output(adau1977->reset_gpio, 0); +		if (ret) +			return ret; +		ndelay(100); +	} + +	ret = adau1977_power_enable(adau1977); +	if (ret) +		return ret; + +	if (type == ADAU1977) { +		ret = adau1977_setup_micbias(adau1977); +		if (ret) +			goto err_poweroff; +	} + +	if (adau1977->dvdd_reg) +		power_off_mask = ~0; +	else +		power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN; + +	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, +				power_off_mask, 0x00); +	if (ret) +		goto err_poweroff; + +	ret = adau1977_power_disable(adau1977); +	if (ret) +		return ret; + +	return snd_soc_register_codec(dev, &adau1977_codec_driver, +			&adau1977_dai, 1); + +err_poweroff: +	adau1977_power_disable(adau1977); +	return ret; + +} +EXPORT_SYMBOL_GPL(adau1977_probe); + +static bool adau1977_register_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case ADAU1977_REG_STATUS(0): +	case ADAU1977_REG_STATUS(1): +	case ADAU1977_REG_STATUS(2): +	case ADAU1977_REG_STATUS(3): +	case ADAU1977_REG_ADC_CLIP: +		return true; +	} + +	return false; +} + +const struct regmap_config adau1977_regmap_config = { +	.max_register = ADAU1977_REG_DC_HPF_CAL, +	.volatile_reg = adau1977_register_volatile, + +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults = adau1977_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults), +}; +EXPORT_SYMBOL_GPL(adau1977_regmap_config); + +MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h new file mode 100644 index 00000000000..95e714345a8 --- /dev/null +++ b/sound/soc/codecs/adau1977.h @@ -0,0 +1,37 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#ifndef __SOUND_SOC_CODECS_ADAU1977_H__ +#define __SOUND_SOC_CODECS_ADAU1977_H__ + +#include <linux/regmap.h> + +struct device; + +enum adau1977_type { +	ADAU1977, +	ADAU1978, +	ADAU1979, +}; + +int adau1977_probe(struct device *dev, struct regmap *regmap, +	enum adau1977_type type, void (*switch_mode)(struct device *dev)); + +extern const struct regmap_config adau1977_regmap_config; + +enum adau1977_clk_id { +	ADAU1977_SYSCLK, +}; + +enum adau1977_sysclk_src { +	ADAU1977_SYSCLK_SRC_MCLK, +	ADAU1977_SYSCLK_SRC_LRCLK, +}; + +#endif diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c new file mode 100644 index 00000000000..790fce33ab1 --- /dev/null +++ b/sound/soc/codecs/adav801.c @@ -0,0 +1,53 @@ +/* + * ADAV801 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "adav80x.h" + +static const struct spi_device_id adav80x_spi_id[] = { +	{ "adav801", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, adav80x_spi_id); + +static int adav80x_spi_probe(struct spi_device *spi) +{ +	struct regmap_config config; + +	config = adav80x_regmap_config; +	config.read_flag_mask = 0x01; + +	return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); +} + +static int adav80x_spi_remove(struct spi_device *spi) +{ +	snd_soc_unregister_codec(&spi->dev); +	return 0; +} + +static struct spi_driver adav80x_spi_driver = { +	.driver = { +		.name	= "adav801", +		.owner	= THIS_MODULE, +	}, +	.probe		= adav80x_spi_probe, +	.remove		= adav80x_spi_remove, +	.id_table	= adav80x_spi_id, +}; +module_spi_driver(adav80x_spi_driver); + +MODULE_DESCRIPTION("ASoC ADAV801 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c new file mode 100644 index 00000000000..66d9fce34e6 --- /dev/null +++ b/sound/soc/codecs/adav803.c @@ -0,0 +1,50 @@ +/* + * ADAV803 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "adav80x.h" + +static const struct i2c_device_id adav803_id[] = { +	{ "adav803", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, adav803_id); + +static int adav803_probe(struct i2c_client *client, +			     const struct i2c_device_id *id) +{ +	return adav80x_bus_probe(&client->dev, +		devm_regmap_init_i2c(client, &adav80x_regmap_config)); +} + +static int adav803_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static struct i2c_driver adav803_driver = { +	.driver = { +		.name = "adav803", +		.owner = THIS_MODULE, +	}, +	.probe = adav803_probe, +	.remove = adav803_remove, +	.id_table = adav803_id, +}; +module_i2c_driver(adav803_driver); + +MODULE_DESCRIPTION("ASoC ADAV803 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 15b012d0f22..c43b93fdf0d 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -8,17 +8,15 @@   * Licensed under the GPL-2 or later.   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/i2c.h> -#include <linux/spi/spi.h> +#include <linux/regmap.h>  #include <linux/slab.h> -#include <sound/core.h> +  #include <sound/pcm.h>  #include <sound/pcm_params.h> -#include <sound/tlv.h>  #include <sound/soc.h> +#include <sound/tlv.h>  #include "adav80x.h" @@ -115,22 +113,34 @@  #define ADAV80X_PLL_OUTE_SYSCLKPD(x)		BIT(2 - (x)) -static u8 adav80x_default_regs[] = { -	0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00, -	0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37, -	0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b, -	0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, -	0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee, -	0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f, -	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x52, 0x00, +static struct reg_default adav80x_reg_defaults[] = { +	{ ADAV80X_PLAYBACK_CTRL,	0x01 }, +	{ ADAV80X_AUX_IN_CTRL,		0x01 }, +	{ ADAV80X_REC_CTRL,		0x02 }, +	{ ADAV80X_AUX_OUT_CTRL,		0x01 }, +	{ ADAV80X_DPATH_CTRL1,		0xc0 }, +	{ ADAV80X_DPATH_CTRL2,		0x11 }, +	{ ADAV80X_DAC_CTRL1,		0x00 }, +	{ ADAV80X_DAC_CTRL2,		0x00 }, +	{ ADAV80X_DAC_CTRL3,		0x00 }, +	{ ADAV80X_DAC_L_VOL,		0xff }, +	{ ADAV80X_DAC_R_VOL,		0xff }, +	{ ADAV80X_PGA_L_VOL,		0x00 }, +	{ ADAV80X_PGA_R_VOL,		0x00 }, +	{ ADAV80X_ADC_CTRL1,		0x00 }, +	{ ADAV80X_ADC_CTRL2,		0x00 }, +	{ ADAV80X_ADC_L_VOL,		0xff }, +	{ ADAV80X_ADC_R_VOL,		0xff }, +	{ ADAV80X_PLL_CTRL1,		0x00 }, +	{ ADAV80X_PLL_CTRL2,		0x00 }, +	{ ADAV80X_ICLK_CTRL1,		0x00 }, +	{ ADAV80X_ICLK_CTRL2,		0x00 }, +	{ ADAV80X_PLL_CLK_SRC,		0x00 }, +	{ ADAV80X_PLL_OUTE,		0x00 },  };  struct adav80x { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	enum adav80x_clk_src clk_src;  	unsigned int sysclk; @@ -162,14 +172,14 @@ static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3);  static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3);  static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = -	SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum); +	SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum);  static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = -	SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum); +	SOC_DAPM_ENUM("Route", adav80x_capture_enum);  static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = -	SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum); +	SOC_DAPM_ENUM("Route", adav80x_dac_enum);  #define ADAV80X_MUX(name, ctrl) \ -	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) +	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)  static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {  	SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), @@ -298,14 +308,14 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec)  		val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;  	} -	return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, +	return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,  		ADAV80X_DAC_CTRL2_DEEMPH_MASK, val);  }  static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,  		struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);  	unsigned int deemph = ucontrol->value.enumerated.item[0]; @@ -320,7 +330,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,  static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = adav80x->deemph; @@ -394,10 +404,11 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  		return -EINVAL;  	} -	snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], +	regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],  		ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER,  		capture); -	snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback); +	regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1], +		playback);  	adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; @@ -407,6 +418,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  static int adav80x_set_adc_clock(struct snd_soc_codec *codec,  		unsigned int sample_rate)  { +	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);  	unsigned int val;  	if (sample_rate <= 48000) @@ -414,7 +426,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec,  	else  		val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; -	snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1, +	regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1,  		ADAV80X_ADC_CTRL1_MODULATOR_MASK, val);  	return 0; @@ -423,6 +435,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec,  static int adav80x_set_dac_clock(struct snd_soc_codec *codec,  		unsigned int sample_rate)  { +	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);  	unsigned int val;  	if (sample_rate <= 48000) @@ -430,7 +443,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,  	else  		val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; -	snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, +	regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,  		ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK,  		val); @@ -438,35 +451,36 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,  }  static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, -		struct snd_soc_dai *dai, snd_pcm_format_t format) +		struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)  { +	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);  	unsigned int val; -	switch (format) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		val = ADAV80X_CAPTURE_WORD_LEN16;  		break; -	case SNDRV_PCM_FORMAT_S18_3LE: +	case 18:  		val = ADAV80X_CAPTRUE_WORD_LEN18;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		val = ADAV80X_CAPTURE_WORD_LEN20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		val = ADAV80X_CAPTURE_WORD_LEN24;  		break;  	default:  		return -EINVAL;  	} -	snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], +	regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],  		ADAV80X_CAPTURE_WORD_LEN_MASK, val);  	return 0;  }  static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, -		struct snd_soc_dai *dai, snd_pcm_format_t format) +		struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)  {  	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);  	unsigned int val; @@ -474,24 +488,24 @@ static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,  	if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J)  		return 0; -	switch (format) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16;  		break; -	case SNDRV_PCM_FORMAT_S18_3LE: +	case 18:  		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24;  		break;  	default:  		return -EINVAL;  	} -	snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1], +	regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],  		ADAV80X_PLAYBACK_MODE_MASK, val);  	return 0; @@ -508,12 +522,10 @@ static int adav80x_hw_params(struct snd_pcm_substream *substream,  		return -EINVAL;  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -		adav80x_set_playback_pcm_format(codec, dai, -			params_format(params)); +		adav80x_set_playback_pcm_format(codec, dai, params);  		adav80x_set_dac_clock(codec, rate);  	} else { -		adav80x_set_capture_pcm_format(codec, dai, -			params_format(params)); +		adav80x_set_capture_pcm_format(codec, dai, params);  		adav80x_set_adc_clock(codec, rate);  	}  	adav80x->rate = rate; @@ -527,6 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,  			      unsigned int freq, int dir)  {  	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = &codec->dapm;  	if (dir == SND_SOC_CLOCK_IN) {  		switch (clk_id) { @@ -554,10 +567,12 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,  					ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id);  			iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); -			snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1); -			snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2); +			regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1, +				iclk_ctrl1); +			regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, +				iclk_ctrl2); -			snd_soc_dapm_sync(&codec->dapm); +			snd_soc_dapm_sync(dapm);  		}  	} else {  		unsigned int mask; @@ -575,24 +590,30 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,  		mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id);  		if (freq == 0) { -			snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask); +			regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, +				mask, mask);  			adav80x->sysclk_pd[clk_id] = true;  		} else { -			snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0); +			regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, +				mask, 0);  			adav80x->sysclk_pd[clk_id] = false;  		} +		snd_soc_dapm_mutex_lock(dapm); +  		if (adav80x->sysclk_pd[0]) -			snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); +			snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1");  		else -			snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); +			snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1");  		if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) -			snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); +			snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2");  		else -			snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); +			snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2"); -		snd_soc_dapm_sync(&codec->dapm); +		snd_soc_dapm_sync_unlocked(dapm); + +		snd_soc_dapm_mutex_unlock(dapm);  	}  	return 0; @@ -650,9 +671,9 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,  		return -EINVAL;  	} -	snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV, -		pll_ctrl1); -	snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2, +	regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1, +			ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1); +	regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2,  			ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2);  	if (source != adav80x->pll_src) { @@ -661,7 +682,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,  		else  			pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); -		snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC, +		regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC,  				ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src);  		adav80x->pll_src = source; @@ -675,6 +696,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,  static int adav80x_set_bias_level(struct snd_soc_codec *codec,  		enum snd_soc_bias_level level)  { +	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);  	unsigned int mask = ADAV80X_DAC_CTRL1_PD;  	switch (level) { @@ -683,10 +705,12 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_PREPARE:  		break;  	case SND_SOC_BIAS_STANDBY: -		snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00); +		regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, +			0x00);  		break;  	case SND_SOC_BIAS_OFF: -		snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask); +		regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, +			mask);  		break;  	} @@ -701,7 +725,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream,  	struct snd_soc_codec *codec = dai->codec;  	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); -	if (!codec->active || !adav80x->rate) +	if (!snd_soc_codec_is_active(codec) || !adav80x->rate)  		return 0;  	return snd_pcm_hw_constraint_minmax(substream->runtime, @@ -714,7 +738,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,  	struct snd_soc_codec *codec = dai->codec;  	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); -	if (!codec->active) +	if (!snd_soc_codec_is_active(codec))  		adav80x->rate = 0;  } @@ -777,37 +801,38 @@ static struct snd_soc_dai_driver adav80x_dais[] = {  static int adav80x_probe(struct snd_soc_codec *codec)  { -	int ret;  	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type); -	if (ret) { -		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Force PLLs on for SYSCLK output */  	snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");  	snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");  	/* Power down S/PDIF receiver, since it is currently not supported */ -	snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20); +	regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);  	/* Disable DAC zero flag */ -	snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6); +	regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);  	return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  }  static int adav80x_suspend(struct snd_soc_codec *codec)  { -	return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); +	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); +	int ret; + +	ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); +	regcache_cache_only(adav80x->regmap, true); + +	return ret;  }  static int adav80x_resume(struct snd_soc_codec *codec)  { +	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(adav80x->regmap, false);  	adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	codec->cache_sync = 1; -	snd_soc_cache_sync(codec); +	regcache_sync(adav80x->regmap);  	return 0;  } @@ -827,10 +852,6 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {  	.set_pll = adav80x_set_pll,  	.set_sysclk = adav80x_set_sysclk, -	.reg_word_size = sizeof(u8), -	.reg_cache_size = ARRAY_SIZE(adav80x_default_regs), -	.reg_cache_default = adav80x_default_regs, -  	.controls = adav80x_controls,  	.num_controls = ARRAY_SIZE(adav80x_controls),  	.dapm_widgets = adav80x_dapm_widgets, @@ -839,119 +860,38 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {  	.num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),  }; -static int adav80x_bus_probe(struct device *dev, -			     enum snd_soc_control_type control_type) +int adav80x_bus_probe(struct device *dev, struct regmap *regmap)  {  	struct adav80x *adav80x; -	int ret; -	adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); + +	adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL);  	if (!adav80x)  		return -ENOMEM;  	dev_set_drvdata(dev, adav80x); -	adav80x->control_type = control_type; +	adav80x->regmap = regmap; -	ret = snd_soc_register_codec(dev, &adav80x_codec_driver, +	return snd_soc_register_codec(dev, &adav80x_codec_driver,  		adav80x_dais, ARRAY_SIZE(adav80x_dais)); -	if (ret) -		kfree(adav80x); - -	return ret; -} - -static int adav80x_bus_remove(struct device *dev) -{ -	snd_soc_unregister_codec(dev); -	kfree(dev_get_drvdata(dev)); -	return 0;  } +EXPORT_SYMBOL_GPL(adav80x_bus_probe); -#if defined(CONFIG_SPI_MASTER) -static const struct spi_device_id adav80x_spi_id[] = { -	{ "adav801", 0 }, -	{ } -}; -MODULE_DEVICE_TABLE(spi, adav80x_spi_id); - -static int adav80x_spi_probe(struct spi_device *spi) -{ -	return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); -} +const struct regmap_config adav80x_regmap_config = { +	.val_bits = 8, +	.pad_bits = 1, +	.reg_bits = 7, +	.read_flag_mask = 0x01, -static int adav80x_spi_remove(struct spi_device *spi) -{ -	return adav80x_bus_remove(&spi->dev); -} +	.max_register = ADAV80X_PLL_OUTE, -static struct spi_driver adav80x_spi_driver = { -	.driver = { -		.name	= "adav801", -		.owner	= THIS_MODULE, -	}, -	.probe		= adav80x_spi_probe, -	.remove		= adav80x_spi_remove, -	.id_table	= adav80x_spi_id, +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults = adav80x_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),  }; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static const struct i2c_device_id adav80x_i2c_id[] = { -	{ "adav803", 0 }, -	{ } -}; -MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); - -static int adav80x_i2c_probe(struct i2c_client *client, -			     const struct i2c_device_id *id) -{ -	return adav80x_bus_probe(&client->dev, SND_SOC_I2C); -} - -static int adav80x_i2c_remove(struct i2c_client *client) -{ -	return adav80x_bus_remove(&client->dev); -} - -static struct i2c_driver adav80x_i2c_driver = { -	.driver = { -		.name = "adav803", -		.owner = THIS_MODULE, -	}, -	.probe = adav80x_i2c_probe, -	.remove = adav80x_i2c_remove, -	.id_table = adav80x_i2c_id, -}; -#endif - -static int __init adav80x_init(void) -{ -	int ret = 0; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	ret = i2c_add_driver(&adav80x_i2c_driver); -	if (ret) -		return ret; -#endif - -#if defined(CONFIG_SPI_MASTER) -	ret = spi_register_driver(&adav80x_spi_driver); -#endif - -	return ret; -} -module_init(adav80x_init); - -static void __exit adav80x_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	i2c_del_driver(&adav80x_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) -	spi_unregister_driver(&adav80x_spi_driver); -#endif -} -module_exit(adav80x_exit); +EXPORT_SYMBOL_GPL(adav80x_regmap_config);  MODULE_DESCRIPTION("ASoC ADAV80x driver");  MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h index adb0fc76d4e..8a1d7c09dca 100644 --- a/sound/soc/codecs/adav80x.h +++ b/sound/soc/codecs/adav80x.h @@ -9,6 +9,13 @@  #ifndef _ADAV80X_H  #define _ADAV80X_H +#include <linux/regmap.h> + +struct device; + +extern const struct regmap_config adav80x_regmap_config; +int adav80x_bus_probe(struct device *dev, struct regmap *regmap); +  enum adav80x_pll_src {  	ADAV80X_PLL_SRC_XIN,  	ADAV80X_PLL_SRC_XTAL, diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 71059c07ae7..1fd7f72b2a6 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -11,13 +11,14 @@  #include <linux/module.h>  #include <linux/slab.h> -#include <sound/core.h> -#include <sound/soc.h> -#include <sound/initval.h>  #include <linux/spi/spi.h>  #include <linux/of_device.h>  #include <linux/of_gpio.h> +#include <linux/regulator/consumer.h>  #include <sound/asoundef.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/initval.h>  /* AK4104 registers addresses */  #define AK4104_REG_CONTROL1		0x00 @@ -45,10 +46,9 @@  #define AK4104_TX_TXE			(1 << 0)  #define AK4104_TX_V			(1 << 1) -#define DRV_NAME "ak4104-codec" -  struct ak4104_private {  	struct regmap *regmap; +	struct regulator *regulator;  };  static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { @@ -176,22 +176,30 @@ static int ak4104_probe(struct snd_soc_codec *codec)  	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);  	int ret; -	codec->control_data = ak4104->regmap; +	ret = regulator_enable(ak4104->regulator); +	if (ret < 0) { +		dev_err(codec->dev, "Unable to enable regulator: %d\n", ret); +		return ret; +	}  	/* set power-up and non-reset bits */  	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,  				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,  				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);  	if (ret < 0) -		return ret; +		goto exit_disable_regulator;  	/* enable transmitter */  	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,  				 AK4104_TX_TXE, AK4104_TX_TXE);  	if (ret < 0) -		return ret; +		goto exit_disable_regulator;  	return 0; + +exit_disable_regulator: +	regulator_disable(ak4104->regulator); +	return ret;  }  static int ak4104_remove(struct snd_soc_codec *codec) @@ -200,13 +208,42 @@ static int ak4104_remove(struct snd_soc_codec *codec)  	regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,  			   AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); +	regulator_disable(ak4104->regulator); + +	return 0; +} + +#ifdef CONFIG_PM +static int ak4104_soc_suspend(struct snd_soc_codec *codec) +{ +	struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); + +	regulator_disable(priv->regulator);  	return 0;  } +static int ak4104_soc_resume(struct snd_soc_codec *codec) +{ +	struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); +	int ret; + +	ret = regulator_enable(priv->regulator); +	if (ret < 0) +		return ret; + +	return 0; +} +#else +#define ak4104_soc_suspend	NULL +#define ak4104_soc_resume	NULL +#endif /* CONFIG_PM */ +  static struct snd_soc_codec_driver soc_codec_device_ak4104 = { -	.probe =	ak4104_probe, -	.remove =	ak4104_remove, +	.probe = ak4104_probe, +	.remove = ak4104_remove, +	.suspend = ak4104_soc_suspend, +	.resume = ak4104_soc_resume,  	.dapm_widgets = ak4104_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), @@ -243,6 +280,13 @@ static int ak4104_spi_probe(struct spi_device *spi)  	if (ak4104 == NULL)  		return -ENOMEM; +	ak4104->regulator = devm_regulator_get(&spi->dev, "vdd"); +	if (IS_ERR(ak4104->regulator)) { +		ret = PTR_ERR(ak4104->regulator); +		dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret); +		return ret; +	} +  	ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);  	if (IS_ERR(ak4104->regmap)) {  		ret = PTR_ERR(ak4104->regmap); @@ -291,12 +335,19 @@ static const struct of_device_id ak4104_of_match[] = {  };  MODULE_DEVICE_TABLE(of, ak4104_of_match); +static const struct spi_device_id ak4104_id_table[] = { +	{ "ak4104", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, ak4104_id_table); +  static struct spi_driver ak4104_spi_driver = {  	.driver  = { -		.name   = DRV_NAME, +		.name   = "ak4104",  		.owner  = THIS_MODULE,  		.of_match_table = ak4104_of_match,  	}, +	.id_table = ak4104_id_table,  	.probe  = ak4104_spi_probe,  	.remove = ak4104_spi_remove,  }; diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 684fe910669..30e297890fe 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -388,15 +388,6 @@ static int ak4535_resume(struct snd_soc_codec *codec)  static int ak4535_probe(struct snd_soc_codec *codec)  { -	struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = ak4535->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	/* power on device */  	ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 5f9af1fb76e..7afe8f48208 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -17,6 +17,7 @@  #include <linux/gpio.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -30,6 +31,7 @@  /* codec private data */  struct ak4641_priv { +	struct regmap *regmap;  	unsigned int sysclk;  	int deemph;  	int playback_fs; @@ -38,12 +40,12 @@ struct ak4641_priv {  /*   * ak4641 register cache   */ -static const u8 ak4641_reg[AK4641_CACHEREGNUM] = { -	0x00, 0x80, 0x00, 0x80, -	0x02, 0x00, 0x11, 0x05, -	0x00, 0x00, 0x36, 0x10, -	0x00, 0x00, 0x57, 0x00, -	0x88, 0x88, 0x08, 0x08 +static const struct reg_default ak4641_reg_defaults[] = { +	{  0, 0x00 }, {  1, 0x80 }, {  2, 0x00 }, {  3, 0x80 }, +	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x11 }, {  7, 0x05 }, +	{  8, 0x00 }, {  9, 0x00 }, { 10, 0x36 }, { 11, 0x10 }, +	{ 12, 0x00 }, { 13, 0x00 }, { 14, 0x57 }, { 15, 0x00 }, +	{ 16, 0x88 }, { 17, 0x88 }, { 18, 0x08 }, { 19, 0x08 }  };  static const int deemph_settings[] = {44100, 0, 48000, 32000}; @@ -72,7 +74,7 @@ static int ak4641_set_deemph(struct snd_soc_codec *codec)  static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);  	int deemph = ucontrol->value.enumerated.item[0]; @@ -87,7 +89,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,  static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = ak4641->deemph; @@ -111,14 +113,14 @@ static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);  static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); -static const struct soc_enum ak4641_mono_out_enum = -	SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out); -static const struct soc_enum ak4641_hp_out_enum = -	SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out); -static const struct soc_enum ak4641_mic_select_enum = -	SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select); -static const struct soc_enum ak4641_mic_or_dac_enum = -	SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac); +static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum, +			    AK4641_SIG1, 6, ak4641_mono_out); +static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum, +			    AK4641_MODE2, 2, ak4641_hp_out); +static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum, +			    AK4641_MIC, 1, ak4641_mic_select); +static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum, +			    AK4641_BTIF, 4, ak4641_mic_or_dac);  static const struct snd_kcontrol_new ak4641_snd_controls[] = {  	SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), @@ -328,7 +330,7 @@ static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {  		ak4641->playback_fs = rate;  		ak4641_set_deemph(codec); -	}; +	}  	return 0;  } @@ -396,6 +398,7 @@ static int ak4641_mute(struct snd_soc_dai *dai, int mute)  static int ak4641_set_bias_level(struct snd_soc_codec *codec,  	enum snd_soc_bias_level level)  { +	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);  	struct ak4641_platform_data *pdata = codec->dev->platform_data;  	int ret; @@ -417,7 +420,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,  				gpio_set_value(pdata->gpio_npdn, 1);  			mdelay(1); -			ret = snd_soc_cache_sync(codec); +			ret = regcache_sync(ak4641->regmap);  			if (ret) {  				dev_err(codec->dev,  					"Failed to sync cache: %d\n", ret); @@ -433,7 +436,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,  			gpio_set_value(pdata->gpio_npdn, 0);  		if (pdata && gpio_is_valid(pdata->gpio_power))  			gpio_set_value(pdata->gpio_power, 0); -		codec->cache_sync = 1; +		regcache_mark_dirty(ak4641->regmap);  		break;  	}  	codec->dapm.bias_level = level; @@ -516,14 +519,6 @@ static int ak4641_resume(struct snd_soc_codec *codec)  static int ak4641_probe(struct snd_soc_codec *codec)  { -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* power on device */  	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -550,12 +545,17 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {  	.dapm_routes		= ak4641_audio_map,  	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),  	.set_bias_level		= ak4641_set_bias_level, -	.reg_cache_size		= ARRAY_SIZE(ak4641_reg), -	.reg_word_size		= sizeof(u8), -	.reg_cache_default	= ak4641_reg, -	.reg_cache_step		= 1,  }; +static const struct regmap_config ak4641_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = AK4641_BTIF, +	.reg_defaults = ak4641_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(ak4641_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +};  static int ak4641_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id) @@ -569,6 +569,10 @@ static int ak4641_i2c_probe(struct i2c_client *i2c,  	if (!ak4641)  		return -ENOMEM; +	ak4641->regmap = devm_regmap_init_i2c(i2c, &ak4641_regmap); +	if (IS_ERR(ak4641->regmap)) +		return PTR_ERR(ak4641->regmap); +  	if (pdata) {  		if (gpio_is_valid(pdata->gpio_power)) {  			ret = gpio_request_one(pdata->gpio_power, diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 2d037870970..3ba4c0f1141 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -28,6 +28,7 @@  #include <linux/slab.h>  #include <linux/of_device.h>  #include <linux/module.h> +#include <linux/regmap.h>  #include <sound/soc.h>  #include <sound/initval.h>  #include <sound/tlv.h> @@ -97,7 +98,7 @@  #define MGAIN0		(1 << 0) /* MIC amp gain*/  /* TIMER */ -#define ZTM(param)	((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */ +#define ZTM(param)	((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */  #define WTM(param)	(((param & 0x4) << 4) | ((param & 0x3) << 2))  /* ALC_CTL1 */ @@ -133,6 +134,15 @@  /* MD_CTL4 */  #define DACH		(1 << 0) +struct ak4642_drvdata { +	const struct regmap_config *regmap_config; +	int extended_frequencies; +}; + +struct ak4642_priv { +	const struct ak4642_drvdata *drvdata; +}; +  /*   * Playback Volume (table 39)   * @@ -147,6 +157,8 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {  	SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,  			 0, 0xFF, 1, out_tlv), +	SOC_SINGLE("ALC Capture Switch", ALC_CTL1, 5, 1, 0), +	SOC_SINGLE("ALC Capture ZC Switch", ALC_CTL1, 4, 1, 1),  };  static const struct snd_kcontrol_new ak4642_headphone_control = @@ -198,30 +210,30 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {  /*   * ak4642 register cache   */ -static const u8 ak4642_reg[] = { -	0x00, 0x00, 0x01, 0x00, -	0x02, 0x00, 0x00, 0x00, -	0xe1, 0xe1, 0x18, 0x00, -	0xe1, 0x18, 0x11, 0x08, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, +static const struct reg_default ak4642_reg[] = { +	{  0, 0x00 }, {  1, 0x00 }, {  2, 0x01 }, {  3, 0x00 }, +	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x00 }, {  7, 0x00 }, +	{  8, 0xe1 }, {  9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 }, +	{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0x08 }, +	{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 }, +	{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 }, +	{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 }, +	{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 }, +	{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 }, +	{ 36, 0x00 },  }; -static const u8 ak4648_reg[] = { -	0x00, 0x00, 0x01, 0x00, -	0x02, 0x00, 0x00, 0x00, -	0xe1, 0xe1, 0x18, 0x00, -	0xe1, 0x18, 0x11, 0xb8, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, -	0x00, 0x88, 0x88, 0x08, +static const struct reg_default ak4648_reg[] = { +	{  0, 0x00 }, {  1, 0x00 }, {  2, 0x01 }, {  3, 0x00 }, +	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x00 }, {  7, 0x00 }, +	{  8, 0xe1 }, {  9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 }, +	{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0xb8 }, +	{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 }, +	{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 }, +	{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 }, +	{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 }, +	{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 }, +	{ 36, 0x00 }, { 37, 0x88 }, { 38, 0x88 }, { 39, 0x08 },  };  static int ak4642_dai_startup(struct snd_pcm_substream *substream, @@ -257,7 +269,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,  		 * This operation came from example code of  		 * "ASAHI KASEI AK4642" (japanese) manual p94.  		 */ -		snd_soc_write(codec, SG_SL1, PMMP | MGAIN0); +		snd_soc_update_bits(codec, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0);  		snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));  		snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);  		snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL); @@ -286,7 +298,9 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,  	int clk_id, unsigned int freq, int dir)  {  	struct snd_soc_codec *codec = codec_dai->codec; +	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);  	u8 pll; +	int extended_freq = 0;  	switch (freq) {  	case 11289600: @@ -307,9 +321,25 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,  	case 27000000:  		pll = PLL3 | PLL2 | PLL0;  		break; +	case 19200000: +		pll = PLL3; +		extended_freq = 1; +		break; +	case 13000000: +		pll = PLL3 | PLL2 | PLL1; +		extended_freq = 1; +		break; +	case 26000000: +		pll = PLL3 | PLL2 | PLL1 | PLL0; +		extended_freq = 1; +		break;  	default:  		return -EINVAL;  	} + +	if (extended_freq && !priv->drvdata->extended_frequencies) +		return -EINVAL; +  	snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);  	return 0; @@ -352,7 +382,6 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	 */  	default:  		return -EINVAL; -		break;  	}  	snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data); @@ -405,7 +434,6 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,  		break;  	default:  		return -EINVAL; -		break;  	}  	snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate); @@ -456,24 +484,16 @@ static struct snd_soc_dai_driver ak4642_dai = {  static int ak4642_resume(struct snd_soc_codec *codec)  { -	snd_soc_cache_sync(codec); +	struct regmap *regmap = dev_get_regmap(codec->dev, NULL); + +	regcache_mark_dirty(regmap); +	regcache_sync(regmap);  	return 0;  }  static int ak4642_probe(struct snd_soc_codec *codec)  { -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	snd_soc_add_codec_controls(codec, ak4642_snd_controls, -			     ARRAY_SIZE(ak4642_snd_controls)); -  	ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  	return 0; @@ -490,55 +510,81 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {  	.remove			= ak4642_remove,  	.resume			= ak4642_resume,  	.set_bias_level		= ak4642_set_bias_level, -	.reg_cache_default	= ak4642_reg,			/* ak4642 reg */ -	.reg_cache_size		= ARRAY_SIZE(ak4642_reg),	/* ak4642 reg */ -	.reg_word_size		= sizeof(u8), +	.controls		= ak4642_snd_controls, +	.num_controls		= ARRAY_SIZE(ak4642_snd_controls),  	.dapm_widgets		= ak4642_dapm_widgets,  	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),  	.dapm_routes		= ak4642_intercon,  	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),  }; -static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { -	.probe			= ak4642_probe, -	.remove			= ak4642_remove, -	.resume			= ak4642_resume, -	.set_bias_level		= ak4642_set_bias_level, -	.reg_cache_default	= ak4648_reg,			/* ak4648 reg */ -	.reg_cache_size		= ARRAY_SIZE(ak4648_reg),	/* ak4648 reg */ -	.reg_word_size		= sizeof(u8), -	.dapm_widgets		= ak4642_dapm_widgets, -	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets), -	.dapm_routes		= ak4642_intercon, -	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon), +static const struct regmap_config ak4642_regmap = { +	.reg_bits		= 8, +	.val_bits		= 8, +	.max_register		= ARRAY_SIZE(ak4642_reg) + 1, +	.reg_defaults		= ak4642_reg, +	.num_reg_defaults	= ARRAY_SIZE(ak4642_reg), +}; + +static const struct regmap_config ak4648_regmap = { +	.reg_bits		= 8, +	.val_bits		= 8, +	.max_register		= ARRAY_SIZE(ak4648_reg) + 1, +	.reg_defaults		= ak4648_reg, +	.num_reg_defaults	= ARRAY_SIZE(ak4648_reg), +}; + +static const struct ak4642_drvdata ak4642_drvdata = { +	.regmap_config = &ak4642_regmap, +}; + +static const struct ak4642_drvdata ak4643_drvdata = { +	.regmap_config = &ak4642_regmap, +}; + +static const struct ak4642_drvdata ak4648_drvdata = { +	.regmap_config = &ak4648_regmap, +	.extended_frequencies = 1,  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)  static struct of_device_id ak4642_of_match[];  static int ak4642_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  {  	struct device_node *np = i2c->dev.of_node; -	const struct snd_soc_codec_driver *driver; +	const struct ak4642_drvdata *drvdata = NULL; +	struct regmap *regmap; +	struct ak4642_priv *priv; -	driver = NULL;  	if (np) {  		const struct of_device_id *of_id;  		of_id = of_match_device(ak4642_of_match, &i2c->dev);  		if (of_id) -			driver = of_id->data; +			drvdata = of_id->data;  	} else { -		driver = (struct snd_soc_codec_driver *)id->driver_data; +		drvdata = (const struct ak4642_drvdata *)id->driver_data;  	} -	if (!driver) { -		dev_err(&i2c->dev, "no driver\n"); +	if (!drvdata) { +		dev_err(&i2c->dev, "Unknown device type\n");  		return -EINVAL;  	} +	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->drvdata = drvdata; + +	i2c_set_clientdata(i2c, priv); + +	regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config); +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); +  	return snd_soc_register_codec(&i2c->dev, -				      driver, &ak4642_dai, 1); +				      &soc_codec_dev_ak4642, &ak4642_dai, 1);  }  static int ak4642_i2c_remove(struct i2c_client *client) @@ -548,17 +594,17 @@ static int ak4642_i2c_remove(struct i2c_client *client)  }  static struct of_device_id ak4642_of_match[] = { -	{ .compatible = "asahi-kasei,ak4642",	.data = &soc_codec_dev_ak4642}, -	{ .compatible = "asahi-kasei,ak4643",	.data = &soc_codec_dev_ak4642}, -	{ .compatible = "asahi-kasei,ak4648",	.data = &soc_codec_dev_ak4648}, +	{ .compatible = "asahi-kasei,ak4642",	.data = &ak4642_drvdata}, +	{ .compatible = "asahi-kasei,ak4643",	.data = &ak4643_drvdata}, +	{ .compatible = "asahi-kasei,ak4648",	.data = &ak4648_drvdata},  	{},  };  MODULE_DEVICE_TABLE(of, ak4642_of_match);  static const struct i2c_device_id ak4642_i2c_id[] = { -	{ "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 }, -	{ "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 }, -	{ "ak4648", (kernel_ulong_t)&soc_codec_dev_ak4648 }, +	{ "ak4642", (kernel_ulong_t)&ak4642_drvdata }, +	{ "ak4643", (kernel_ulong_t)&ak4643_drvdata }, +	{ "ak4648", (kernel_ulong_t)&ak4648_drvdata },  	{ }  };  MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); @@ -573,27 +619,8 @@ static struct i2c_driver ak4642_i2c_driver = {  	.remove		= ak4642_i2c_remove,  	.id_table	= ak4642_i2c_id,  }; -#endif - -static int __init ak4642_modinit(void) -{ -	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	ret = i2c_add_driver(&ak4642_i2c_driver); -#endif -	return ret; -} -module_init(ak4642_modinit); - -static void __exit ak4642_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	i2c_del_driver(&ak4642_i2c_driver); -#endif - -} -module_exit(ak4642_exit); +module_i2c_driver(ak4642_i2c_driver);  MODULE_DESCRIPTION("Soc AK4642 driver");  MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 25bdf6ad4a5..998fa0c5a0b 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -15,6 +15,7 @@  #include <linux/init.h>  #include <linux/i2c.h>  #include <linux/delay.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/soc.h>  #include <sound/initval.h> @@ -23,104 +24,99 @@  #include "ak4671.h" -/* codec private data */ -struct ak4671_priv { -	enum snd_soc_control_type control_type; -}; -  /* ak4671 register cache & default register settings */ -static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { -	0x00,	/* AK4671_AD_DA_POWER_MANAGEMENT	(0x00)	*/ -	0xf6,	/* AK4671_PLL_MODE_SELECT0		(0x01)	*/ -	0x00,	/* AK4671_PLL_MODE_SELECT1		(0x02)	*/ -	0x02,	/* AK4671_FORMAT_SELECT			(0x03)	*/ -	0x00,	/* AK4671_MIC_SIGNAL_SELECT		(0x04)	*/ -	0x55,	/* AK4671_MIC_AMP_GAIN			(0x05)	*/ -	0x00,	/* AK4671_MIXING_POWER_MANAGEMENT0	(0x06)	*/ -	0x00,	/* AK4671_MIXING_POWER_MANAGEMENT1	(0x07)	*/ -	0xb5,	/* AK4671_OUTPUT_VOLUME_CONTROL		(0x08)	*/ -	0x00,	/* AK4671_LOUT1_SIGNAL_SELECT		(0x09)	*/ -	0x00,	/* AK4671_ROUT1_SIGNAL_SELECT		(0x0a)	*/ -	0x00,	/* AK4671_LOUT2_SIGNAL_SELECT		(0x0b)	*/ -	0x00,	/* AK4671_ROUT2_SIGNAL_SELECT		(0x0c)	*/ -	0x00,	/* AK4671_LOUT3_SIGNAL_SELECT		(0x0d)	*/ -	0x00,	/* AK4671_ROUT3_SIGNAL_SELECT		(0x0e)	*/ -	0x00,	/* AK4671_LOUT1_POWER_MANAGERMENT	(0x0f)	*/ -	0x00,	/* AK4671_LOUT2_POWER_MANAGERMENT	(0x10)	*/ -	0x80,	/* AK4671_LOUT3_POWER_MANAGERMENT	(0x11)	*/ -	0x91,	/* AK4671_LCH_INPUT_VOLUME_CONTROL	(0x12)	*/ -	0x91,	/* AK4671_RCH_INPUT_VOLUME_CONTROL	(0x13)	*/ -	0xe1,	/* AK4671_ALC_REFERENCE_SELECT		(0x14)	*/ -	0x00,	/* AK4671_DIGITAL_MIXING_CONTROL	(0x15)	*/ -	0x00,	/* AK4671_ALC_TIMER_SELECT		(0x16)	*/ -	0x00,	/* AK4671_ALC_MODE_CONTROL		(0x17)	*/ -	0x02,	/* AK4671_MODE_CONTROL1			(0x18)	*/ -	0x01,	/* AK4671_MODE_CONTROL2			(0x19)	*/ -	0x18,	/* AK4671_LCH_OUTPUT_VOLUME_CONTROL	(0x1a)	*/ -	0x18,	/* AK4671_RCH_OUTPUT_VOLUME_CONTROL	(0x1b)	*/ -	0x00,	/* AK4671_SIDETONE_A_CONTROL		(0x1c)	*/ -	0x02,	/* AK4671_DIGITAL_FILTER_SELECT		(0x1d)	*/ -	0x00,	/* AK4671_FIL3_COEFFICIENT0		(0x1e)	*/ -	0x00,	/* AK4671_FIL3_COEFFICIENT1		(0x1f)	*/ -	0x00,	/* AK4671_FIL3_COEFFICIENT2		(0x20)	*/ -	0x00,	/* AK4671_FIL3_COEFFICIENT3		(0x21)	*/ -	0x00,	/* AK4671_EQ_COEFFICIENT0		(0x22)	*/ -	0x00,	/* AK4671_EQ_COEFFICIENT1		(0x23)	*/ -	0x00,	/* AK4671_EQ_COEFFICIENT2		(0x24)	*/ -	0x00,	/* AK4671_EQ_COEFFICIENT3		(0x25)	*/ -	0x00,	/* AK4671_EQ_COEFFICIENT4		(0x26)	*/ -	0x00,	/* AK4671_EQ_COEFFICIENT5		(0x27)	*/ -	0xa9,	/* AK4671_FIL1_COEFFICIENT0		(0x28)	*/ -	0x1f,	/* AK4671_FIL1_COEFFICIENT1		(0x29)	*/ -	0xad,	/* AK4671_FIL1_COEFFICIENT2		(0x2a)	*/ -	0x20,	/* AK4671_FIL1_COEFFICIENT3		(0x2b)	*/ -	0x00,	/* AK4671_FIL2_COEFFICIENT0		(0x2c)	*/ -	0x00,	/* AK4671_FIL2_COEFFICIENT1		(0x2d)	*/ -	0x00,	/* AK4671_FIL2_COEFFICIENT2		(0x2e)	*/ -	0x00,	/* AK4671_FIL2_COEFFICIENT3		(0x2f)	*/ -	0x00,	/* AK4671_DIGITAL_FILTER_SELECT2	(0x30)	*/ -	0x00,	/* this register not used			*/ -	0x00,	/* AK4671_E1_COEFFICIENT0		(0x32)	*/ -	0x00,	/* AK4671_E1_COEFFICIENT1		(0x33)	*/ -	0x00,	/* AK4671_E1_COEFFICIENT2		(0x34)	*/ -	0x00,	/* AK4671_E1_COEFFICIENT3		(0x35)	*/ -	0x00,	/* AK4671_E1_COEFFICIENT4		(0x36)	*/ -	0x00,	/* AK4671_E1_COEFFICIENT5		(0x37)	*/ -	0x00,	/* AK4671_E2_COEFFICIENT0		(0x38)	*/ -	0x00,	/* AK4671_E2_COEFFICIENT1		(0x39)	*/ -	0x00,	/* AK4671_E2_COEFFICIENT2		(0x3a)	*/ -	0x00,	/* AK4671_E2_COEFFICIENT3		(0x3b)	*/ -	0x00,	/* AK4671_E2_COEFFICIENT4		(0x3c)	*/ -	0x00,	/* AK4671_E2_COEFFICIENT5		(0x3d)	*/ -	0x00,	/* AK4671_E3_COEFFICIENT0		(0x3e)	*/ -	0x00,	/* AK4671_E3_COEFFICIENT1		(0x3f)	*/ -	0x00,	/* AK4671_E3_COEFFICIENT2		(0x40)	*/ -	0x00,	/* AK4671_E3_COEFFICIENT3		(0x41)	*/ -	0x00,	/* AK4671_E3_COEFFICIENT4		(0x42)	*/ -	0x00,	/* AK4671_E3_COEFFICIENT5		(0x43)	*/ -	0x00,	/* AK4671_E4_COEFFICIENT0		(0x44)	*/ -	0x00,	/* AK4671_E4_COEFFICIENT1		(0x45)	*/ -	0x00,	/* AK4671_E4_COEFFICIENT2		(0x46)	*/ -	0x00,	/* AK4671_E4_COEFFICIENT3		(0x47)	*/ -	0x00,	/* AK4671_E4_COEFFICIENT4		(0x48)	*/ -	0x00,	/* AK4671_E4_COEFFICIENT5		(0x49)	*/ -	0x00,	/* AK4671_E5_COEFFICIENT0		(0x4a)	*/ -	0x00,	/* AK4671_E5_COEFFICIENT1		(0x4b)	*/ -	0x00,	/* AK4671_E5_COEFFICIENT2		(0x4c)	*/ -	0x00,	/* AK4671_E5_COEFFICIENT3		(0x4d)	*/ -	0x00,	/* AK4671_E5_COEFFICIENT4		(0x4e)	*/ -	0x00,	/* AK4671_E5_COEFFICIENT5		(0x4f)	*/ -	0x88,	/* AK4671_EQ_CONTROL_250HZ_100HZ	(0x50)	*/ -	0x88,	/* AK4671_EQ_CONTROL_3500HZ_1KHZ	(0x51)	*/ -	0x08,	/* AK4671_EQ_CONTRO_10KHZ		(0x52)	*/ -	0x00,	/* AK4671_PCM_IF_CONTROL0		(0x53)	*/ -	0x00,	/* AK4671_PCM_IF_CONTROL1		(0x54)	*/ -	0x00,	/* AK4671_PCM_IF_CONTROL2		(0x55)	*/ -	0x18,	/* AK4671_DIGITAL_VOLUME_B_CONTROL	(0x56)	*/ -	0x18,	/* AK4671_DIGITAL_VOLUME_C_CONTROL	(0x57)	*/ -	0x00,	/* AK4671_SIDETONE_VOLUME_CONTROL	(0x58)	*/ -	0x00,	/* AK4671_DIGITAL_MIXING_CONTROL2	(0x59)	*/ -	0x00,	/* AK4671_SAR_ADC_CONTROL		(0x5a)	*/ +static const struct reg_default ak4671_reg_defaults[] = { +	{ 0x00, 0x00 },	/* AK4671_AD_DA_POWER_MANAGEMENT	(0x00)	*/ +	{ 0x01, 0xf6 },	/* AK4671_PLL_MODE_SELECT0		(0x01)	*/ +	{ 0x02, 0x00 },	/* AK4671_PLL_MODE_SELECT1		(0x02)	*/ +	{ 0x03, 0x02 },	/* AK4671_FORMAT_SELECT			(0x03)	*/ +	{ 0x04, 0x00 },	/* AK4671_MIC_SIGNAL_SELECT		(0x04)	*/ +	{ 0x05, 0x55 },	/* AK4671_MIC_AMP_GAIN			(0x05)	*/ +	{ 0x06, 0x00 },	/* AK4671_MIXING_POWER_MANAGEMENT0	(0x06)	*/ +	{ 0x07, 0x00 },	/* AK4671_MIXING_POWER_MANAGEMENT1	(0x07)	*/ +	{ 0x08, 0xb5 },	/* AK4671_OUTPUT_VOLUME_CONTROL		(0x08)	*/ +	{ 0x09, 0x00 },	/* AK4671_LOUT1_SIGNAL_SELECT		(0x09)	*/ +	{ 0x0a, 0x00 },	/* AK4671_ROUT1_SIGNAL_SELECT		(0x0a)	*/ +	{ 0x0b, 0x00 },	/* AK4671_LOUT2_SIGNAL_SELECT		(0x0b)	*/ +	{ 0x0c, 0x00 },	/* AK4671_ROUT2_SIGNAL_SELECT		(0x0c)	*/ +	{ 0x0d, 0x00 },	/* AK4671_LOUT3_SIGNAL_SELECT		(0x0d)	*/ +	{ 0x0e, 0x00 },	/* AK4671_ROUT3_SIGNAL_SELECT		(0x0e)	*/ +	{ 0x0f, 0x00 },	/* AK4671_LOUT1_POWER_MANAGERMENT	(0x0f)	*/ +	{ 0x10, 0x00 },	/* AK4671_LOUT2_POWER_MANAGERMENT	(0x10)	*/ +	{ 0x11, 0x80 },	/* AK4671_LOUT3_POWER_MANAGERMENT	(0x11)	*/ +	{ 0x12, 0x91 },	/* AK4671_LCH_INPUT_VOLUME_CONTROL	(0x12)	*/ +	{ 0x13, 0x91 },	/* AK4671_RCH_INPUT_VOLUME_CONTROL	(0x13)	*/ +	{ 0x14, 0xe1 },	/* AK4671_ALC_REFERENCE_SELECT		(0x14)	*/ +	{ 0x15, 0x00 },	/* AK4671_DIGITAL_MIXING_CONTROL	(0x15)	*/ +	{ 0x16, 0x00 },	/* AK4671_ALC_TIMER_SELECT		(0x16)	*/ +	{ 0x17, 0x00 },	/* AK4671_ALC_MODE_CONTROL		(0x17)	*/ +	{ 0x18, 0x02 },	/* AK4671_MODE_CONTROL1			(0x18)	*/ +	{ 0x19, 0x01 },	/* AK4671_MODE_CONTROL2			(0x19)	*/ +	{ 0x1a, 0x18 },	/* AK4671_LCH_OUTPUT_VOLUME_CONTROL	(0x1a)	*/ +	{ 0x1b, 0x18 },	/* AK4671_RCH_OUTPUT_VOLUME_CONTROL	(0x1b)	*/ +	{ 0x1c, 0x00 },	/* AK4671_SIDETONE_A_CONTROL		(0x1c)	*/ +	{ 0x1d, 0x02 },	/* AK4671_DIGITAL_FILTER_SELECT		(0x1d)	*/ +	{ 0x1e, 0x00 },	/* AK4671_FIL3_COEFFICIENT0		(0x1e)	*/ +	{ 0x1f, 0x00 },	/* AK4671_FIL3_COEFFICIENT1		(0x1f)	*/ +	{ 0x20, 0x00 },	/* AK4671_FIL3_COEFFICIENT2		(0x20)	*/ +	{ 0x21, 0x00 },	/* AK4671_FIL3_COEFFICIENT3		(0x21)	*/ +	{ 0x22, 0x00 },	/* AK4671_EQ_COEFFICIENT0		(0x22)	*/ +	{ 0x23, 0x00 },	/* AK4671_EQ_COEFFICIENT1		(0x23)	*/ +	{ 0x24, 0x00 },	/* AK4671_EQ_COEFFICIENT2		(0x24)	*/ +	{ 0x25, 0x00 },	/* AK4671_EQ_COEFFICIENT3		(0x25)	*/ +	{ 0x26, 0x00 },	/* AK4671_EQ_COEFFICIENT4		(0x26)	*/ +	{ 0x27, 0x00 },	/* AK4671_EQ_COEFFICIENT5		(0x27)	*/ +	{ 0x28, 0xa9 },	/* AK4671_FIL1_COEFFICIENT0		(0x28)	*/ +	{ 0x29, 0x1f },	/* AK4671_FIL1_COEFFICIENT1		(0x29)	*/ +	{ 0x2a, 0xad },	/* AK4671_FIL1_COEFFICIENT2		(0x2a)	*/ +	{ 0x2b, 0x20 },	/* AK4671_FIL1_COEFFICIENT3		(0x2b)	*/ +	{ 0x2c, 0x00 },	/* AK4671_FIL2_COEFFICIENT0		(0x2c)	*/ +	{ 0x2d, 0x00 },	/* AK4671_FIL2_COEFFICIENT1		(0x2d)	*/ +	{ 0x2e, 0x00 },	/* AK4671_FIL2_COEFFICIENT2		(0x2e)	*/ +	{ 0x2f, 0x00 },	/* AK4671_FIL2_COEFFICIENT3		(0x2f)	*/ +	{ 0x30, 0x00 },	/* AK4671_DIGITAL_FILTER_SELECT2	(0x30)	*/ + +	{ 0x32, 0x00 },	/* AK4671_E1_COEFFICIENT0		(0x32)	*/ +	{ 0x33, 0x00 },	/* AK4671_E1_COEFFICIENT1		(0x33)	*/ +	{ 0x34, 0x00 },	/* AK4671_E1_COEFFICIENT2		(0x34)	*/ +	{ 0x35, 0x00 },	/* AK4671_E1_COEFFICIENT3		(0x35)	*/ +	{ 0x36, 0x00 },	/* AK4671_E1_COEFFICIENT4		(0x36)	*/ +	{ 0x37, 0x00 },	/* AK4671_E1_COEFFICIENT5		(0x37)	*/ +	{ 0x38, 0x00 },	/* AK4671_E2_COEFFICIENT0		(0x38)	*/ +	{ 0x39, 0x00 },	/* AK4671_E2_COEFFICIENT1		(0x39)	*/ +	{ 0x3a, 0x00 },	/* AK4671_E2_COEFFICIENT2		(0x3a)	*/ +	{ 0x3b, 0x00 },	/* AK4671_E2_COEFFICIENT3		(0x3b)	*/ +	{ 0x3c, 0x00 },	/* AK4671_E2_COEFFICIENT4		(0x3c)	*/ +	{ 0x3d, 0x00 },	/* AK4671_E2_COEFFICIENT5		(0x3d)	*/ +	{ 0x3e, 0x00 },	/* AK4671_E3_COEFFICIENT0		(0x3e)	*/ +	{ 0x3f, 0x00 },	/* AK4671_E3_COEFFICIENT1		(0x3f)	*/ +	{ 0x40, 0x00 },	/* AK4671_E3_COEFFICIENT2		(0x40)	*/ +	{ 0x41, 0x00 },	/* AK4671_E3_COEFFICIENT3		(0x41)	*/ +	{ 0x42, 0x00 },	/* AK4671_E3_COEFFICIENT4		(0x42)	*/ +	{ 0x43, 0x00 },	/* AK4671_E3_COEFFICIENT5		(0x43)	*/ +	{ 0x44, 0x00 },	/* AK4671_E4_COEFFICIENT0		(0x44)	*/ +	{ 0x45, 0x00 },	/* AK4671_E4_COEFFICIENT1		(0x45)	*/ +	{ 0x46, 0x00 },	/* AK4671_E4_COEFFICIENT2		(0x46)	*/ +	{ 0x47, 0x00 },	/* AK4671_E4_COEFFICIENT3		(0x47)	*/ +	{ 0x48, 0x00 },	/* AK4671_E4_COEFFICIENT4		(0x48)	*/ +	{ 0x49, 0x00 },	/* AK4671_E4_COEFFICIENT5		(0x49)	*/ +	{ 0x4a, 0x00 },	/* AK4671_E5_COEFFICIENT0		(0x4a)	*/ +	{ 0x4b, 0x00 },	/* AK4671_E5_COEFFICIENT1		(0x4b)	*/ +	{ 0x4c, 0x00 },	/* AK4671_E5_COEFFICIENT2		(0x4c)	*/ +	{ 0x4d, 0x00 },	/* AK4671_E5_COEFFICIENT3		(0x4d)	*/ +	{ 0x4e, 0x00 },	/* AK4671_E5_COEFFICIENT4		(0x4e)	*/ +	{ 0x4f, 0x00 },	/* AK4671_E5_COEFFICIENT5		(0x4f)	*/ +	{ 0x50, 0x88 },	/* AK4671_EQ_CONTROL_250HZ_100HZ	(0x50)	*/ +	{ 0x51, 0x88 },	/* AK4671_EQ_CONTROL_3500HZ_1KHZ	(0x51)	*/ +	{ 0x52, 0x08 },	/* AK4671_EQ_CONTRO_10KHZ		(0x52)	*/ +	{ 0x53, 0x00 },	/* AK4671_PCM_IF_CONTROL0		(0x53)	*/ +	{ 0x54, 0x00 },	/* AK4671_PCM_IF_CONTROL1		(0x54)	*/ +	{ 0x55, 0x00 },	/* AK4671_PCM_IF_CONTROL2		(0x55)	*/ +	{ 0x56, 0x18 },	/* AK4671_DIGITAL_VOLUME_B_CONTROL	(0x56)	*/ +	{ 0x57, 0x18 },	/* AK4671_DIGITAL_VOLUME_C_CONTROL	(0x57)	*/ +	{ 0x58, 0x00 },	/* AK4671_SIDETONE_VOLUME_CONTROL	(0x58)	*/ +	{ 0x59, 0x00 },	/* AK4671_DIGITAL_MIXING_CONTROL2	(0x59)	*/ +	{ 0x5a, 0x00 },	/* AK4671_SAR_ADC_CONTROL		(0x5a)	*/  };  /* @@ -241,19 +237,17 @@ static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = {  /* Input MUXs */  static const char *ak4671_lin_mux_texts[] =  		{"LIN1", "LIN2", "LIN3", "LIN4"}; -static const struct soc_enum ak4671_lin_mux_enum = -	SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, -			ARRAY_SIZE(ak4671_lin_mux_texts), -			ak4671_lin_mux_texts); +static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum, +			    AK4671_MIC_SIGNAL_SELECT, 0, +			    ak4671_lin_mux_texts);  static const struct snd_kcontrol_new ak4671_lin_mux_control =  	SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum);  static const char *ak4671_rin_mux_texts[] =  		{"RIN1", "RIN2", "RIN3", "RIN4"}; -static const struct soc_enum ak4671_rin_mux_enum = -	SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, -			ARRAY_SIZE(ak4671_rin_mux_texts), -			ak4671_rin_mux_texts); +static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum, +			    AK4671_MIC_SIGNAL_SELECT, 2, +			    ak4671_rin_mux_texts);  static const struct snd_kcontrol_new ak4671_rin_mux_control =  	SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); @@ -619,21 +613,7 @@ static struct snd_soc_dai_driver ak4671_dai = {  static int ak4671_probe(struct snd_soc_codec *codec)  { -	struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	snd_soc_add_codec_controls(codec, ak4671_snd_controls, -			     ARRAY_SIZE(ak4671_snd_controls)); - -	ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - -	return ret; +	return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  }  static int ak4671_remove(struct snd_soc_codec *codec) @@ -646,28 +626,36 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {  	.probe = ak4671_probe,  	.remove = ak4671_remove,  	.set_bias_level = ak4671_set_bias_level, -	.reg_cache_size = AK4671_CACHEREGNUM, -	.reg_word_size = sizeof(u8), -	.reg_cache_default = ak4671_reg, +	.controls = ak4671_snd_controls, +	.num_controls = ARRAY_SIZE(ak4671_snd_controls),  	.dapm_widgets = ak4671_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),  	.dapm_routes = ak4671_intercon,  	.num_dapm_routes = ARRAY_SIZE(ak4671_intercon),  }; +static const struct regmap_config ak4671_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = AK4671_SAR_ADC_CONTROL, +	.reg_defaults = ak4671_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +}; +  static int ak4671_i2c_probe(struct i2c_client *client,  			    const struct i2c_device_id *id)  { -	struct ak4671_priv *ak4671; +	struct regmap *regmap;  	int ret; -	ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv), -			      GFP_KERNEL); -	if (ak4671 == NULL) -		return -ENOMEM; - -	i2c_set_clientdata(client, ak4671); -	ak4671->control_type = SND_SOC_I2C; +	regmap = devm_regmap_init_i2c(client, &ak4671_regmap); +	if (IS_ERR(regmap)) { +		ret = PTR_ERR(regmap); +		dev_err(&client->dev, "Failed to create regmap: %d\n", ret); +		return ret; +	}  	ret = snd_soc_register_codec(&client->dev,  			&soc_codec_dev_ak4671, &ak4671_dai, 1); diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h index 61cb7ab7552..394a34d3f50 100644 --- a/sound/soc/codecs/ak4671.h +++ b/sound/soc/codecs/ak4671.h @@ -105,8 +105,6 @@  #define AK4671_DIGITAL_MIXING_CONTROL2		0x59  #define AK4671_SAR_ADC_CONTROL			0x5a -#define AK4671_CACHEREGNUM			(AK4671_SAR_ADC_CONTROL + 1) -  /* Bitfield Definitions */  /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 256c364193a..9d0755aa1d1 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -21,7 +21,9 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h> +#include <linux/of.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -38,26 +40,13 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");  /* codec private data */  struct alc5623_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	u8 id;  	unsigned int sysclk; -	u16 reg_cache[ALC5623_VENDOR_ID2+2];  	unsigned int add_ctrl;  	unsigned int jack_det_ctrl;  }; -static void alc5623_fill_cache(struct snd_soc_codec *codec) -{ -	int i, step = codec->driver->reg_cache_step; -	u16 *cache = codec->reg_cache; - -	/* not really efficient ... */ -	codec->cache_bypass = 1; -	for (i = 0 ; i < codec->driver->reg_cache_size ; i += step) -		cache[i] = snd_soc_read(codec, i); -	codec->cache_bypass = 0; -} -  static inline int alc5623_reset(struct snd_soc_codec *codec)  {  	return snd_soc_write(codec, ALC5623_RESET, 0); @@ -228,32 +217,37 @@ static const char *alc5623_aux_out_input_sel[] = {  		"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};  /* auxout output mux */ -static const struct soc_enum alc5623_aux_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum, +			    ALC5623_OUTPUT_MIXER_CTRL, 6, +			    alc5623_aux_out_input_sel);  static const struct snd_kcontrol_new alc5623_auxout_mux_controls =  SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum);  /* speaker output mux */ -static const struct soc_enum alc5623_spkout_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum, +			    ALC5623_OUTPUT_MIXER_CTRL, 10, +			    alc5623_spkout_input_sel);  static const struct snd_kcontrol_new alc5623_spkout_mux_controls =  SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum);  /* headphone left output mux */ -static const struct soc_enum alc5623_hpl_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum, +			    ALC5623_OUTPUT_MIXER_CTRL, 9, +			    alc5623_hpl_out_input_sel);  static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls =  SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum);  /* headphone right output mux */ -static const struct soc_enum alc5623_hpr_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum, +			    ALC5623_OUTPUT_MIXER_CTRL, 8, +			    alc5623_hpr_out_input_sel);  static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls =  SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum);  /* speaker output N select */ -static const struct soc_enum alc5623_spk_n_sour_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum, +			    ALC5623_OUTPUT_MIXER_CTRL, 14, +			    alc5623_spk_n_sour_sel);  static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls =  SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); @@ -338,8 +332,9 @@ SND_SOC_DAPM_VMID("Vmid"),  };  static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; -static const struct soc_enum alc5623_amp_enum = -	SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names); +static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum, +			    ALC5623_OUTPUT_MIXER_CTRL, 13, +			    alc5623_amp_names);  static const struct snd_kcontrol_new alc5623_amp_mux_controls =  	SOC_DAPM_ENUM("Route", alc5623_amp_enum); @@ -714,17 +709,17 @@ static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,  	iface &= ~ALC5623_DAI_I2S_DL_MASK;  	/* bit size */ -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		iface |= ALC5623_DAI_I2S_DL_16;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		iface |= ALC5623_DAI_I2S_DL_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		iface |= ALC5623_DAI_I2S_DL_24;  		break; -	case SNDRV_PCM_FORMAT_S32_LE: +	case 32:  		iface |= ALC5623_DAI_I2S_DL_32;  		break;  	default: @@ -869,18 +864,28 @@ static struct snd_soc_dai_driver alc5623_dai = {  static int alc5623_suspend(struct snd_soc_codec *codec)  { +	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); +  	alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); +	regcache_cache_only(alc5623->regmap, true); +  	return 0;  }  static int alc5623_resume(struct snd_soc_codec *codec)  { -	int i, step = codec->driver->reg_cache_step; -	u16 *cache = codec->reg_cache; +	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); +	int ret;  	/* Sync reg_cache with the hardware */ -	for (i = 2 ; i < codec->driver->reg_cache_size ; i += step) -		snd_soc_write(codec, i, cache[i]); +	regcache_cache_only(alc5623->regmap, false); +	ret = regcache_sync(alc5623->regmap); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to sync register cache: %d\n", +			ret); +		regcache_cache_only(alc5623->regmap, true); +		return ret; +	}  	alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -898,16 +903,8 @@ static int alc5623_probe(struct snd_soc_codec *codec)  {  	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);  	struct snd_soc_dapm_context *dapm = &codec->dapm; -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	alc5623_reset(codec); -	alc5623_fill_cache(codec);  	/* power on device */  	alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -964,7 +961,7 @@ static int alc5623_probe(struct snd_soc_codec *codec)  		return -EINVAL;  	} -	return ret; +	return 0;  }  /* power down chip */ @@ -980,9 +977,15 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = {  	.suspend = alc5623_suspend,  	.resume = alc5623_resume,  	.set_bias_level = alc5623_set_bias_level, -	.reg_cache_size = ALC5623_VENDOR_ID2+2, -	.reg_word_size = sizeof(u16), -	.reg_cache_step = 2, +}; + +static const struct regmap_config alc5623_regmap = { +	.reg_bits = 8, +	.val_bits = 16, +	.reg_stride = 2, + +	.max_register = ALC5623_VENDOR_ID2, +	.cache_type = REGCACHE_RBTREE,  };  /* @@ -996,20 +999,35 @@ static int alc5623_i2c_probe(struct i2c_client *client,  {  	struct alc5623_platform_data *pdata;  	struct alc5623_priv *alc5623; -	int ret, vid1, vid2; +	struct device_node *np; +	unsigned int vid1, vid2; +	int ret; +	u32 val32; -	vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1); -	if (vid1 < 0) { -		dev_err(&client->dev, "failed to read I2C\n"); -		return -EIO; +	alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), +			       GFP_KERNEL); +	if (alc5623 == NULL) +		return -ENOMEM; + +	alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap); +	if (IS_ERR(alc5623->regmap)) { +		ret = PTR_ERR(alc5623->regmap); +		dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret); +		return ret; +	} + +	ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1); +	if (ret < 0) { +		dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret); +		return ret;  	} -	vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); -	vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2); -	if (vid2 < 0) { -		dev_err(&client->dev, "failed to read I2C\n"); -		return -EIO; +	ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2); +	if (ret < 0) { +		dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret); +		return ret;  	} +	vid2 >>= 8;  	if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {  		dev_err(&client->dev, "unknown or wrong codec\n"); @@ -1021,15 +1039,20 @@ static int alc5623_i2c_probe(struct i2c_client *client,  	dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); -	alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), -			       GFP_KERNEL); -	if (alc5623 == NULL) -		return -ENOMEM; -  	pdata = client->dev.platform_data;  	if (pdata) {  		alc5623->add_ctrl = pdata->add_ctrl;  		alc5623->jack_det_ctrl = pdata->jack_det_ctrl; +	} else { +		if (client->dev.of_node) { +			np = client->dev.of_node; +			ret = of_property_read_u32(np, "add-ctrl", &val32); +			if (!ret) +				alc5623->add_ctrl = val32; +			ret = of_property_read_u32(np, "jack-det-ctrl", &val32); +			if (!ret) +				alc5623->jack_det_ctrl = val32; +		}  	}  	alc5623->id = vid2; @@ -1048,7 +1071,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,  	}  	i2c_set_clientdata(client, alc5623); -	alc5623->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&client->dev,  		&soc_codec_device_alc5623, &alc5623_dai, 1); @@ -1072,11 +1094,18 @@ static const struct i2c_device_id alc5623_i2c_table[] = {  };  MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); +static const struct of_device_id alc5623_of_match[] = { +	{ .compatible = "realtek,alc5623", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, alc5623_of_match); +  /*  i2c codec control layer */  static struct i2c_driver alc5623_i2c_driver = {  	.driver = {  		.name = "alc562x-codec",  		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(alc5623_of_match),  	},  	.probe = alc5623_i2c_probe,  	.remove =  alc5623_i2c_remove, diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index f2e62e45f91..85942ca36cb 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -293,51 +293,59 @@ static const char * const alc5632_i2s_out_sel[] = {  		"ADC LR", "Voice Stereo Digital"};  /* auxout output mux */ -static const struct soc_enum alc5632_aux_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum, +			    ALC5632_OUTPUT_MIXER_CTRL, 6, +			    alc5632_aux_out_input_sel);  static const struct snd_kcontrol_new alc5632_auxout_mux_controls =  SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum);  /* speaker output mux */ -static const struct soc_enum alc5632_spkout_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum, +			    ALC5632_OUTPUT_MIXER_CTRL, 10, +			    alc5632_spkout_input_sel);  static const struct snd_kcontrol_new alc5632_spkout_mux_controls =  SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum);  /* headphone left output mux */ -static const struct soc_enum alc5632_hpl_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum, +			    ALC5632_OUTPUT_MIXER_CTRL, 9, +			    alc5632_hpl_out_input_sel);  static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls =  SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum);  /* headphone right output mux */ -static const struct soc_enum alc5632_hpr_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum, +			    ALC5632_OUTPUT_MIXER_CTRL, 8, +			    alc5632_hpr_out_input_sel);  static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls =  SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum);  /* speaker output N select */ -static const struct soc_enum alc5632_spk_n_sour_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum, +			    ALC5632_OUTPUT_MIXER_CTRL, 14, +			    alc5632_spk_n_sour_sel);  static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls =  SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum);  /* speaker amplifier */  static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"}; -static const struct soc_enum alc5632_amp_enum = -	SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names); +static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum, +			    ALC5632_OUTPUT_MIXER_CTRL, 13, +			    alc5632_amp_names);  static const struct snd_kcontrol_new alc5632_amp_mux_controls =  	SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum);  /* ADC output select */ -static const struct soc_enum alc5632_adcr_func_enum = -	SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum, +			    ALC5632_DAC_FUNC_SELECT, 5, +			    alc5632_adcr_func_sel);  static const struct snd_kcontrol_new alc5632_adcr_func_controls =  	SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum);  /* I2S out select */ -static const struct soc_enum alc5632_i2s_out_enum = -	SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum, +			    ALC5632_I2S_OUT_CTL, 5, +			    alc5632_i2s_out_sel);  static const struct snd_kcontrol_new alc5632_i2s_out_controls =  	SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); @@ -614,7 +622,7 @@ struct _pll_div {  };  /* Note : pll code from original alc5632 driver. Not sure of how good it is */ -/* usefull only for master mode */ +/* useful only for master mode */  static const struct _pll_div codec_master_pll_div[] = {  	{  2048000,  8192000,	0x0ea0}, @@ -869,14 +877,14 @@ static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,  	iface &= ~ALC5632_DAI_I2S_DL_MASK;  	/* bit size */ -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		iface |= ALC5632_DAI_I2S_DL_16;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		iface |= ALC5632_DAI_I2S_DL_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		iface |= ALC5632_DAI_I2S_DL_24;  		break;  	default: @@ -1053,15 +1061,6 @@ static int alc5632_resume(struct snd_soc_codec *codec)  static int alc5632_probe(struct snd_soc_codec *codec)  {  	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = alc5632->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	/* power on device  */  	alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1075,7 +1074,7 @@ static int alc5632_probe(struct snd_soc_codec *codec)  		return -EINVAL;  	} -	return ret; +	return 0;  }  /* power down chip */ @@ -1191,11 +1190,18 @@ static const struct i2c_device_id alc5632_i2c_table[] = {  };  MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table); +static const struct of_device_id alc5632_of_match[] = { +	{ .compatible = "realtek,alc5632", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, alc5632_of_match); +  /* i2c codec control layer */  static struct i2c_driver alc5632_i2c_driver = {  	.driver = {  		.name = "alc5632",  		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(alc5632_of_match),  	},  	.probe = alc5632_i2c_probe,  	.remove =  alc5632_i2c_remove, diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 657808ba141..29e198f57d4 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -53,6 +53,14 @@  #define ARIZONA_AIF_RX_ENABLES                  0x1A  #define ARIZONA_AIF_FORCE_WRITE                 0x1B +#define ARIZONA_FLL_VCO_CORNER 141900000 +#define ARIZONA_FLL_MAX_FREF   13500000 +#define ARIZONA_FLL_MIN_FVCO   90000000 +#define ARIZONA_FLL_MAX_FRATIO 16 +#define ARIZONA_FLL_MAX_REFDIV 8 +#define ARIZONA_FLL_MIN_OUTDIV 2 +#define ARIZONA_FLL_MAX_OUTDIV 7 +  #define arizona_fll_err(_fll, fmt, ...) \  	dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)  #define arizona_fll_warn(_fll, fmt, ...) \ @@ -93,7 +101,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,  	switch (event) {  	case SND_SOC_DAPM_PRE_PMU:  		if (!priv->spk_ena && manual_ena) { -			snd_soc_write(codec, 0x4f5, 0x25a); +			regmap_write_async(arizona->regmap, 0x4f5, 0x25a);  			priv->spk_ena_pending = true;  		}  		break; @@ -105,12 +113,13 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,  			return -EBUSY;  		} -		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, -				    1 << w->shift, 1 << w->shift); +		regmap_update_bits_async(arizona->regmap, +					 ARIZONA_OUTPUT_ENABLES_1, +					 1 << w->shift, 1 << w->shift);  		if (priv->spk_ena_pending) {  			msleep(75); -			snd_soc_write(codec, 0x4f5, 0xda); +			regmap_write_async(arizona->regmap, 0x4f5, 0xda);  			priv->spk_ena_pending = false;  			priv->spk_ena++;  		} @@ -119,16 +128,19 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,  		if (manual_ena) {  			priv->spk_ena--;  			if (!priv->spk_ena) -				snd_soc_write(codec, 0x4f5, 0x25a); +				regmap_write_async(arizona->regmap, +						   0x4f5, 0x25a);  		} -		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, -				    1 << w->shift, 0); +		regmap_update_bits_async(arizona->regmap, +					 ARIZONA_OUTPUT_ENABLES_1, +					 1 << w->shift, 0);  		break;  	case SND_SOC_DAPM_POST_PMD:  		if (manual_ena) {  			if (!priv->spk_ena) -				snd_soc_write(codec, 0x4f5, 0x0da); +				regmap_write_async(arizona->regmap, +						   0x4f5, 0x0da);  		}  		break;  	} @@ -292,6 +304,10 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {  	"AIF1RX8",  	"AIF2RX1",  	"AIF2RX2", +	"AIF2RX3", +	"AIF2RX4", +	"AIF2RX5", +	"AIF2RX6",  	"AIF3RX1",  	"AIF3RX2",  	"SLIMRX1", @@ -395,6 +411,10 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {  	0x27,  	0x28,  /* AIF2RX1 */  	0x29, +	0x2a, +	0x2b, +	0x2c, +	0x2d,  	0x30,  /* AIF3RX1 */  	0x31,  	0x38,  /* SLIMRX1 */ @@ -486,6 +506,22 @@ const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {  EXPORT_SYMBOL_GPL(arizona_rate_val); +const struct soc_enum arizona_isrc_fsh[] = { +	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1, +			      ARIZONA_ISRC1_FSH_SHIFT, 0xf, +			      ARIZONA_RATE_ENUM_SIZE, +			      arizona_rate_text, arizona_rate_val), +	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1, +			      ARIZONA_ISRC2_FSH_SHIFT, 0xf, +			      ARIZONA_RATE_ENUM_SIZE, +			      arizona_rate_text, arizona_rate_val), +	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1, +			      ARIZONA_ISRC3_FSH_SHIFT, 0xf, +			      ARIZONA_RATE_ENUM_SIZE, +			      arizona_rate_text, arizona_rate_val), +}; +EXPORT_SYMBOL_GPL(arizona_isrc_fsh); +  const struct soc_enum arizona_isrc_fsl[] = {  	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,  			      ARIZONA_ISRC1_FSL_SHIFT, 0xf, @@ -502,64 +538,90 @@ const struct soc_enum arizona_isrc_fsl[] = {  };  EXPORT_SYMBOL_GPL(arizona_isrc_fsl); +const struct soc_enum arizona_asrc_rate1 = +	SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1, +			      ARIZONA_ASRC_RATE1_SHIFT, 0xf, +			      ARIZONA_RATE_ENUM_SIZE - 1, +			      arizona_rate_text, arizona_rate_val); +EXPORT_SYMBOL_GPL(arizona_asrc_rate1); +  static const char *arizona_vol_ramp_text[] = {  	"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",  	"15ms/6dB", "30ms/6dB",  }; -const struct soc_enum arizona_in_vd_ramp = -	SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, -			ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp, +		     ARIZONA_INPUT_VOLUME_RAMP, +		     ARIZONA_IN_VD_RAMP_SHIFT, +		     arizona_vol_ramp_text);  EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); -const struct soc_enum arizona_in_vi_ramp = -	SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, -			ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp, +		     ARIZONA_INPUT_VOLUME_RAMP, +		     ARIZONA_IN_VI_RAMP_SHIFT, +		     arizona_vol_ramp_text);  EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); -const struct soc_enum arizona_out_vd_ramp = -	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, -			ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp, +		     ARIZONA_OUTPUT_VOLUME_RAMP, +		     ARIZONA_OUT_VD_RAMP_SHIFT, +		     arizona_vol_ramp_text);  EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); -const struct soc_enum arizona_out_vi_ramp = -	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, -			ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp, +		     ARIZONA_OUTPUT_VOLUME_RAMP, +		     ARIZONA_OUT_VI_RAMP_SHIFT, +		     arizona_vol_ramp_text);  EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);  static const char *arizona_lhpf_mode_text[] = {  	"Low-pass", "High-pass"  }; -const struct soc_enum arizona_lhpf1_mode = -	SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2, -			arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode, +		     ARIZONA_HPLPF1_1, +		     ARIZONA_LHPF1_MODE_SHIFT, +		     arizona_lhpf_mode_text);  EXPORT_SYMBOL_GPL(arizona_lhpf1_mode); -const struct soc_enum arizona_lhpf2_mode = -	SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2, -			arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode, +		     ARIZONA_HPLPF2_1, +		     ARIZONA_LHPF2_MODE_SHIFT, +		     arizona_lhpf_mode_text);  EXPORT_SYMBOL_GPL(arizona_lhpf2_mode); -const struct soc_enum arizona_lhpf3_mode = -	SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2, -			arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode, +		     ARIZONA_HPLPF3_1, +		     ARIZONA_LHPF3_MODE_SHIFT, +		     arizona_lhpf_mode_text);  EXPORT_SYMBOL_GPL(arizona_lhpf3_mode); -const struct soc_enum arizona_lhpf4_mode = -	SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2, -			arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode, +		     ARIZONA_HPLPF4_1, +		     ARIZONA_LHPF4_MODE_SHIFT, +		     arizona_lhpf_mode_text);  EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);  static const char *arizona_ng_hold_text[] = {  	"30ms", "120ms", "250ms", "500ms",  }; -const struct soc_enum arizona_ng_hold = -	SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT, -			4, arizona_ng_hold_text); +SOC_ENUM_SINGLE_DECL(arizona_ng_hold, +		     ARIZONA_NOISE_GATE_CONTROL, +		     ARIZONA_NGATE_HOLD_SHIFT, +		     arizona_ng_hold_text);  EXPORT_SYMBOL_GPL(arizona_ng_hold); +static const char * const arizona_in_hpf_cut_text[] = { +	"2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" +}; + +SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum, +		     ARIZONA_HPF_CONTROL, +		     ARIZONA_IN_HPF_CUT_SHIFT, +		     arizona_in_hpf_cut_text); +EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); +  static const char * const arizona_in_dmic_osr_text[] = {  	"1.536MHz", "3.072MHz", "6.144MHz",  }; @@ -669,6 +731,7 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,  		   int event)  {  	struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); +	struct arizona *arizona = priv->arizona;  	unsigned int mask = 1 << w->shift;  	unsigned int val; @@ -691,7 +754,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,  	if (priv->arizona->hpdet_magic)  		val = 0; -	snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val); +	regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, +				 mask, val);  	return arizona_out_ev(w, kcontrol, event);  } @@ -846,6 +910,8 @@ EXPORT_SYMBOL_GPL(arizona_set_sysclk);  static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  {  	struct snd_soc_codec *codec = dai->codec; +	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); +	struct arizona *arizona = priv->arizona;  	int lrclk, bclk, mode, base;  	base = dai->driver->base; @@ -902,17 +968,19 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  		return -EINVAL;  	} -	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, -			    ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR, -			    bclk); -	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL, -			    ARIZONA_AIF1TX_LRCLK_INV | -			    ARIZONA_AIF1TX_LRCLK_MSTR, lrclk); -	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL, -			    ARIZONA_AIF1RX_LRCLK_INV | -			    ARIZONA_AIF1RX_LRCLK_MSTR, lrclk); -	snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT, -			    ARIZONA_AIF1_FMT_MASK, mode); +	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL, +				 ARIZONA_AIF1_BCLK_INV | +				 ARIZONA_AIF1_BCLK_MSTR, +				 bclk); +	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL, +				 ARIZONA_AIF1TX_LRCLK_INV | +				 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk); +	regmap_update_bits_async(arizona->regmap, +				 base + ARIZONA_AIF_RX_PIN_CTRL, +				 ARIZONA_AIF1RX_LRCLK_INV | +				 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk); +	regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT, +			   ARIZONA_AIF1_FMT_MASK, mode);  	return 0;  } @@ -1164,18 +1232,22 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,  	if (ret != 0)  		return ret; -	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, -			    ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); -	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE, -			    ARIZONA_AIF1TX_BCPF_MASK, lrclk); -	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE, -			    ARIZONA_AIF1RX_BCPF_MASK, lrclk); -	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1, -			    ARIZONA_AIF1TX_WL_MASK | -			    ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); -	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2, -			    ARIZONA_AIF1RX_WL_MASK | -			    ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); +	regmap_update_bits_async(arizona->regmap, +				 base + ARIZONA_AIF_BCLK_CTRL, +				 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); +	regmap_update_bits_async(arizona->regmap, +				 base + ARIZONA_AIF_TX_BCLK_RATE, +				 ARIZONA_AIF1TX_BCPF_MASK, lrclk); +	regmap_update_bits_async(arizona->regmap, +				 base + ARIZONA_AIF_RX_BCLK_RATE, +				 ARIZONA_AIF1RX_BCPF_MASK, lrclk); +	regmap_update_bits_async(arizona->regmap, +				 base + ARIZONA_AIF_FRAME_CTRL_1, +				 ARIZONA_AIF1TX_WL_MASK | +				 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); +	regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2, +			   ARIZONA_AIF1RX_WL_MASK | +			   ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);  	return 0;  } @@ -1322,74 +1394,147 @@ struct arizona_fll_cfg {  	int gain;  }; -static int arizona_calc_fll(struct arizona_fll *fll, -			    struct arizona_fll_cfg *cfg, -			    unsigned int Fref, -			    unsigned int Fout) +static int arizona_validate_fll(struct arizona_fll *fll, +				unsigned int Fref, +				unsigned int Fout)  { -	unsigned int target, div, gcd_fll; -	int i, ratio; +	unsigned int Fvco_min; + +	if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { +		arizona_fll_err(fll, +				"Can't scale %dMHz in to <=13.5MHz\n", +				Fref); +		return -EINVAL; +	} + +	Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult; +	if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) { +		arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", +				Fout); +		return -EINVAL; +	} + +	return 0; +} + +static int arizona_find_fratio(unsigned int Fref, int *fratio) +{ +	int i; + +	/* Find an appropriate FLL_FRATIO */ +	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { +		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { +			if (fratio) +				*fratio = fll_fratios[i].fratio; +			return fll_fratios[i].ratio; +		} +	} + +	return -EINVAL; +} -	arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); +static int arizona_calc_fratio(struct arizona_fll *fll, +			       struct arizona_fll_cfg *cfg, +			       unsigned int target, +			       unsigned int Fref, bool sync) +{ +	int init_ratio, ratio; +	int refdiv, div; -	/* Fref must be <=13.5MHz */ +	/* Fref must be <=13.5MHz, find initial refdiv */  	div = 1;  	cfg->refdiv = 0; -	while ((Fref / div) > 13500000) { +	while (Fref > ARIZONA_FLL_MAX_FREF) {  		div *= 2; +		Fref /= 2;  		cfg->refdiv++; -		if (div > 8) { -			arizona_fll_err(fll, -					"Can't scale %dMHz in to <=13.5MHz\n", -					Fref); +		if (div > ARIZONA_FLL_MAX_REFDIV)  			return -EINVAL; +	} + +	/* Find an appropriate FLL_FRATIO */ +	init_ratio = arizona_find_fratio(Fref, &cfg->fratio); +	if (init_ratio < 0) { +		arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", +				Fref); +		return init_ratio; +	} + +	switch (fll->arizona->type) { +	case WM5110: +		if (fll->arizona->rev < 3 || sync) +			return init_ratio; +		break; +	default: +		return init_ratio; +	} + +	cfg->fratio = init_ratio - 1; + +	/* Adjust FRATIO/refdiv to avoid integer mode if possible */ +	refdiv = cfg->refdiv; + +	while (div <= ARIZONA_FLL_MAX_REFDIV) { +		for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; +		     ratio++) { +			if (target % (ratio * Fref)) { +				cfg->refdiv = refdiv; +				cfg->fratio = ratio - 1; +				return ratio; +			} +		} + +		for (ratio = init_ratio - 1; ratio >= 0; ratio--) { +			if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < +			    Fref) +				break; + +			if (target % (ratio * Fref)) { +				cfg->refdiv = refdiv; +				cfg->fratio = ratio - 1; +				return ratio; +			}  		} + +		div *= 2; +		Fref /= 2; +		refdiv++; +		init_ratio = arizona_find_fratio(Fref, NULL);  	} -	/* Apply the division for our remaining calculations */ -	Fref /= div; +	arizona_fll_warn(fll, "Falling back to integer mode operation\n"); +	return cfg->fratio + 1; +} + +static int arizona_calc_fll(struct arizona_fll *fll, +			    struct arizona_fll_cfg *cfg, +			    unsigned int Fref, bool sync) +{ +	unsigned int target, div, gcd_fll; +	int i, ratio; + +	arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);  	/* Fvco should be over the targt; don't check the upper bound */ -	div = 1; -	while (Fout * div < 90000000 * fll->vco_mult) { +	div = ARIZONA_FLL_MIN_OUTDIV; +	while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {  		div++; -		if (div > 7) { -			arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", -					Fout); +		if (div > ARIZONA_FLL_MAX_OUTDIV)  			return -EINVAL; -		}  	} -	target = Fout * div / fll->vco_mult; +	target = fll->fout * div / fll->vco_mult;  	cfg->outdiv = div;  	arizona_fll_dbg(fll, "Fvco=%dHz\n", target); -	/* Find an appropraite FLL_FRATIO and factor it out of the target */ -	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { -		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { -			cfg->fratio = fll_fratios[i].fratio; -			ratio = fll_fratios[i].ratio; -			break; -		} -	} -	if (i == ARRAY_SIZE(fll_fratios)) { -		arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", -				Fref); -		return -EINVAL; -	} +	/* Find an appropriate FLL_FRATIO and refdiv */ +	ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync); +	if (ratio < 0) +		return ratio; -	for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { -		if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { -			cfg->gain = fll_gains[i].gain; -			break; -		} -	} -	if (i == ARRAY_SIZE(fll_gains)) { -		arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", -				Fref); -		return -EINVAL; -	} +	/* Apply the division for our remaining calculations */ +	Fref = Fref / (1 << cfg->refdiv);  	cfg->n = target / (ratio * Fref); @@ -1414,6 +1559,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,  		cfg->lambda >>= 1;  	} +	for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { +		if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { +			cfg->gain = fll_gains[i].gain; +			break; +		} +	} +	if (i == ARRAY_SIZE(fll_gains)) { +		arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", +				Fref); +		return -EINVAL; +	} +  	arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",  			cfg->n, cfg->theta, cfg->lambda);  	arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", @@ -1428,31 +1585,35 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,  			      struct arizona_fll_cfg *cfg, int source,  			      bool sync)  { -	regmap_update_bits(arizona->regmap, base + 3, -			   ARIZONA_FLL1_THETA_MASK, cfg->theta); -	regmap_update_bits(arizona->regmap, base + 4, -			   ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda); -	regmap_update_bits(arizona->regmap, base + 5, -			   ARIZONA_FLL1_FRATIO_MASK, -			   cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT); -	regmap_update_bits(arizona->regmap, base + 6, -			   ARIZONA_FLL1_CLK_REF_DIV_MASK | -			   ARIZONA_FLL1_CLK_REF_SRC_MASK, -			   cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | -			   source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); - -	if (sync) +	regmap_update_bits_async(arizona->regmap, base + 3, +				 ARIZONA_FLL1_THETA_MASK, cfg->theta); +	regmap_update_bits_async(arizona->regmap, base + 4, +				 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda); +	regmap_update_bits_async(arizona->regmap, base + 5, +				 ARIZONA_FLL1_FRATIO_MASK, +				 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT); +	regmap_update_bits_async(arizona->regmap, base + 6, +				 ARIZONA_FLL1_CLK_REF_DIV_MASK | +				 ARIZONA_FLL1_CLK_REF_SRC_MASK, +				 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | +				 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); + +	if (sync) {  		regmap_update_bits(arizona->regmap, base + 0x7,  				   ARIZONA_FLL1_GAIN_MASK,  				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); -	else +	} else { +		regmap_update_bits(arizona->regmap, base + 0x5, +				   ARIZONA_FLL1_OUTDIV_MASK, +				   cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);  		regmap_update_bits(arizona->regmap, base + 0x9,  				   ARIZONA_FLL1_GAIN_MASK,  				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); +	} -	regmap_update_bits(arizona->regmap, base + 2, -			   ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, -			   ARIZONA_FLL1_CTRL_UPD | cfg->n); +	regmap_update_bits_async(arizona->regmap, base + 2, +				 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, +				 ARIZONA_FLL1_CTRL_UPD | cfg->n);  }  static bool arizona_is_enabled_fll(struct arizona_fll *fll) @@ -1471,37 +1632,38 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll)  	return reg & ARIZONA_FLL1_ENA;  } -static void arizona_enable_fll(struct arizona_fll *fll, -			      struct arizona_fll_cfg *ref, -			      struct arizona_fll_cfg *sync) +static void arizona_enable_fll(struct arizona_fll *fll)  {  	struct arizona *arizona = fll->arizona;  	int ret; +	bool use_sync = false; +	struct arizona_fll_cfg cfg;  	/*  	 * If we have both REFCLK and SYNCCLK then enable both,  	 * otherwise apply the SYNCCLK settings to REFCLK.  	 */ -	if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) { -		regmap_update_bits(arizona->regmap, fll->base + 5, -				   ARIZONA_FLL1_OUTDIV_MASK, -				   ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); +	if (fll->ref_src >= 0 && fll->ref_freq && +	    fll->ref_src != fll->sync_src) { +		arizona_calc_fll(fll, &cfg, fll->ref_freq, false); -		arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, +		arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,  				  false); -		if (fll->sync_src >= 0) -			arizona_apply_fll(arizona, fll->base + 0x10, sync, +		if (fll->sync_src >= 0) { +			arizona_calc_fll(fll, &cfg, fll->sync_freq, true); + +			arizona_apply_fll(arizona, fll->base + 0x10, &cfg,  					  fll->sync_src, true); +			use_sync = true; +		}  	} else if (fll->sync_src >= 0) { -		regmap_update_bits(arizona->regmap, fll->base + 5, -				   ARIZONA_FLL1_OUTDIV_MASK, -				   sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); +		arizona_calc_fll(fll, &cfg, fll->sync_freq, false); -		arizona_apply_fll(arizona, fll->base, sync, +		arizona_apply_fll(arizona, fll->base, &cfg,  				  fll->sync_src, false); -		regmap_update_bits(arizona->regmap, fll->base + 0x11, -				   ARIZONA_FLL1_SYNC_ENA, 0); +		regmap_update_bits_async(arizona->regmap, fll->base + 0x11, +					 ARIZONA_FLL1_SYNC_ENA, 0);  	} else {  		arizona_fll_err(fll, "No clocks provided\n");  		return; @@ -1511,12 +1673,13 @@ static void arizona_enable_fll(struct arizona_fll *fll,  	 * Increase the bandwidth if we're not using a low frequency  	 * sync source.  	 */ -	if (fll->sync_src >= 0 && fll->sync_freq > 100000) -		regmap_update_bits(arizona->regmap, fll->base + 0x17, -				   ARIZONA_FLL1_SYNC_BW, 0); +	if (use_sync && fll->sync_freq > 100000) +		regmap_update_bits_async(arizona->regmap, fll->base + 0x17, +					 ARIZONA_FLL1_SYNC_BW, 0);  	else -		regmap_update_bits(arizona->regmap, fll->base + 0x17, -				   ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); +		regmap_update_bits_async(arizona->regmap, fll->base + 0x17, +					 ARIZONA_FLL1_SYNC_BW, +					 ARIZONA_FLL1_SYNC_BW);  	if (!arizona_is_enabled_fll(fll))  		pm_runtime_get(arizona->dev); @@ -1524,13 +1687,14 @@ static void arizona_enable_fll(struct arizona_fll *fll,  	/* Clear any pending completions */  	try_wait_for_completion(&fll->ok); -	regmap_update_bits(arizona->regmap, fll->base + 1, -			   ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); -	if (fll->ref_src >= 0 && fll->sync_src >= 0 && -	    fll->ref_src != fll->sync_src) -		regmap_update_bits(arizona->regmap, fll->base + 0x11, -				   ARIZONA_FLL1_SYNC_ENA, -				   ARIZONA_FLL1_SYNC_ENA); +	regmap_update_bits_async(arizona->regmap, fll->base + 1, +				 ARIZONA_FLL1_FREERUN, 0); +	regmap_update_bits_async(arizona->regmap, fll->base + 1, +				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); +	if (use_sync) +		regmap_update_bits_async(arizona->regmap, fll->base + 0x11, +					 ARIZONA_FLL1_SYNC_ENA, +					 ARIZONA_FLL1_SYNC_ENA);  	ret = wait_for_completion_timeout(&fll->ok,  					  msecs_to_jiffies(250)); @@ -1543,6 +1707,8 @@ static void arizona_disable_fll(struct arizona_fll *fll)  	struct arizona *arizona = fll->arizona;  	bool change; +	regmap_update_bits_async(arizona->regmap, fll->base + 1, +				 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);  	regmap_update_bits_check(arizona->regmap, fll->base + 1,  				 ARIZONA_FLL1_ENA, 0, &change);  	regmap_update_bits(arizona->regmap, fll->base + 0x11, @@ -1555,30 +1721,22 @@ static void arizona_disable_fll(struct arizona_fll *fll)  int arizona_set_fll_refclk(struct arizona_fll *fll, int source,  			   unsigned int Fref, unsigned int Fout)  { -	struct arizona_fll_cfg ref, sync;  	int ret;  	if (fll->ref_src == source && fll->ref_freq == Fref)  		return 0;  	if (fll->fout && Fref > 0) { -		ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); +		ret = arizona_validate_fll(fll, Fref, fll->fout);  		if (ret != 0)  			return ret; - -		if (fll->sync_src >= 0) { -			ret = arizona_calc_fll(fll, &sync, fll->sync_freq, -					       fll->fout); -			if (ret != 0) -				return ret; -		}  	}  	fll->ref_src = source;  	fll->ref_freq = Fref;  	if (fll->fout && Fref > 0) { -		arizona_enable_fll(fll, &ref, &sync); +		arizona_enable_fll(fll);  	}  	return 0; @@ -1588,7 +1746,6 @@ EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);  int arizona_set_fll(struct arizona_fll *fll, int source,  		    unsigned int Fref, unsigned int Fout)  { -	struct arizona_fll_cfg ref, sync;  	int ret;  	if (fll->sync_src == source && @@ -1597,13 +1754,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source,  	if (Fout) {  		if (fll->ref_src >= 0) { -			ret = arizona_calc_fll(fll, &ref, fll->ref_freq, -					       Fout); +			ret = arizona_validate_fll(fll, fll->ref_freq, Fout);  			if (ret != 0)  				return ret;  		} -		ret = arizona_calc_fll(fll, &sync, Fref, Fout); +		ret = arizona_validate_fll(fll, Fref, Fout);  		if (ret != 0)  			return ret;  	} @@ -1613,7 +1769,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source,  	fll->fout = Fout;  	if (Fout) { -		arizona_enable_fll(fll, &ref, &sync); +		arizona_enable_fll(fll);  	} else {  		arizona_disable_fll(fll);  	} diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9e81b639269..05ae17f5bca 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -81,7 +81,7 @@ struct arizona_priv {  	unsigned int spk_ena_pending:1;  }; -#define ARIZONA_NUM_MIXER_INPUTS 99 +#define ARIZONA_NUM_MIXER_INPUTS 103  extern const unsigned int arizona_mixer_tlv[];  extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; @@ -107,7 +107,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];  #define ARIZONA_MUX_CTL_DECL(name) \  	const struct snd_kcontrol_new name##_mux =	\ -		SOC_DAPM_VALUE_ENUM("Route", name##_enum) +		SOC_DAPM_ENUM("Route", name##_enum)  #define ARIZONA_MUX_ENUMS(name, base_reg) \  	static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg);      \ @@ -128,7 +128,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];  	ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40)  #define ARIZONA_MUX(name, ctrl) \ -	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) +	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)  #define ARIZONA_MUX_WIDGETS(name, name_str) \  	ARIZONA_MUX(name_str " Input", &name##_mux) @@ -166,26 +166,29 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];  	ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")  #define ARIZONA_DSP_ROUTES(name) \ -	{ name, NULL, name " Aux 1" }, \ -	{ name, NULL, name " Aux 2" }, \ -	{ name, NULL, name " Aux 3" }, \ -	{ name, NULL, name " Aux 4" }, \ -	{ name, NULL, name " Aux 5" }, \ -	{ name, NULL, name " Aux 6" }, \ +	{ name, NULL, name " Preloader"}, \ +	{ name " Preloader", NULL, name " Aux 1" }, \ +	{ name " Preloader", NULL, name " Aux 2" }, \ +	{ name " Preloader", NULL, name " Aux 3" }, \ +	{ name " Preloader", NULL, name " Aux 4" }, \ +	{ name " Preloader", NULL, name " Aux 5" }, \ +	{ name " Preloader", NULL, name " Aux 6" }, \  	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \  	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \  	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \  	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \  	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \  	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \ -	ARIZONA_MIXER_ROUTES(name, name "L"), \ -	ARIZONA_MIXER_ROUTES(name, name "R") +	ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \ +	ARIZONA_MIXER_ROUTES(name " Preloader", name "R")  #define ARIZONA_RATE_ENUM_SIZE 4  extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];  extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];  extern const struct soc_enum arizona_isrc_fsl[]; +extern const struct soc_enum arizona_isrc_fsh[]; +extern const struct soc_enum arizona_asrc_rate1;  extern const struct soc_enum arizona_in_vi_ramp;  extern const struct soc_enum arizona_in_vd_ramp; @@ -199,6 +202,7 @@ extern const struct soc_enum arizona_lhpf3_mode;  extern const struct soc_enum arizona_lhpf4_mode;  extern const struct soc_enum arizona_ng_hold; +extern const struct soc_enum arizona_in_hpf_cut_enum;  extern const struct soc_enum arizona_in_dmic_osr[];  extern int arizona_in_ev(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 23316c887b1..537327c7f7f 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -38,24 +38,6 @@  #include <sound/soc.h>  #include <sound/initval.h> -static inline unsigned int cq93vc_read(struct snd_soc_codec *codec, -						unsigned int reg) -{ -	struct davinci_vc *davinci_vc = codec->control_data; - -	return readl(davinci_vc->base + reg); -} - -static inline int cq93vc_write(struct snd_soc_codec *codec, unsigned int reg, -		       unsigned int value) -{ -	struct davinci_vc *davinci_vc = codec->control_data; - -	writel(value, davinci_vc->base + reg); - -	return 0; -} -  static const struct snd_kcontrol_new cq93vc_snd_controls[] = {  	SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0),  	SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0), @@ -64,13 +46,15 @@ static const struct snd_kcontrol_new cq93vc_snd_controls[] = {  static int cq93vc_mute(struct snd_soc_dai *dai, int mute)  {  	struct snd_soc_codec *codec = dai->codec; -	u8 reg = cq93vc_read(codec, DAVINCI_VC_REG09) & ~DAVINCI_VC_REG09_MUTE; +	u8 reg;  	if (mute) -		cq93vc_write(codec, DAVINCI_VC_REG09, -			     reg | DAVINCI_VC_REG09_MUTE); +		reg = DAVINCI_VC_REG09_MUTE;  	else -		cq93vc_write(codec, DAVINCI_VC_REG09, reg); +		reg = 0; + +	snd_soc_update_bits(codec, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE, +			    reg);  	return 0;  } @@ -79,7 +63,7 @@ static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,  				 int clk_id, unsigned int freq, int dir)  {  	struct snd_soc_codec *codec = codec_dai->codec; -	struct davinci_vc *davinci_vc = codec->control_data; +	struct davinci_vc *davinci_vc = codec->dev->platform_data;  	switch (freq) {  	case 22579200: @@ -97,18 +81,18 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,  {  	switch (level) {  	case SND_SOC_BIAS_ON: -		cq93vc_write(codec, DAVINCI_VC_REG12, +		snd_soc_write(codec, DAVINCI_VC_REG12,  			     DAVINCI_VC_REG12_POWER_ALL_ON);  		break;  	case SND_SOC_BIAS_PREPARE:  		break;  	case SND_SOC_BIAS_STANDBY: -		cq93vc_write(codec, DAVINCI_VC_REG12, +		snd_soc_write(codec, DAVINCI_VC_REG12,  			     DAVINCI_VC_REG12_POWER_ALL_OFF);  		break;  	case SND_SOC_BIAS_OFF:  		/* force all power off */ -		cq93vc_write(codec, DAVINCI_VC_REG12, +		snd_soc_write(codec, DAVINCI_VC_REG12,  			     DAVINCI_VC_REG12_POWER_ALL_OFF);  		break;  	} @@ -154,11 +138,6 @@ static int cq93vc_probe(struct snd_soc_codec *codec)  	struct davinci_vc *davinci_vc = codec->dev->platform_data;  	davinci_vc->cq93vc.codec = codec; -	codec->control_data = davinci_vc; - -	/* Set controls */ -	snd_soc_add_codec_controls(codec, cq93vc_snd_controls, -			     ARRAY_SIZE(cq93vc_snd_controls));  	/* Off, with power on */  	cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -173,13 +152,21 @@ static int cq93vc_remove(struct snd_soc_codec *codec)  	return 0;  } +static struct regmap *cq93vc_get_regmap(struct device *dev) +{ +	struct davinci_vc *davinci_vc = dev->platform_data; + +	return davinci_vc->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { -	.read = cq93vc_read, -	.write = cq93vc_write,  	.set_bias_level = cq93vc_set_bias_level,  	.probe = cq93vc_probe,  	.remove = cq93vc_remove,  	.resume = cq93vc_resume, +	.get_regmap = cq93vc_get_regmap, +	.controls = cq93vc_snd_controls, +	.num_controls = ARRAY_SIZE(cq93vc_snd_controls),  };  static int cq93vc_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 83c835d9fd8..9947a958367 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -438,7 +438,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)  static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);  	int left = !ucontrol->value.integer.value[0];  	int right = !ucontrol->value.integer.value[1]; @@ -506,15 +506,6 @@ static int cs4270_probe(struct snd_soc_codec *codec)  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);  	int ret; -	/* Tell ASoC what kind of I/O to use to read the registers.  ASoC will -	 * then do the I2C transactions itself. -	 */ -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); -		return ret; -	} -  	/* Disable auto-mute.  This feature appears to be buggy.  In some  	 * situations, auto-mute will not deactivate when it should, so we want  	 * this feature disabled by default.  An application (e.g. alsactl) can diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index a20f1bb8f07..93cec52f473 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -25,6 +25,7 @@  #include <linux/gpio.h>  #include <linux/i2c.h>  #include <linux/spi/spi.h> +#include <linux/of.h>  #include <linux/of_device.h>  #include <linux/of_gpio.h>  #include <sound/pcm.h> @@ -158,7 +159,6 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)  }  struct cs4271_private { -	/* SND_SOC_I2C or SND_SOC_SPI */  	unsigned int			mclk;  	bool				master;  	bool				deemph; @@ -284,7 +284,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec)  static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = cs4271->deemph; @@ -294,7 +294,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,  static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);  	cs4271->deemph = ucontrol->value.enumerated.item[0]; @@ -539,14 +539,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)  	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);  	struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;  	int ret; -	int gpio_nreset = -EINVAL;  	bool amutec_eq_bmutec = false;  #ifdef CONFIG_OF  	if (of_match_device(cs4271_dt_ids, codec->dev)) { -		gpio_nreset = of_get_named_gpio(codec->dev->of_node, -						"reset-gpio", 0); -  		if (of_get_property(codec->dev->of_node,  				     "cirrus,amutec-eq-bmutec", NULL))  			amutec_eq_bmutec = true; @@ -558,27 +554,19 @@ static int cs4271_probe(struct snd_soc_codec *codec)  #endif  	if (cs4271plat) { -		if (gpio_is_valid(cs4271plat->gpio_nreset)) -			gpio_nreset = cs4271plat->gpio_nreset; -  		amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;  		cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;  	} -	if (gpio_nreset >= 0) -		if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) -			gpio_nreset = -EINVAL; -	if (gpio_nreset >= 0) { +	if (gpio_is_valid(cs4271->gpio_nreset)) {  		/* Reset codec */ -		gpio_direction_output(gpio_nreset, 0); +		gpio_direction_output(cs4271->gpio_nreset, 0);  		udelay(1); -		gpio_set_value(gpio_nreset, 1); +		gpio_set_value(cs4271->gpio_nreset, 1);  		/* Give the codec time to wake up */  		udelay(1);  	} -	cs4271->gpio_nreset = gpio_nreset; -  	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,  				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,  				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN); @@ -624,6 +612,36 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {  	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),  }; +static int cs4271_common_probe(struct device *dev, +			       struct cs4271_private **c) +{ +	struct cs4271_platform_data *cs4271plat = dev->platform_data; +	struct cs4271_private *cs4271; + +	cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL); +	if (!cs4271) +		return -ENOMEM; + +	if (of_match_device(cs4271_dt_ids, dev)) +		cs4271->gpio_nreset = +			of_get_named_gpio(dev->of_node, "reset-gpio", 0); + +	if (cs4271plat) +		cs4271->gpio_nreset = cs4271plat->gpio_nreset; + +	if (gpio_is_valid(cs4271->gpio_nreset)) { +		int ret; + +		ret = devm_gpio_request(dev, cs4271->gpio_nreset, +					"CS4271 Reset"); +		if (ret < 0) +			return ret; +	} + +	*c = cs4271; +	return 0; +} +  #if defined(CONFIG_SPI_MASTER)  static const struct regmap_config cs4271_spi_regmap = { @@ -643,10 +661,11 @@ static const struct regmap_config cs4271_spi_regmap = {  static int cs4271_spi_probe(struct spi_device *spi)  {  	struct cs4271_private *cs4271; +	int ret; -	cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL); -	if (!cs4271) -		return -ENOMEM; +	ret = cs4271_common_probe(&spi->dev, &cs4271); +	if (ret < 0) +		return ret;  	spi_set_drvdata(spi, cs4271);  	cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); @@ -674,7 +693,7 @@ static struct spi_driver cs4271_spi_driver = {  };  #endif /* defined(CONFIG_SPI_MASTER) */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static const struct i2c_device_id cs4271_i2c_id[] = {  	{"cs4271", 0},  	{} @@ -697,10 +716,11 @@ static int cs4271_i2c_probe(struct i2c_client *client,  			    const struct i2c_device_id *id)  {  	struct cs4271_private *cs4271; +	int ret; -	cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL); -	if (!cs4271) -		return -ENOMEM; +	ret = cs4271_common_probe(&client->dev, &cs4271); +	if (ret < 0) +		return ret;  	i2c_set_clientdata(client, cs4271);  	cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); @@ -727,7 +747,7 @@ static struct i2c_driver cs4271_i2c_driver = {  	.probe		= cs4271_i2c_probe,  	.remove		= cs4271_i2c_remove,  }; -#endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */ +#endif /* IS_ENABLED(CONFIG_I2C) */  /*   * We only register our serial bus driver here without @@ -740,7 +760,7 @@ static int __init cs4271_modinit(void)  {  	int ret; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&cs4271_i2c_driver);  	if (ret) {  		pr_err("Failed to register CS4271 I2C driver: %d\n", ret); @@ -766,7 +786,7 @@ static void __exit cs4271_modexit(void)  	spi_unregister_driver(&cs4271_spi_driver);  #endif -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&cs4271_i2c_driver);  #endif  } diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c new file mode 100644 index 00000000000..cee51ae177c --- /dev/null +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -0,0 +1,59 @@ +/* + * cs42l56.c -- CS42L51 ALSA SoC I2C audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin <brian.austin@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <sound/soc.h> + +#include "cs42l51.h" + +static struct i2c_device_id cs42l51_i2c_id[] = { +	{"cs42l51", 0}, +	{} +}; +MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); + +static int cs42l51_i2c_probe(struct i2c_client *i2c, +			     const struct i2c_device_id *id) +{ +	struct regmap_config config; + +	config = cs42l51_regmap; +	config.val_bits = 8; +	config.reg_bits = 8; + +	return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config)); +} + +static int cs42l51_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); + +	return 0; +} + +static struct i2c_driver cs42l51_i2c_driver = { +	.driver = { +		.name = "cs42l51", +		.owner = THIS_MODULE, +	}, +	.probe = cs42l51_i2c_probe, +	.remove = cs42l51_i2c_remove, +	.id_table = cs42l51_i2c_id, +}; + +module_i2c_driver(cs42l51_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L51 I2C Driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 1e0fa3b5f79..09488d97de6 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -29,7 +29,7 @@  #include <sound/initval.h>  #include <sound/pcm_params.h>  #include <sound/pcm.h> -#include <linux/i2c.h> +#include <linux/regmap.h>  #include "cs42l51.h" @@ -40,7 +40,6 @@ enum master_slave_mode {  };  struct cs42l51_private { -	enum snd_soc_control_type control_type;  	unsigned int mclk;  	unsigned int audio_mode;	/* The mode (I2S or left-justified) */  	enum master_slave_mode func; @@ -52,28 +51,10 @@ struct cs42l51_private {  		SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \  		SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE) -static int cs42l51_fill_cache(struct snd_soc_codec *codec) -{ -	u8 *cache = codec->reg_cache + 1; -	struct i2c_client *i2c_client = to_i2c_client(codec->dev); -	s32 length; - -	length = i2c_smbus_read_i2c_block_data(i2c_client, -			CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache); -	if (length != CS42L51_NUMREGS) { -		dev_err(&i2c_client->dev, -				"I2C read failure, addr=0x%x (ret=%d vs %d)\n", -				i2c_client->addr, length, CS42L51_NUMREGS); -		return -EIO; -	} - -	return 0; -} -  static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,  			struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;  	switch (value) { @@ -101,7 +82,7 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,  static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,  			struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned char val;  	switch (ucontrol->value.integer.value[0]) { @@ -124,9 +105,8 @@ static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,  static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);  static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); -/* This is a lie. after -102 db, it stays at -102 */ -/* maybe a range would be better */ -static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0); + +static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);  static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);  static const char *chan_mix[] = { @@ -135,13 +115,12 @@ static const char *chan_mix[] = {  	"R L",  }; -static const struct soc_enum cs42l51_chan_mix = -	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix); +static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix);  static const struct snd_kcontrol_new cs42l51_snd_controls[] = {  	SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",  			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, -			6, 0x19, 0x7F, adc_pcm_tlv), +			0, 0x19, 0x7F, adc_pcm_tlv),  	SOC_DOUBLE_R("PCM Playback Switch",  			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),  	SOC_DOUBLE_R_SX_TLV("Analog Playback Volume", @@ -149,7 +128,7 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {  			0, 0x34, 0xE4, aout_tlv),  	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",  			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, -			6, 0x19, 0x7F, adc_pcm_tlv), +			0, 0x19, 0x7F, adc_pcm_tlv),  	SOC_DOUBLE_R("ADC Mixer Switch",  			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),  	SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0), @@ -192,22 +171,22 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,  static const char *cs42l51_dac_names[] = {"Direct PCM",  	"DSP PCM", "ADC"}; -static const struct soc_enum cs42l51_dac_mux_enum = -	SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names); +static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum, +			    CS42L51_DAC_CTL, 6, cs42l51_dac_names);  static const struct snd_kcontrol_new cs42l51_dac_mux_controls =  	SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);  static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",  	"MIC Left", "MIC+preamp Left"}; -static const struct soc_enum cs42l51_adcl_mux_enum = -	SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names); +static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum, +			    CS42L51_ADC_INPUT, 4, cs42l51_adcl_names);  static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =  	SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);  static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",  	"MIC Right", "MIC+preamp Right"}; -static const struct soc_enum cs42l51_adcr_mux_enum = -	SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names); +static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum, +			    CS42L51_ADC_INPUT, 6, cs42l51_adcr_names);  static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =  	SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); @@ -423,21 +402,17 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,  		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);  		break;  	case SND_SOC_DAIFMT_RIGHT_J: -		switch (params_format(params)) { -		case SNDRV_PCM_FORMAT_S16_LE: -		case SNDRV_PCM_FORMAT_S16_BE: +		switch (params_width(params)) { +		case 16:  			fmt = CS42L51_DAC_DIF_RJ16;  			break; -		case SNDRV_PCM_FORMAT_S18_3LE: -		case SNDRV_PCM_FORMAT_S18_3BE: +		case 18:  			fmt = CS42L51_DAC_DIF_RJ18;  			break; -		case SNDRV_PCM_FORMAT_S20_3LE: -		case SNDRV_PCM_FORMAT_S20_3BE: +		case 20:  			fmt = CS42L51_DAC_DIF_RJ20;  			break; -		case SNDRV_PCM_FORMAT_S24_LE: -		case SNDRV_PCM_FORMAT_S24_BE: +		case 24:  			fmt = CS42L51_DAC_DIF_RJ24;  			break;  		default: @@ -507,23 +482,10 @@ static struct snd_soc_dai_driver cs42l51_dai = {  	.ops = &cs42l51_dai_ops,  }; -static int cs42l51_probe(struct snd_soc_codec *codec) +static int cs42l51_codec_probe(struct snd_soc_codec *codec)  { -	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);  	int ret, reg; -	ret = cs42l51_fill_cache(codec); -	if (ret < 0) { -		dev_err(codec->dev, "failed to fill register cache\n"); -		return ret; -	} - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/*  	 * DAC configuration  	 * - Use signal processor @@ -541,9 +503,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec)  }  static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { -	.probe = cs42l51_probe, -	.reg_cache_size = CS42L51_NUMREGS + 1, -	.reg_word_size = sizeof(u8), +	.probe = cs42l51_codec_probe,  	.controls = cs42l51_snd_controls,  	.num_controls = ARRAY_SIZE(cs42l51_snd_controls), @@ -553,69 +513,56 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {  	.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),  }; -static int cs42l51_i2c_probe(struct i2c_client *i2c_client, -	const struct i2c_device_id *id) +const struct regmap_config cs42l51_regmap = { +	.max_register = CS42L51_CHARGE_FREQ, +	.cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs42l51_regmap); + +int cs42l51_probe(struct device *dev, struct regmap *regmap)  {  	struct cs42l51_private *cs42l51; +	unsigned int val;  	int ret; +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); + +	cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private), +			       GFP_KERNEL); +	if (!cs42l51) +		return -ENOMEM; + +	dev_set_drvdata(dev, cs42l51); +  	/* Verify that we have a CS42L51 */ -	ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID); +	ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);  	if (ret < 0) { -		dev_err(&i2c_client->dev, "failed to read I2C\n"); +		dev_err(dev, "failed to read I2C\n");  		goto error;  	} -	if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && -	    (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { -		dev_err(&i2c_client->dev, "Invalid chip id\n"); +	if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && +	    (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { +		dev_err(dev, "Invalid chip id: %x\n", val);  		ret = -ENODEV;  		goto error;  	} +	dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n", +		 val & CS42L51_CHIP_REV_MASK); -	dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", -				ret & 7); - -	cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), -			       GFP_KERNEL); -	if (!cs42l51) { -		dev_err(&i2c_client->dev, "could not allocate codec\n"); -		return -ENOMEM; -	} - -	i2c_set_clientdata(i2c_client, cs42l51); -	cs42l51->control_type = SND_SOC_I2C; - -	ret =  snd_soc_register_codec(&i2c_client->dev, +	ret =  snd_soc_register_codec(dev,  			&soc_codec_device_cs42l51, &cs42l51_dai, 1);  error:  	return ret;  } +EXPORT_SYMBOL_GPL(cs42l51_probe); -static int cs42l51_i2c_remove(struct i2c_client *client) -{ -	snd_soc_unregister_codec(&client->dev); -	return 0; -} - -static const struct i2c_device_id cs42l51_id[] = { -	{"cs42l51", 0}, -	{} +static const struct of_device_id cs42l51_of_match[] = { +	{ .compatible = "cirrus,cs42l51", }, +	{ }  }; -MODULE_DEVICE_TABLE(i2c, cs42l51_id); - -static struct i2c_driver cs42l51_i2c_driver = { -	.driver = { -		.name = "cs42l51-codec", -		.owner = THIS_MODULE, -	}, -	.id_table = cs42l51_id, -	.probe = cs42l51_i2c_probe, -	.remove = cs42l51_i2c_remove, -}; - -module_i2c_driver(cs42l51_i2c_driver); - +MODULE_DEVICE_TABLE(of, cs42l51_of_match);  MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");  MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");  MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h index 2beeb171db4..8c55bf384bc 100644 --- a/sound/soc/codecs/cs42l51.h +++ b/sound/soc/codecs/cs42l51.h @@ -18,9 +18,15 @@  #ifndef _CS42L51_H  #define _CS42L51_H +struct device; + +extern const struct regmap_config cs42l51_regmap; +int cs42l51_probe(struct device *dev, struct regmap *regmap); +  #define CS42L51_CHIP_ID			0x1B  #define CS42L51_CHIP_REV_A		0x00  #define CS42L51_CHIP_REV_B		0x01 +#define CS42L51_CHIP_REV_MASK		0x07  #define CS42L51_CHIP_REV_ID		0x01  #define CS42L51_MK_CHIP_REV(a, b)	((a)<<3|(b)) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index be2ba1b6fe4..071fc77f2f0 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -17,6 +17,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/delay.h> +#include <linux/of_gpio.h>  #include <linux/pm.h>  #include <linux/i2c.h>  #include <linux/input.h> @@ -49,11 +50,9 @@ struct  cs42l52_private {  	u8 mclksel;  	u32 mclk;  	u8 flags; -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)  	struct input_dev *beep;  	struct work_struct beep_work;  	int beep_rate; -#endif  };  static const struct reg_default cs42l52_reg_defaults[] = { @@ -209,13 +208,11 @@ static const char * const cs42l52_adca_text[] = {  static const char * const cs42l52_adcb_text[] = {  	"Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"}; -static const struct soc_enum adca_enum = -	SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5, -		ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text); +static SOC_ENUM_SINGLE_DECL(adca_enum, +			    CS42L52_ADC_PGA_A, 5, cs42l52_adca_text); -static const struct soc_enum adcb_enum = -	SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5, -		ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text); +static SOC_ENUM_SINGLE_DECL(adcb_enum, +			    CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text);  static const struct snd_kcontrol_new adca_mux =  	SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum); @@ -228,32 +225,22 @@ static const char * const mic_bias_level_text[] = {  	"0.8 +VA", "0.83 +VA", "0.91 +VA"  }; -static const struct soc_enum mic_bias_level_enum = -	SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0, -			ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text); +static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum, +			    CS42L52_IFACE_CTL2, 0, mic_bias_level_text); -static const char * const cs42l52_mic_text[] = { "Single", "Differential" }; +static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" }; -static const struct soc_enum mica_enum = -	SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5, -			ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); +static SOC_ENUM_SINGLE_DECL(mica_enum, +			    CS42L52_MICA_CTL, 5, cs42l52_mic_text); -static const struct soc_enum micb_enum = -	SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5, -			ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); - -static const struct snd_kcontrol_new mica_mux = -	SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum); - -static const struct snd_kcontrol_new micb_mux = -	SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum); +static SOC_ENUM_SINGLE_DECL(micb_enum, +			    CS42L52_MICB_CTL, 5, cs42l52_mic_text);  static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; -static const struct soc_enum digital_output_mux_enum = -	SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6, -			ARRAY_SIZE(digital_output_mux_text), -			digital_output_mux_text); +static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum, +			    CS42L52_ADC_MISC_CTL, 6, +			    digital_output_mux_text);  static const struct snd_kcontrol_new digital_output_mux =  	SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum); @@ -263,18 +250,18 @@ static const char * const hp_gain_num_text[] = {  	"0.7099", "0.8399", "1.000", "1.1430"  }; -static const struct soc_enum hp_gain_enum = -	SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 5, -		ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text); +static SOC_ENUM_SINGLE_DECL(hp_gain_enum, +			    CS42L52_PB_CTL1, 5, +			    hp_gain_num_text);  static const char * const beep_pitch_text[] = {  	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",  	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"  }; -static const struct soc_enum beep_pitch_enum = -	SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4, -			ARRAY_SIZE(beep_pitch_text), beep_pitch_text); +static SOC_ENUM_SINGLE_DECL(beep_pitch_enum, +			    CS42L52_BEEP_FREQ, 4, +			    beep_pitch_text);  static const char * const beep_ontime_text[] = {  	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", @@ -282,66 +269,66 @@ static const char * const beep_ontime_text[] = {  	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"  }; -static const struct soc_enum beep_ontime_enum = -	SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0, -			ARRAY_SIZE(beep_ontime_text), beep_ontime_text); +static SOC_ENUM_SINGLE_DECL(beep_ontime_enum, +			    CS42L52_BEEP_FREQ, 0, +			    beep_ontime_text);  static const char * const beep_offtime_text[] = {  	"1.23 s", "2.58 s", "3.90 s", "5.20 s",  	"6.60 s", "8.05 s", "9.35 s", "10.80 s"  }; -static const struct soc_enum beep_offtime_enum = -	SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5, -			ARRAY_SIZE(beep_offtime_text), beep_offtime_text); +static SOC_ENUM_SINGLE_DECL(beep_offtime_enum, +			    CS42L52_BEEP_VOL, 5, +			    beep_offtime_text);  static const char * const beep_config_text[] = {  	"Off", "Single", "Multiple", "Continuous"  }; -static const struct soc_enum beep_config_enum = -	SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6, -			ARRAY_SIZE(beep_config_text), beep_config_text); +static SOC_ENUM_SINGLE_DECL(beep_config_enum, +			    CS42L52_BEEP_TONE_CTL, 6, +			    beep_config_text);  static const char * const beep_bass_text[] = {  	"50 Hz", "100 Hz", "200 Hz", "250 Hz"  }; -static const struct soc_enum beep_bass_enum = -	SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1, -			ARRAY_SIZE(beep_bass_text), beep_bass_text); +static SOC_ENUM_SINGLE_DECL(beep_bass_enum, +			    CS42L52_BEEP_TONE_CTL, 1, +			    beep_bass_text);  static const char * const beep_treble_text[] = {  	"5 kHz", "7 kHz", "10 kHz", " 15 kHz"  }; -static const struct soc_enum beep_treble_enum = -	SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3, -			ARRAY_SIZE(beep_treble_text), beep_treble_text); +static SOC_ENUM_SINGLE_DECL(beep_treble_enum, +			    CS42L52_BEEP_TONE_CTL, 3, +			    beep_treble_text);  static const char * const ng_threshold_text[] = {  	"-34dB", "-37dB", "-40dB", "-43dB",  	"-46dB", "-52dB", "-58dB", "-64dB"  }; -static const struct soc_enum ng_threshold_enum = -	SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2, -		ARRAY_SIZE(ng_threshold_text), ng_threshold_text); +static SOC_ENUM_SINGLE_DECL(ng_threshold_enum, +			    CS42L52_NOISE_GATE_CTL, 2, +			    ng_threshold_text);  static const char * const cs42l52_ng_delay_text[] = {  	"50ms", "100ms", "150ms", "200ms"}; -static const struct soc_enum ng_delay_enum = -	SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0, -		ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text); +static SOC_ENUM_SINGLE_DECL(ng_delay_enum, +			    CS42L52_NOISE_GATE_CTL, 0, +			    cs42l52_ng_delay_text);  static const char * const cs42l52_ng_type_text[] = {  	"Apply Specific", "Apply All"  }; -static const struct soc_enum ng_type_enum = -	SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6, -		ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text); +static SOC_ENUM_SINGLE_DECL(ng_type_enum, +			    CS42L52_NOISE_GATE_CTL, 6, +			    cs42l52_ng_type_text);  static const char * const left_swap_text[] = {  	"Left", "LR 2", "Right"}; @@ -352,7 +339,7 @@ static const char * const right_swap_text[] = {  static const unsigned int swap_values[] = { 0, 1, 3 };  static const struct soc_enum adca_swap_enum = -	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 1, +	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 3,  			      ARRAY_SIZE(left_swap_text),  			      left_swap_text,  			      swap_values); @@ -361,7 +348,7 @@ static const struct snd_kcontrol_new adca_mixer =  	SOC_DAPM_ENUM("Route", adca_swap_enum);  static const struct soc_enum pcma_swap_enum = -	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 1, +	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 3,  			      ARRAY_SIZE(left_swap_text),  			      left_swap_text,  			      swap_values); @@ -370,7 +357,7 @@ static const struct snd_kcontrol_new pcma_mixer =  	SOC_DAPM_ENUM("Route", pcma_swap_enum);  static const struct soc_enum adcb_swap_enum = -	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 1, +	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 3,  			      ARRAY_SIZE(right_swap_text),  			      right_swap_text,  			      swap_values); @@ -379,7 +366,7 @@ static const struct snd_kcontrol_new adcb_mixer =  	SOC_DAPM_ENUM("Route", adcb_swap_enum);  static const struct soc_enum pcmb_swap_enum = -	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 1, +	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 3,  			      ARRAY_SIZE(right_swap_text),  			      right_swap_text,  			      swap_values); @@ -530,6 +517,30 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = {  }; +static const struct snd_kcontrol_new cs42l52_mica_controls[] = { +	SOC_ENUM("MICA Select", mica_enum), +}; + +static const struct snd_kcontrol_new cs42l52_micb_controls[] = { +	SOC_ENUM("MICB Select", micb_enum), +}; + +static int cs42l52_add_mic_controls(struct snd_soc_codec *codec) +{ +	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec); +	struct cs42l52_platform_data *pdata = &cs42l52->pdata; + +	if (!pdata->mica_diff_cfg) +		snd_soc_add_codec_controls(codec, cs42l52_mica_controls, +				     ARRAY_SIZE(cs42l52_mica_controls)); + +	if (!pdata->micb_diff_cfg) +		snd_soc_add_codec_controls(codec, cs42l52_micb_controls, +				     ARRAY_SIZE(cs42l52_micb_controls)); + +	return 0; +} +  static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {  	SND_SOC_DAPM_INPUT("AIN1L"), @@ -549,9 +560,6 @@ static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {  	SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL,  0,  			SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux), -	SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux), -  	SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),  	SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),  	SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0), @@ -952,7 +960,6 @@ static int cs42l52_resume(struct snd_soc_codec *codec)  	return 0;  } -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)  static int beep_rates[] = {  	261, 522, 585, 667, 706, 774, 889, 1000,  	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 @@ -1086,29 +1093,15 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)  	snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,  			    CS42L52_BEEP_EN_MASK, 0);  } -#else -static void cs42l52_init_beep(struct snd_soc_codec *codec) -{ -} - -static void cs42l52_free_beep(struct snd_soc_codec *codec) -{ -} -#endif  static int cs42l52_probe(struct snd_soc_codec *codec)  {  	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec); -	int ret; -	codec->control_data = cs42l52->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	regcache_cache_only(cs42l52->regmap, true); +	cs42l52_add_mic_controls(codec); +  	cs42l52_init_beep(codec);  	cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1116,41 +1109,7 @@ static int cs42l52_probe(struct snd_soc_codec *codec)  	cs42l52->sysclk = CS42L52_DEFAULT_CLK;  	cs42l52->config.format = CS42L52_DEFAULT_FORMAT; -	/* Set Platform MICx CFG */ -	snd_soc_update_bits(codec, CS42L52_MICA_CTL, -			    CS42L52_MIC_CTL_TYPE_MASK, -				cs42l52->pdata.mica_cfg << -				CS42L52_MIC_CTL_TYPE_SHIFT); - -	snd_soc_update_bits(codec, CS42L52_MICB_CTL, -			    CS42L52_MIC_CTL_TYPE_MASK, -				cs42l52->pdata.micb_cfg << -				CS42L52_MIC_CTL_TYPE_SHIFT); - -	/* if Single Ended, Get Mic_Select */ -	if (cs42l52->pdata.mica_cfg) -		snd_soc_update_bits(codec, CS42L52_MICA_CTL, -				    CS42L52_MIC_CTL_MIC_SEL_MASK, -				cs42l52->pdata.mica_sel << -				CS42L52_MIC_CTL_MIC_SEL_SHIFT); -	if (cs42l52->pdata.micb_cfg) -		snd_soc_update_bits(codec, CS42L52_MICB_CTL, -				    CS42L52_MIC_CTL_MIC_SEL_MASK, -				cs42l52->pdata.micb_sel << -				CS42L52_MIC_CTL_MIC_SEL_SHIFT); - -	/* Set Platform Charge Pump Freq */ -	snd_soc_update_bits(codec, CS42L52_CHARGE_PUMP, -			    CS42L52_CHARGE_PUMP_MASK, -				cs42l52->pdata.chgfreq << -				CS42L52_CHARGE_PUMP_SHIFT); - -	/* Set Platform Bias Level */ -	snd_soc_update_bits(codec, CS42L52_IFACE_CTL2, -			    CS42L52_IFACE_CTL2_BIAS_LVL, -				cs42l52->pdata.micbias_lvl); - -	return ret; +	return 0;  }  static int cs42l52_remove(struct snd_soc_codec *codec) @@ -1205,9 +1164,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,  			     const struct i2c_device_id *id)  {  	struct cs42l52_private *cs42l52; +	struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev);  	int ret;  	unsigned int devid = 0;  	unsigned int reg; +	u32 val32;  	cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),  			       GFP_KERNEL); @@ -1221,12 +1182,55 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,  		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);  		return ret;  	} +	if (pdata) { +		cs42l52->pdata = *pdata; +	} else { +		pdata = devm_kzalloc(&i2c_client->dev, +				     sizeof(struct cs42l52_platform_data), +				GFP_KERNEL); +		if (!pdata) { +			dev_err(&i2c_client->dev, "could not allocate pdata\n"); +			return -ENOMEM; +		} +		if (i2c_client->dev.of_node) { +			if (of_property_read_bool(i2c_client->dev.of_node, +				"cirrus,mica-differential-cfg")) +				pdata->mica_diff_cfg = true; + +			if (of_property_read_bool(i2c_client->dev.of_node, +				"cirrus,micb-differential-cfg")) +				pdata->micb_diff_cfg = true; + +			if (of_property_read_u32(i2c_client->dev.of_node, +				"cirrus,micbias-lvl", &val32) >= 0) +				pdata->micbias_lvl = val32; + +			if (of_property_read_u32(i2c_client->dev.of_node, +				"cirrus,chgfreq-divisor", &val32) >= 0) +				pdata->chgfreq = val32; + +			pdata->reset_gpio = +				of_get_named_gpio(i2c_client->dev.of_node, +						"cirrus,reset-gpio", 0); +		} +		cs42l52->pdata = *pdata; +	} -	i2c_set_clientdata(i2c_client, cs42l52); +	if (cs42l52->pdata.reset_gpio) { +		ret = devm_gpio_request_one(&i2c_client->dev, +					    cs42l52->pdata.reset_gpio, +					    GPIOF_OUT_INIT_HIGH, +					    "CS42L52 /RST"); +		if (ret < 0) { +			dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", +				cs42l52->pdata.reset_gpio, ret); +			return ret; +		} +		gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 0); +		gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 1); +	} -	if (dev_get_platdata(&i2c_client->dev)) -		memcpy(&cs42l52->pdata, dev_get_platdata(&i2c_client->dev), -		       sizeof(cs42l52->pdata)); +	i2c_set_clientdata(i2c_client, cs42l52);  	ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch,  				    ARRAY_SIZE(cs42l52_threshold_patch)); @@ -1244,7 +1248,32 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,  		return ret;  	} -	regcache_cache_only(cs42l52->regmap, true); +	dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n", +		 reg & CS42L52_CHIP_REV_MASK); + +	/* Set Platform Data */ +	if (cs42l52->pdata.mica_diff_cfg) +		regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL, +				   CS42L52_MIC_CTL_TYPE_MASK, +				cs42l52->pdata.mica_diff_cfg << +				CS42L52_MIC_CTL_TYPE_SHIFT); + +	if (cs42l52->pdata.micb_diff_cfg) +		regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL, +				   CS42L52_MIC_CTL_TYPE_MASK, +				cs42l52->pdata.micb_diff_cfg << +				CS42L52_MIC_CTL_TYPE_SHIFT); + +	if (cs42l52->pdata.chgfreq) +		regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP, +				   CS42L52_CHARGE_PUMP_MASK, +				cs42l52->pdata.chgfreq << +				CS42L52_CHARGE_PUMP_SHIFT); + +	if (cs42l52->pdata.micbias_lvl) +		regmap_update_bits(cs42l52->regmap, CS42L52_IFACE_CTL2, +				   CS42L52_IFACE_CTL2_BIAS_LVL, +				cs42l52->pdata.micbias_lvl);  	ret =  snd_soc_register_codec(&i2c_client->dev,  			&soc_codec_dev_cs42l52, &cs42l52_dai, 1); @@ -1259,6 +1288,13 @@ static int cs42l52_i2c_remove(struct i2c_client *client)  	return 0;  } +static const struct of_device_id cs42l52_of_match[] = { +	{ .compatible = "cirrus,cs42l52", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, cs42l52_of_match); + +  static const struct i2c_device_id cs42l52_id[] = {  	{ "cs42l52", 0 },  	{ } @@ -1269,6 +1305,7 @@ static struct i2c_driver cs42l52_i2c_driver = {  	.driver = {  		.name = "cs42l52",  		.owner = THIS_MODULE, +		.of_match_table = cs42l52_of_match,  	},  	.id_table = cs42l52_id,  	.probe =    cs42l52_i2c_probe, diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h index 4277012c471..ac445993e6b 100644 --- a/sound/soc/codecs/cs42l52.h +++ b/sound/soc/codecs/cs42l52.h @@ -37,7 +37,7 @@  #define CS42L52_CHIP_REV_A0			0x00  #define CS42L52_CHIP_REV_A1			0x01  #define CS42L52_CHIP_REV_B0			0x02 -#define CS42L52_CHIP_REV_MASK			0x03 +#define CS42L52_CHIP_REV_MASK			0x07  #define CS42L52_PWRCTL1				0x02  #define CS42L52_PWRCTL1_PDN_ALL			0x9F @@ -179,7 +179,7 @@  #define CS42L52_MICB_CTL			0x11  #define	CS42L52_MIC_CTL_MIC_SEL_MASK		0xBF  #define	CS42L52_MIC_CTL_MIC_SEL_SHIFT		6 -#define CS42L52_MIC_CTL_TYPE_MASK		0xDF +#define CS42L52_MIC_CTL_TYPE_MASK		0x20  #define CS42L52_MIC_CTL_TYPE_SHIFT		5 @@ -269,6 +269,6 @@  #define CS42L52_FIX_BITS1			0x3E  #define CS42L52_FIX_BITS2			0x47 -#define CS42L52_MAX_REGISTER			0x34 +#define CS42L52_MAX_REGISTER			0x47  #endif diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c new file mode 100644 index 00000000000..fdc4bd27b0d --- /dev/null +++ b/sound/soc/codecs/cs42l56.c @@ -0,0 +1,1419 @@ +/* + * cs42l56.c -- CS42L56 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin <brian.austin@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/cs42l56.h> +#include "cs42l56.h" + +#define CS42L56_NUM_SUPPLIES 3 +static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = { +	"VA", +	"VCP", +	"VLDO", +}; + +struct  cs42l56_private { +	struct regmap *regmap; +	struct snd_soc_codec *codec; +	struct device *dev; +	struct cs42l56_platform_data pdata; +	struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES]; +	u32 mclk; +	u8 mclk_prediv; +	u8 mclk_div2; +	u8 mclk_ratio; +	u8 iface; +	u8 iface_fmt; +	u8 iface_inv; +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +	struct input_dev *beep; +	struct work_struct beep_work; +	int beep_rate; +#endif +}; + +static const struct reg_default cs42l56_reg_defaults[] = { +	{ 1, 0x56 },	/* r01	- ID 1 */ +	{ 2, 0x04 },	/* r02	- ID 2 */ +	{ 3, 0x7f },	/* r03	- Power Ctl 1 */ +	{ 4, 0xff },	/* r04	- Power Ctl 2 */ +	{ 5, 0x00 },	/* ro5	- Clocking Ctl 1 */ +	{ 6, 0x0b },	/* r06	- Clocking Ctl 2 */ +	{ 7, 0x00 },	/* r07	- Serial Format */ +	{ 8, 0x05 },	/* r08	- Class H Ctl */ +	{ 9, 0x0c },	/* r09	- Misc Ctl */ +	{ 10, 0x80 },	/* r0a	- INT Status */ +	{ 11, 0x00 },	/* r0b	- Playback Ctl */ +	{ 12, 0x0c },	/* r0c	- DSP Mute Ctl */ +	{ 13, 0x00 },	/* r0d	- ADCA Mixer Volume */ +	{ 14, 0x00 },	/* r0e	- ADCB Mixer Volume */ +	{ 15, 0x00 },	/* r0f	- PCMA Mixer Volume */ +	{ 16, 0x00 },	/* r10	- PCMB Mixer Volume */ +	{ 17, 0x00 },	/* r11	- Analog Input Advisory Volume */ +	{ 18, 0x00 },	/* r12	- Digital Input Advisory Volume */ +	{ 19, 0x00 },	/* r13	- Master A Volume */ +	{ 20, 0x00 },	/* r14	- Master B Volume */ +	{ 21, 0x00 },	/* r15	- Beep Freq / On Time */ +	{ 22, 0x00 },	/* r16	- Beep Volume / Off Time */ +	{ 23, 0x00 },	/* r17	- Beep Tone Ctl */ +	{ 24, 0x88 },	/* r18	- Tone Ctl */ +	{ 25, 0x00 },	/* r19	- Channel Mixer & Swap */ +	{ 26, 0x00 },	/* r1a	- AIN Ref Config / ADC Mux */ +	{ 27, 0xa0 },	/* r1b	- High-Pass Filter Ctl */ +	{ 28, 0x00 },	/* r1c	- Misc ADC Ctl */ +	{ 29, 0x00 },	/* r1d	- Gain & Bias Ctl */ +	{ 30, 0x00 },	/* r1e	- PGAA Mux & Volume */ +	{ 31, 0x00 },	/* r1f	- PGAB Mux & Volume */ +	{ 32, 0x00 },	/* r20	- ADCA Attenuator */ +	{ 33, 0x00 },	/* r21	- ADCB Attenuator */ +	{ 34, 0x00 },	/* r22	- ALC Enable & Attack Rate */ +	{ 35, 0xbf },	/* r23	- ALC Release Rate */ +	{ 36, 0x00 },	/* r24	- ALC Threshold */ +	{ 37, 0x00 },	/* r25	- Noise Gate Ctl */ +	{ 38, 0x00 },	/* r26	- ALC, Limiter, SFT, ZeroCross */ +	{ 39, 0x00 },	/* r27	- Analog Mute, LO & HP Mux */ +	{ 40, 0x00 },	/* r28	- HP A Volume */ +	{ 41, 0x00 },	/* r29	- HP B Volume */ +	{ 42, 0x00 },	/* r2a	- LINEOUT A Volume */ +	{ 43, 0x00 },	/* r2b	- LINEOUT B Volume */ +	{ 44, 0x00 },	/* r2c	- Limit Threshold Ctl */ +	{ 45, 0x7f },	/* r2d	- Limiter Ctl & Release Rate */ +	{ 46, 0x00 },	/* r2e	- Limiter Attack Rate */ +}; + +static bool cs42l56_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS42L56_CHIP_ID_1: +	case CS42L56_CHIP_ID_2: +	case CS42L56_PWRCTL_1: +	case CS42L56_PWRCTL_2: +	case CS42L56_CLKCTL_1: +	case CS42L56_CLKCTL_2: +	case CS42L56_SERIAL_FMT: +	case CS42L56_CLASSH_CTL: +	case CS42L56_MISC_CTL: +	case CS42L56_INT_STATUS: +	case CS42L56_PLAYBACK_CTL: +	case CS42L56_DSP_MUTE_CTL: +	case CS42L56_ADCA_MIX_VOLUME: +	case CS42L56_ADCB_MIX_VOLUME: +	case CS42L56_PCMA_MIX_VOLUME: +	case CS42L56_PCMB_MIX_VOLUME: +	case CS42L56_ANAINPUT_ADV_VOLUME: +	case CS42L56_DIGINPUT_ADV_VOLUME: +	case CS42L56_MASTER_A_VOLUME: +	case CS42L56_MASTER_B_VOLUME: +	case CS42L56_BEEP_FREQ_ONTIME: +	case CS42L56_BEEP_FREQ_OFFTIME: +	case CS42L56_BEEP_TONE_CFG: +	case CS42L56_TONE_CTL: +	case CS42L56_CHAN_MIX_SWAP: +	case CS42L56_AIN_REFCFG_ADC_MUX: +	case CS42L56_HPF_CTL: +	case CS42L56_MISC_ADC_CTL: +	case CS42L56_GAIN_BIAS_CTL: +	case CS42L56_PGAA_MUX_VOLUME: +	case CS42L56_PGAB_MUX_VOLUME: +	case CS42L56_ADCA_ATTENUATOR: +	case CS42L56_ADCB_ATTENUATOR: +	case CS42L56_ALC_EN_ATTACK_RATE: +	case CS42L56_ALC_RELEASE_RATE: +	case CS42L56_ALC_THRESHOLD: +	case CS42L56_NOISE_GATE_CTL: +	case CS42L56_ALC_LIM_SFT_ZC: +	case CS42L56_AMUTE_HPLO_MUX: +	case CS42L56_HPA_VOLUME: +	case CS42L56_HPB_VOLUME: +	case CS42L56_LOA_VOLUME: +	case CS42L56_LOB_VOLUME: +	case CS42L56_LIM_THRESHOLD_CTL: +	case CS42L56_LIM_CTL_RELEASE_RATE: +	case CS42L56_LIM_ATTACK_RATE: +		return true; +	default: +		return false; +	} +} + +static bool cs42l56_volatile_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS42L56_INT_STATUS: +		return 1; +	default: +		return 0; +	} +} + +static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0); +static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0); +static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0); +static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0); +static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); +static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0); +static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); + +static const unsigned int ngnb_tlv[] = { +	TLV_DB_RANGE_HEAD(2), +	0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0), +	2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0), +}; +static const unsigned int ngb_tlv[] = { +	TLV_DB_RANGE_HEAD(2), +	0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0), +	3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0), +}; +static const unsigned int alc_tlv[] = { +	TLV_DB_RANGE_HEAD(2), +	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0), +	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0), +}; + +static const char * const beep_config_text[] = { +	"Off", "Single", "Multiple", "Continuous" +}; + +static const struct soc_enum beep_config_enum = +	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6, +			ARRAY_SIZE(beep_config_text), beep_config_text); + +static const char * const beep_pitch_text[] = { +	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", +	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" +}; + +static const struct soc_enum beep_pitch_enum = +	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4, +			ARRAY_SIZE(beep_pitch_text), beep_pitch_text); + +static const char * const beep_ontime_text[] = { +	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", +	"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s", +	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" +}; + +static const struct soc_enum beep_ontime_enum = +	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0, +			ARRAY_SIZE(beep_ontime_text), beep_ontime_text); + +static const char * const beep_offtime_text[] = { +	"1.23 s", "2.58 s", "3.90 s", "5.20 s", +	"6.60 s", "8.05 s", "9.35 s", "10.80 s" +}; + +static const struct soc_enum beep_offtime_enum = +	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5, +			ARRAY_SIZE(beep_offtime_text), beep_offtime_text); + +static const char * const beep_treble_text[] = { +	"5kHz", "7kHz", "10kHz", "15kHz" +}; + +static const struct soc_enum beep_treble_enum = +	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3, +			ARRAY_SIZE(beep_treble_text), beep_treble_text); + +static const char * const beep_bass_text[] = { +	"50Hz", "100Hz", "200Hz", "250Hz" +}; + +static const struct soc_enum beep_bass_enum = +	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1, +			ARRAY_SIZE(beep_bass_text), beep_bass_text); + +static const char * const adc_swap_text[] = { +	"None", "A+B/2", "A-B/2", "Swap" +}; + +static const struct soc_enum adc_swap_enum = +	SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3, +			ARRAY_SIZE(adc_swap_text), adc_swap_text); + +static const char * const pgaa_mux_text[] = { +	"AIN1A", "AIN2A", "AIN3A"}; + +static const struct soc_enum pgaa_mux_enum = +	SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0, +			      ARRAY_SIZE(pgaa_mux_text), +			      pgaa_mux_text); + +static const struct snd_kcontrol_new pgaa_mux = +	SOC_DAPM_ENUM("Route", pgaa_mux_enum); + +static const char * const pgab_mux_text[] = { +	"AIN1B", "AIN2B", "AIN3B"}; + +static const struct soc_enum pgab_mux_enum = +	SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0, +			      ARRAY_SIZE(pgab_mux_text), +			      pgab_mux_text); + +static const struct snd_kcontrol_new pgab_mux = +	SOC_DAPM_ENUM("Route", pgab_mux_enum); + +static const char * const adca_mux_text[] = { +	"PGAA", "AIN1A", "AIN2A", "AIN3A"}; + +static const struct soc_enum adca_mux_enum = +	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0, +			      ARRAY_SIZE(adca_mux_text), +			      adca_mux_text); + +static const struct snd_kcontrol_new adca_mux = +	SOC_DAPM_ENUM("Route", adca_mux_enum); + +static const char * const adcb_mux_text[] = { +	"PGAB", "AIN1B", "AIN2B", "AIN3B"}; + +static const struct soc_enum adcb_mux_enum = +	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2, +			      ARRAY_SIZE(adcb_mux_text), +			      adcb_mux_text); + +static const struct snd_kcontrol_new adcb_mux = +	SOC_DAPM_ENUM("Route", adcb_mux_enum); + +static const char * const left_swap_text[] = { +	"Left", "LR 2", "Right"}; + +static const char * const right_swap_text[] = { +	"Right", "LR 2", "Left"}; + +static const unsigned int swap_values[] = { 0, 1, 3 }; + +static const struct soc_enum adca_swap_enum = +	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3, +			      ARRAY_SIZE(left_swap_text), +			      left_swap_text, +			      swap_values); + +static const struct soc_enum pcma_swap_enum = +	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3, +			      ARRAY_SIZE(left_swap_text), +			      left_swap_text, +			      swap_values); + +static const struct soc_enum adcb_swap_enum = +	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3, +			      ARRAY_SIZE(right_swap_text), +			      right_swap_text, +			      swap_values); + +static const struct soc_enum pcmb_swap_enum = +	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3, +			      ARRAY_SIZE(right_swap_text), +			      right_swap_text, +			      swap_values); + +static const struct snd_kcontrol_new hpa_switch = +	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1); + +static const struct snd_kcontrol_new hpb_switch = +	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1); + +static const struct snd_kcontrol_new loa_switch = +	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1); + +static const struct snd_kcontrol_new lob_switch = +	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1); + +static const char * const hploa_input_text[] = { +	"DACA", "PGAA"}; + +static const struct soc_enum lineouta_input_enum = +	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2, +			      ARRAY_SIZE(hploa_input_text), +			      hploa_input_text); + +static const struct snd_kcontrol_new lineouta_input = +	SOC_DAPM_ENUM("Route", lineouta_input_enum); + +static const struct soc_enum hpa_input_enum = +	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0, +			      ARRAY_SIZE(hploa_input_text), +			      hploa_input_text); + +static const struct snd_kcontrol_new hpa_input = +	SOC_DAPM_ENUM("Route", hpa_input_enum); + +static const char * const hplob_input_text[] = { +	"DACB", "PGAB"}; + +static const struct soc_enum lineoutb_input_enum = +	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3, +			      ARRAY_SIZE(hplob_input_text), +			      hplob_input_text); + +static const struct snd_kcontrol_new lineoutb_input = +	SOC_DAPM_ENUM("Route", lineoutb_input_enum); + +static const struct soc_enum hpb_input_enum = +	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1, +			      ARRAY_SIZE(hplob_input_text), +			      hplob_input_text); + +static const struct snd_kcontrol_new hpb_input = +	SOC_DAPM_ENUM("Route", hpb_input_enum); + +static const char * const dig_mux_text[] = { +	"ADC", "DSP"}; + +static const struct soc_enum dig_mux_enum = +	SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7, +			      ARRAY_SIZE(dig_mux_text), +			      dig_mux_text); + +static const struct snd_kcontrol_new dig_mux = +	SOC_DAPM_ENUM("Route", dig_mux_enum); + +static const char * const hpf_freq_text[] = { +	"1.8Hz", "119Hz", "236Hz", "464Hz" +}; + +static const struct soc_enum hpfa_freq_enum = +	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0, +			ARRAY_SIZE(hpf_freq_text), hpf_freq_text); + +static const struct soc_enum hpfb_freq_enum = +	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2, +			ARRAY_SIZE(hpf_freq_text), hpf_freq_text); + +static const char * const ng_delay_text[] = { +	"50ms", "100ms", "150ms", "200ms" +}; + +static const struct soc_enum ng_delay_enum = +	SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0, +			ARRAY_SIZE(ng_delay_text), ng_delay_text); + +static const struct snd_kcontrol_new cs42l56_snd_controls[] = { + +	SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME, +			      CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xfd, adv_tlv), +	SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1), + +	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME, +			      CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), +	SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1), + +	SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME, +			      CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), +	SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1), + +	SOC_SINGLE_TLV("Analog Advisory Volume", +			  CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), +	SOC_SINGLE_TLV("Digital Advisory Volume", +			  CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), + +	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME, +			      CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0xfd, pga_tlv), +	SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR, +			      CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv), +	SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1), +	SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), + +	SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, +			      CS42L56_HPA_VOLUME, 0, 0x44, 0x55, hl_tlv), +	SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, +			      CS42L56_LOA_VOLUME, 0, 0x44, 0x55, hl_tlv), + +	SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, +			0, 0x00, 1, tone_tlv), +	SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL, +			4, 0x00, 1, tone_tlv), + +	SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL, +			4, 6, 0x02, 1, preamp_tlv), + +	SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1), +	SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1), +	SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1), +	SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1), + +	SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1), +	SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1), +	SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1), +	SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1), + +	SOC_ENUM("PCMA Swap", pcma_swap_enum), +	SOC_ENUM("PCMB Swap", pcmb_swap_enum), +	SOC_ENUM("ADCA Swap", adca_swap_enum), +	SOC_ENUM("ADCB Swap", adcb_swap_enum), + +	SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1), +	SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1), +	SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum), +	SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum), + +	SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1), +	SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC, +		7, 5, 1, 1), +	SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1), +	SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC, +		6, 4, 1, 1), +	SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1), +	SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC, +		3, 1, 1), + +	SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1), + +	SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1), +	SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1), +	SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE, +			0, 0, 0x3f, 0), +	SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE, +			0, 0x3f, 0, 0), +	SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD, +			5, 0x07, 1, alc_tlv), +	SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD, +			2, 0x07, 1, alc_tlv), + +	SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1), +	SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1), +	SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE, +			0, 0, 0x3f, 0), +	SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE, +			0, 0x3f, 0, 0), +	SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL, +			5, 0x07, 1, alc_tlv), +	SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD, +			2, 0x07, 1, alc_tlv), + +	SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1), +	SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1), +	SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1), +	SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL, +			2, 0x07, 1, ngnb_tlv), +	SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL, +			2, 0x07, 1, ngb_tlv), +	SOC_ENUM("NG Delay", ng_delay_enum), + +	SOC_ENUM("Beep Config", beep_config_enum), +	SOC_ENUM("Beep Pitch", beep_pitch_enum), +	SOC_ENUM("Beep on Time", beep_ontime_enum), +	SOC_ENUM("Beep off Time", beep_offtime_enum), +	SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME, +			0, 0x07, 0x23, beep_tlv), +	SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1), +	SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum), +	SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum), + +}; + +static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = { + +	SND_SOC_DAPM_SIGGEN("Beep"), +	SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0), +	SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1), +	SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0), + +	SND_SOC_DAPM_INPUT("AIN1A"), +	SND_SOC_DAPM_INPUT("AIN2A"), +	SND_SOC_DAPM_INPUT("AIN1B"), +	SND_SOC_DAPM_INPUT("AIN2B"), +	SND_SOC_DAPM_INPUT("AIN3A"), +	SND_SOC_DAPM_INPUT("AIN3B"), + +	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL,  0, +			SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_AIF_IN("SDIN", NULL,  0, +			SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM, +			 0, 0, &dig_mux), + +	SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MUX("PGAA Input Mux", +			SND_SOC_NOPM, 0, 0, &pgaa_mux), +	SND_SOC_DAPM_MUX("PGAB Input Mux", +			SND_SOC_NOPM, 0, 0, &pgab_mux), + +	SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM, +			 0, 0, &adca_mux), +	SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM, +			 0, 0, &adcb_mux), + +	SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1), +	SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1), + +	SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_OUTPUT("HPA"), +	SND_SOC_DAPM_OUTPUT("LOA"), +	SND_SOC_DAPM_OUTPUT("HPB"), +	SND_SOC_DAPM_OUTPUT("LOB"), + +	SND_SOC_DAPM_SWITCH("Headphone Right", +			    CS42L56_PWRCTL_2, 4, 1, &hpb_switch), +	SND_SOC_DAPM_SWITCH("Headphone Left", +			    CS42L56_PWRCTL_2, 6, 1, &hpa_switch), + +	SND_SOC_DAPM_SWITCH("Lineout Right", +			    CS42L56_PWRCTL_2, 0, 1, &lob_switch), +	SND_SOC_DAPM_SWITCH("Lineout Left", +			    CS42L56_PWRCTL_2, 2, 1, &loa_switch), + +	SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM, +			 0, 0, &lineouta_input), +	SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM, +			 0, 0, &lineoutb_input), +	SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM, +			 0, 0, &hpa_input), +	SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM, +			 0, 0, &hpb_input), + +}; + +static const struct snd_soc_dapm_route cs42l56_audio_map[] = { + +	{"HiFi Capture", "DSP", "Digital Output Mux"}, +	{"HiFi Capture", "ADC", "Digital Output Mux"}, + +	{"Digital Output Mux", NULL, "ADCA"}, +	{"Digital Output Mux", NULL, "ADCB"}, + +	{"ADCB", NULL, "ADCB Mux"}, +	{"ADCA", NULL, "ADCA Mux"}, + +	{"ADCA Mux", NULL, "AIN3A"}, +	{"ADCA Mux", NULL, "AIN2A"}, +	{"ADCA Mux", NULL, "AIN1A"}, +	{"ADCA Mux", NULL, "PGAA"}, +	{"ADCB Mux", NULL, "AIN3B"}, +	{"ADCB Mux", NULL, "AIN2B"}, +	{"ADCB Mux", NULL, "AIN1B"}, +	{"ADCB Mux", NULL, "PGAB"}, + +	{"PGAA", "AIN1A", "PGAA Input Mux"}, +	{"PGAA", "AIN2A", "PGAA Input Mux"}, +	{"PGAA", "AIN3A", "PGAA Input Mux"}, +	{"PGAB", "AIN1B", "PGAB Input Mux"}, +	{"PGAB", "AIN2B", "PGAB Input Mux"}, +	{"PGAB", "AIN3B", "PGAB Input Mux"}, + +	{"PGAA Input Mux", NULL, "AIN1A"}, +	{"PGAA Input Mux", NULL, "AIN2A"}, +	{"PGAA Input Mux", NULL, "AIN3A"}, +	{"PGAB Input Mux", NULL, "AIN1B"}, +	{"PGAB Input Mux", NULL, "AIN2B"}, +	{"PGAB Input Mux", NULL, "AIN3B"}, + +	{"LOB", NULL, "Lineout Right"}, +	{"LOA", NULL, "Lineout Left"}, + +	{"Lineout Right", "Switch", "LINEOUTB Input Mux"}, +	{"Lineout Left", "Switch", "LINEOUTA Input Mux"}, + +	{"LINEOUTA Input Mux", "PGAA", "PGAA"}, +	{"LINEOUTB Input Mux", "PGAB", "PGAB"}, +	{"LINEOUTA Input Mux", "DACA", "DACA"}, +	{"LINEOUTB Input Mux", "DACB", "DACB"}, + +	{"HPA", NULL, "Headphone Left"}, +	{"HPB", NULL, "Headphone Right"}, + +	{"Headphone Right", "Switch", "HPB Input Mux"}, +	{"Headphone Left", "Switch", "HPA Input Mux"}, + +	{"HPA Input Mux", "PGAA", "PGAA"}, +	{"HPB Input Mux", "PGAB", "PGAB"}, +	{"HPA Input Mux", "DACA", "DACA"}, +	{"HPB Input Mux", "DACB", "DACB"}, + +	{"DACB", NULL, "HiFi Playback"}, +	{"DACA", NULL, "HiFi Playback"}, + +}; + +struct cs42l56_clk_para { +	u32 mclk; +	u32 srate; +	u8 ratio; +}; + +static const struct cs42l56_clk_para clk_ratio_table[] = { +	/* 8k */ +	{ 6000000, 8000, CS42L56_MCLK_LRCLK_768 }, +	{ 6144000, 8000, CS42L56_MCLK_LRCLK_750 }, +	{ 12000000, 8000, CS42L56_MCLK_LRCLK_768 }, +	{ 12288000, 8000, CS42L56_MCLK_LRCLK_750 }, +	{ 24000000, 8000, CS42L56_MCLK_LRCLK_768 }, +	{ 24576000, 8000, CS42L56_MCLK_LRCLK_750 }, +	/* 11.025k */ +	{ 5644800, 11025, CS42L56_MCLK_LRCLK_512}, +	{ 11289600, 11025, CS42L56_MCLK_LRCLK_512}, +	{ 22579200, 11025, CS42L56_MCLK_LRCLK_512 }, +	/* 11.0294k */ +	{ 6000000, 110294, CS42L56_MCLK_LRCLK_544 }, +	{ 12000000, 110294, CS42L56_MCLK_LRCLK_544 }, +	{ 24000000, 110294, CS42L56_MCLK_LRCLK_544 }, +	/* 12k */ +	{ 6000000, 12000, CS42L56_MCLK_LRCLK_500 }, +	{ 6144000, 12000, CS42L56_MCLK_LRCLK_512 }, +	{ 12000000, 12000, CS42L56_MCLK_LRCLK_500 }, +	{ 12288000, 12000, CS42L56_MCLK_LRCLK_512 }, +	{ 24000000, 12000, CS42L56_MCLK_LRCLK_500 }, +	{ 24576000, 12000, CS42L56_MCLK_LRCLK_512 }, +	/* 16k */ +	{ 6000000, 16000, CS42L56_MCLK_LRCLK_375 }, +	{ 6144000, 16000, CS42L56_MCLK_LRCLK_384 }, +	{ 12000000, 16000, CS42L56_MCLK_LRCLK_375 }, +	{ 12288000, 16000, CS42L56_MCLK_LRCLK_384 }, +	{ 24000000, 16000, CS42L56_MCLK_LRCLK_375 }, +	{ 24576000, 16000, CS42L56_MCLK_LRCLK_384 }, +	/* 22.050k */ +	{ 5644800, 22050, CS42L56_MCLK_LRCLK_256 }, +	{ 11289600, 22050, CS42L56_MCLK_LRCLK_256 }, +	{ 22579200, 22050, CS42L56_MCLK_LRCLK_256 }, +	/* 22.0588k */ +	{ 6000000, 220588, CS42L56_MCLK_LRCLK_272 }, +	{ 12000000, 220588, CS42L56_MCLK_LRCLK_272 }, +	{ 24000000, 220588, CS42L56_MCLK_LRCLK_272 }, +	/* 24k */ +	{ 6000000, 24000, CS42L56_MCLK_LRCLK_250 }, +	{ 6144000, 24000, CS42L56_MCLK_LRCLK_256 }, +	{ 12000000, 24000, CS42L56_MCLK_LRCLK_250 }, +	{ 12288000, 24000, CS42L56_MCLK_LRCLK_256 }, +	{ 24000000, 24000, CS42L56_MCLK_LRCLK_250 }, +	{ 24576000, 24000, CS42L56_MCLK_LRCLK_256 }, +	/* 32k */ +	{ 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, +	{ 6144000, 32000, CS42L56_MCLK_LRCLK_192 }, +	{ 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, +	{ 12288000, 32000, CS42L56_MCLK_LRCLK_192 }, +	{ 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, +	{ 24576000, 32000, CS42L56_MCLK_LRCLK_192 }, +	/* 44.118k */ +	{ 6000000, 44118, CS42L56_MCLK_LRCLK_136 }, +	{ 12000000, 44118, CS42L56_MCLK_LRCLK_136 }, +	{ 24000000, 44118, CS42L56_MCLK_LRCLK_136 }, +	/* 44.1k */ +	{ 5644800, 44100, CS42L56_MCLK_LRCLK_128 }, +	{ 11289600, 44100, CS42L56_MCLK_LRCLK_128 }, +	{ 22579200, 44100, CS42L56_MCLK_LRCLK_128 }, +	/* 48k */ +	{ 6000000, 48000, CS42L56_MCLK_LRCLK_125 }, +	{ 6144000, 48000, CS42L56_MCLK_LRCLK_128 }, +	{ 12000000, 48000, CS42L56_MCLK_LRCLK_125 }, +	{ 12288000, 48000, CS42L56_MCLK_LRCLK_128 }, +	{ 24000000, 48000, CS42L56_MCLK_LRCLK_125 }, +	{ 24576000, 48000, CS42L56_MCLK_LRCLK_128 }, +}; + +static int cs42l56_get_mclk_ratio(int mclk, int rate) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) { +		if (clk_ratio_table[i].mclk == mclk && +		    clk_ratio_table[i].srate == rate) +			return clk_ratio_table[i].ratio; +	} +	return -EINVAL; +} + +static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai, +			int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + +	switch (freq) { +	case CS42L56_MCLK_5P6448MHZ: +	case CS42L56_MCLK_6MHZ: +	case CS42L56_MCLK_6P144MHZ: +		cs42l56->mclk_div2 = 0; +		cs42l56->mclk_prediv = 0; +		break; +	case CS42L56_MCLK_11P2896MHZ: +	case CS42L56_MCLK_12MHZ: +	case CS42L56_MCLK_12P288MHZ: +		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2; +		cs42l56->mclk_prediv = 0; +		break; +	case CS42L56_MCLK_22P5792MHZ: +	case CS42L56_MCLK_24MHZ: +	case CS42L56_MCLK_24P576MHZ: +		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2; +		cs42l56->mclk_prediv = CS42L56_MCLK_PREDIV; +		break; +	default: +		return -EINVAL; +	} +	cs42l56->mclk = freq; + +	snd_soc_update_bits(codec, CS42L56_CLKCTL_1, +			    CS42L56_MCLK_PREDIV_MASK, +				cs42l56->mclk_prediv); +	snd_soc_update_bits(codec, CS42L56_CLKCTL_1, +			    CS42L56_MCLK_DIV2_MASK, +				cs42l56->mclk_div2); + +	return 0; +} + +static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		cs42l56->iface = CS42L56_MASTER_MODE; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		cs42l56->iface = CS42L56_SLAVE_MODE; +		break; +	default: +		return -EINVAL; +	} + +	 /* interface format */ +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S; +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J; +		break; +	default: +		return -EINVAL; +	} + +	/* sclk inversion */ +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		cs42l56->iface_inv = 0; +		break; +	case SND_SOC_DAIFMT_IB_NF: +		cs42l56->iface_inv = CS42L56_SCLK_INV; +		break; +	default: +		return -EINVAL; +	} + +	snd_soc_update_bits(codec, CS42L56_CLKCTL_1, +			    CS42L56_MS_MODE_MASK, cs42l56->iface); +	snd_soc_update_bits(codec, CS42L56_SERIAL_FMT, +			    CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt); +	snd_soc_update_bits(codec, CS42L56_CLKCTL_1, +			    CS42L56_SCLK_INV_MASK, cs42l56->iface_inv); +	return 0; +} + +static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute) +{ +	struct snd_soc_codec *codec = dai->codec; + +	if (mute) { +		/* Hit the DSP Mixer first */ +		snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL, +				    CS42L56_ADCAMIX_MUTE_MASK | +				    CS42L56_ADCBMIX_MUTE_MASK | +				    CS42L56_PCMAMIX_MUTE_MASK | +				    CS42L56_PCMBMIX_MUTE_MASK | +				    CS42L56_MSTB_MUTE_MASK | +				    CS42L56_MSTA_MUTE_MASK, +				    CS42L56_MUTE_ALL); +		/* Mute ADC's */ +		snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL, +				    CS42L56_ADCA_MUTE_MASK | +				    CS42L56_ADCB_MUTE_MASK, +				    CS42L56_MUTE_ALL); +		/* HP And LO */ +		snd_soc_update_bits(codec, CS42L56_HPA_VOLUME, +				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL); +		snd_soc_update_bits(codec, CS42L56_HPB_VOLUME, +				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL); +		snd_soc_update_bits(codec, CS42L56_LOA_VOLUME, +				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL); +		snd_soc_update_bits(codec, CS42L56_LOB_VOLUME, +				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL); +	} else { +		snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL, +				    CS42L56_ADCAMIX_MUTE_MASK | +				    CS42L56_ADCBMIX_MUTE_MASK | +				    CS42L56_PCMAMIX_MUTE_MASK | +				    CS42L56_PCMBMIX_MUTE_MASK | +				    CS42L56_MSTB_MUTE_MASK | +				    CS42L56_MSTA_MUTE_MASK, +				    CS42L56_UNMUTE); + +		snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL, +				    CS42L56_ADCA_MUTE_MASK | +				    CS42L56_ADCB_MUTE_MASK, +				    CS42L56_UNMUTE); + +		snd_soc_update_bits(codec, CS42L56_HPA_VOLUME, +				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE); +		snd_soc_update_bits(codec, CS42L56_HPB_VOLUME, +				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE); +		snd_soc_update_bits(codec, CS42L56_LOA_VOLUME, +				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE); +		snd_soc_update_bits(codec, CS42L56_LOB_VOLUME, +				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE); +	} +	return 0; +} + +static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream, +				     struct snd_pcm_hw_params *params, +				     struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); +	int ratio; + +	ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params)); +	if (ratio >= 0) { +		snd_soc_update_bits(codec, CS42L56_CLKCTL_2, +				    CS42L56_CLK_RATIO_MASK, ratio); +	} else { +		dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n"); +		return -EINVAL; +	} + +	return 0; +} + +static int cs42l56_set_bias_level(struct snd_soc_codec *codec, +					enum snd_soc_bias_level level) +{ +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); +	int ret; + +	switch (level) { +	case SND_SOC_BIAS_ON: +		break; +	case SND_SOC_BIAS_PREPARE: +		snd_soc_update_bits(codec, CS42L56_CLKCTL_1, +				    CS42L56_MCLK_DIS_MASK, 0); +		snd_soc_update_bits(codec, CS42L56_PWRCTL_1, +				    CS42L56_PDN_ALL_MASK, 0); +		break; +	case SND_SOC_BIAS_STANDBY: +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { +			regcache_cache_only(cs42l56->regmap, false); +			regcache_sync(cs42l56->regmap); +			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), +						    cs42l56->supplies); +			if (ret != 0) { +				dev_err(cs42l56->dev, +					"Failed to enable regulators: %d\n", +					ret); +				return ret; +			} +		} +		snd_soc_update_bits(codec, CS42L56_PWRCTL_1, +				    CS42L56_PDN_ALL_MASK, 1); +		break; +	case SND_SOC_BIAS_OFF: +		snd_soc_update_bits(codec, CS42L56_PWRCTL_1, +				    CS42L56_PDN_ALL_MASK, 1); +		snd_soc_update_bits(codec, CS42L56_CLKCTL_1, +				    CS42L56_MCLK_DIS_MASK, 1); +		regcache_cache_only(cs42l56->regmap, true); +		regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), +						    cs42l56->supplies); +		break; +	} +	codec->dapm.bias_level = level; + +	return 0; +} + +#define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000) + +#define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ +			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ +			SNDRV_PCM_FMTBIT_S32_LE) + + +static struct snd_soc_dai_ops cs42l56_ops = { +	.hw_params	= cs42l56_pcm_hw_params, +	.digital_mute	= cs42l56_digital_mute, +	.set_fmt	= cs42l56_set_dai_fmt, +	.set_sysclk	= cs42l56_set_sysclk, +}; + +static struct snd_soc_dai_driver cs42l56_dai = { +		.name = "cs42l56", +		.playback = { +			.stream_name = "HiFi Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = CS42L56_RATES, +			.formats = CS42L56_FORMATS, +		}, +		.capture = { +			.stream_name = "HiFi Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = CS42L56_RATES, +			.formats = CS42L56_FORMATS, +		}, +		.ops = &cs42l56_ops, +}; + +static int cs42l56_suspend(struct snd_soc_codec *codec) +{ +	cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); + +	return 0; +} + +static int cs42l56_resume(struct snd_soc_codec *codec) +{ +	cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + +	return 0; +} + +static int beep_freq[] = { +	261, 522, 585, 667, 706, 774, 889, 1000, +	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 +}; + +static void cs42l56_beep_work(struct work_struct *work) +{ +	struct cs42l56_private *cs42l56 = +		container_of(work, struct cs42l56_private, beep_work); +	struct snd_soc_codec *codec = cs42l56->codec; +	struct snd_soc_dapm_context *dapm = &codec->dapm; +	int i; +	int val = 0; +	int best = 0; + +	if (cs42l56->beep_rate) { +		for (i = 0; i < ARRAY_SIZE(beep_freq); i++) { +			if (abs(cs42l56->beep_rate - beep_freq[i]) < +			    abs(cs42l56->beep_rate - beep_freq[best])) +				best = i; +		} + +		dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n", +			beep_freq[best], cs42l56->beep_rate); + +		val = (best << CS42L56_BEEP_RATE_SHIFT); + +		snd_soc_dapm_enable_pin(dapm, "Beep"); +	} else { +		dev_dbg(codec->dev, "Disabling beep\n"); +		snd_soc_dapm_disable_pin(dapm, "Beep"); +	} + +	snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME, +			    CS42L56_BEEP_FREQ_MASK, val); + +	snd_soc_dapm_sync(dapm); +} + +/* For usability define a way of injecting beep events for the device - + * many systems will not have a keyboard. + */ +static int cs42l56_beep_event(struct input_dev *dev, unsigned int type, +			     unsigned int code, int hz) +{ +	struct snd_soc_codec *codec = input_get_drvdata(dev); +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + +	dev_dbg(codec->dev, "Beep event %x %x\n", code, hz); + +	switch (code) { +	case SND_BELL: +		if (hz) +			hz = 261; +	case SND_TONE: +		break; +	default: +		return -1; +	} + +	/* Kick the beep from a workqueue */ +	cs42l56->beep_rate = hz; +	schedule_work(&cs42l56->beep_work); +	return 0; +} + +static ssize_t cs42l56_beep_set(struct device *dev, +			       struct device_attribute *attr, +			       const char *buf, size_t count) +{ +	struct cs42l56_private *cs42l56 = dev_get_drvdata(dev); +	long int time; +	int ret; + +	ret = kstrtol(buf, 10, &time); +	if (ret != 0) +		return ret; + +	input_event(cs42l56->beep, EV_SND, SND_TONE, time); + +	return count; +} + +static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set); + +static void cs42l56_init_beep(struct snd_soc_codec *codec) +{ +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); +	int ret; + +	cs42l56->beep = devm_input_allocate_device(codec->dev); +	if (!cs42l56->beep) { +		dev_err(codec->dev, "Failed to allocate beep device\n"); +		return; +	} + +	INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work); +	cs42l56->beep_rate = 0; + +	cs42l56->beep->name = "CS42L56 Beep Generator"; +	cs42l56->beep->phys = dev_name(codec->dev); +	cs42l56->beep->id.bustype = BUS_I2C; + +	cs42l56->beep->evbit[0] = BIT_MASK(EV_SND); +	cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); +	cs42l56->beep->event = cs42l56_beep_event; +	cs42l56->beep->dev.parent = codec->dev; +	input_set_drvdata(cs42l56->beep, codec); + +	ret = input_register_device(cs42l56->beep); +	if (ret != 0) { +		cs42l56->beep = NULL; +		dev_err(codec->dev, "Failed to register beep device\n"); +	} + +	ret = device_create_file(codec->dev, &dev_attr_beep); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to create keyclick file: %d\n", +			ret); +	} +} + +static void cs42l56_free_beep(struct snd_soc_codec *codec) +{ +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + +	device_remove_file(codec->dev, &dev_attr_beep); +	cancel_work_sync(&cs42l56->beep_work); +	cs42l56->beep = NULL; + +	snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG, +			    CS42L56_BEEP_EN_MASK, 0); +} + +static int cs42l56_probe(struct snd_soc_codec *codec) +{ +	cs42l56_init_beep(codec); + +	cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + +	return 0; +} + +static int cs42l56_remove(struct snd_soc_codec *codec) +{ +	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + +	cs42l56_free_beep(codec); +	cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); +	regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); + +	return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { +	.probe = cs42l56_probe, +	.remove = cs42l56_remove, +	.suspend = cs42l56_suspend, +	.resume = cs42l56_resume, +	.set_bias_level = cs42l56_set_bias_level, + +	.dapm_widgets = cs42l56_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), +	.dapm_routes = cs42l56_audio_map, +	.num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map), + +	.controls = cs42l56_snd_controls, +	.num_controls = ARRAY_SIZE(cs42l56_snd_controls), +}; + +static struct regmap_config cs42l56_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = CS42L56_MAX_REGISTER, +	.reg_defaults = cs42l56_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults), +	.readable_reg = cs42l56_readable_register, +	.volatile_reg = cs42l56_volatile_register, +	.cache_type = REGCACHE_RBTREE, +}; + +static int cs42l56_handle_of_data(struct i2c_client *i2c_client, +				    struct cs42l56_platform_data *pdata) +{ +	struct device_node *np = i2c_client->dev.of_node; +	u32 val32; + +	if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg")) +		pdata->ain1a_ref_cfg = true; + +	if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg")) +		pdata->ain2a_ref_cfg = true; + +	if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg")) +		pdata->ain1b_ref_cfg = true; + +	if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg")) +		pdata->ain2b_ref_cfg = true; + +	if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0) +		pdata->micbias_lvl = val32; + +	if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0) +		pdata->chgfreq = val32; + +	if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0) +		pdata->adaptive_pwr = val32; + +	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0) +		pdata->hpfa_freq = val32; + +	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0) +		pdata->hpfb_freq = val32; + +	pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0); + +	return 0; +} + +static int cs42l56_i2c_probe(struct i2c_client *i2c_client, +			     const struct i2c_device_id *id) +{ +	struct cs42l56_private *cs42l56; +	struct cs42l56_platform_data *pdata = +		dev_get_platdata(&i2c_client->dev); +	int ret, i; +	unsigned int devid = 0; +	unsigned int alpha_rev, metal_rev; +	unsigned int reg; + +	cs42l56 = devm_kzalloc(&i2c_client->dev, +			       sizeof(struct cs42l56_private), +			       GFP_KERNEL); +	if (cs42l56 == NULL) +		return -ENOMEM; +	cs42l56->dev = &i2c_client->dev; + +	cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap); +	if (IS_ERR(cs42l56->regmap)) { +		ret = PTR_ERR(cs42l56->regmap); +		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); +		return ret; +	} + +	if (pdata) { +		cs42l56->pdata = *pdata; +	} else { +		pdata = devm_kzalloc(&i2c_client->dev, +				     sizeof(struct cs42l56_platform_data), +				     GFP_KERNEL); +		if (!pdata) { +			dev_err(&i2c_client->dev, +				"could not allocate pdata\n"); +			return -ENOMEM; +		} +		if (i2c_client->dev.of_node) { +			ret = cs42l56_handle_of_data(i2c_client, +						     &cs42l56->pdata); +			if (ret != 0) +				return ret; +		} +		cs42l56->pdata = *pdata; +	} + +	if (cs42l56->pdata.gpio_nreset) { +		ret = gpio_request_one(cs42l56->pdata.gpio_nreset, +				       GPIOF_OUT_INIT_HIGH, "CS42L56 /RST"); +		if (ret < 0) { +			dev_err(&i2c_client->dev, +				"Failed to request /RST %d: %d\n", +				cs42l56->pdata.gpio_nreset, ret); +			return ret; +		} +		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0); +		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1); +	} + + +	i2c_set_clientdata(i2c_client, cs42l56); + +	for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++) +		cs42l56->supplies[i].supply = cs42l56_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c_client->dev, +				      ARRAY_SIZE(cs42l56->supplies), +				      cs42l56->supplies); +	if (ret != 0) { +		dev_err(&i2c_client->dev, +			"Failed to request supplies: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), +				    cs42l56->supplies); +	if (ret != 0) { +		dev_err(&i2c_client->dev, +			"Failed to enable supplies: %d\n", ret); +		return ret; +	} + +	regcache_cache_bypass(cs42l56->regmap, true); + +	ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); +	devid = reg & CS42L56_CHIP_ID_MASK; +	if (devid != CS42L56_DEVID) { +		dev_err(&i2c_client->dev, +			"CS42L56 Device ID (%X). Expected %X\n", +			devid, CS42L56_DEVID); +		goto err_enable; +	} +	alpha_rev = reg & CS42L56_AREV_MASK; +	metal_rev = reg & CS42L56_MTLREV_MASK; + +	dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 "); +	dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n", +		 alpha_rev, metal_rev); + +	regcache_cache_bypass(cs42l56->regmap, false); + +	if (cs42l56->pdata.ain1a_ref_cfg) +		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, +				   CS42L56_AIN1A_REF_MASK, 1); + +	if (cs42l56->pdata.ain1b_ref_cfg) +		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, +				   CS42L56_AIN1B_REF_MASK, 1); + +	if (cs42l56->pdata.ain2a_ref_cfg) +		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, +				   CS42L56_AIN2A_REF_MASK, 1); + +	if (cs42l56->pdata.ain2b_ref_cfg) +		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, +				   CS42L56_AIN2B_REF_MASK, 1); + +	if (cs42l56->pdata.micbias_lvl) +		regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL, +				   CS42L56_MIC_BIAS_MASK, +				cs42l56->pdata.micbias_lvl); + +	if (cs42l56->pdata.chgfreq) +		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL, +				   CS42L56_CHRG_FREQ_MASK, +				cs42l56->pdata.chgfreq); + +	if (cs42l56->pdata.hpfb_freq) +		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL, +				   CS42L56_HPFB_FREQ_MASK, +				cs42l56->pdata.hpfb_freq); + +	if (cs42l56->pdata.hpfa_freq) +		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL, +				   CS42L56_HPFA_FREQ_MASK, +				cs42l56->pdata.hpfa_freq); + +	if (cs42l56->pdata.adaptive_pwr) +		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL, +				   CS42L56_ADAPT_PWR_MASK, +				cs42l56->pdata.adaptive_pwr); + +	ret =  snd_soc_register_codec(&i2c_client->dev, +			&soc_codec_dev_cs42l56, &cs42l56_dai, 1); +	if (ret < 0) +		return ret; + +	return 0; + +err_enable: +	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), +			       cs42l56->supplies); +	return ret; +} + +static int cs42l56_i2c_remove(struct i2c_client *client) +{ +	struct cs42l56_private *cs42l56 = i2c_get_clientdata(client); + +	snd_soc_unregister_codec(&client->dev); +	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), +			       cs42l56->supplies); +	return 0; +} + +static const struct of_device_id cs42l56_of_match[] = { +	{ .compatible = "cirrus,cs42l56", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, cs42l56_of_match); + + +static const struct i2c_device_id cs42l56_id[] = { +	{ "cs42l56", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, cs42l56_id); + +static struct i2c_driver cs42l56_i2c_driver = { +	.driver = { +		.name = "cs42l56", +		.owner = THIS_MODULE, +		.of_match_table = cs42l56_of_match, +	}, +	.id_table = cs42l56_id, +	.probe =    cs42l56_i2c_probe, +	.remove =   cs42l56_i2c_remove, +}; + +module_i2c_driver(cs42l56_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L56 driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l56.h b/sound/soc/codecs/cs42l56.h new file mode 100644 index 00000000000..5025ec9be9b --- /dev/null +++ b/sound/soc/codecs/cs42l56.h @@ -0,0 +1,177 @@ +/* + * cs42l52.h -- CS42L56 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin <brian.austin@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __CS42L56_H__ +#define __CS42L56_H__ + +#define CS42L56_CHIP_ID_1		0x01 +#define CS42L56_CHIP_ID_2		0x02 +#define CS42L56_PWRCTL_1		0x03 +#define CS42L56_PWRCTL_2		0x04 +#define CS42L56_CLKCTL_1		0x05 +#define CS42L56_CLKCTL_2		0x06 +#define CS42L56_SERIAL_FMT		0x07 +#define CS42L56_CLASSH_CTL		0x08 +#define CS42L56_MISC_CTL		0x09 +#define CS42L56_INT_STATUS		0x0a +#define CS42L56_PLAYBACK_CTL		0x0b +#define CS42L56_DSP_MUTE_CTL		0x0c +#define CS42L56_ADCA_MIX_VOLUME		0x0d +#define CS42L56_ADCB_MIX_VOLUME		0x0e +#define CS42L56_PCMA_MIX_VOLUME		0x0f +#define CS42L56_PCMB_MIX_VOLUME		0x10 +#define CS42L56_ANAINPUT_ADV_VOLUME	0x11 +#define CS42L56_DIGINPUT_ADV_VOLUME	0x12 +#define CS42L56_MASTER_A_VOLUME		0x13 +#define CS42L56_MASTER_B_VOLUME		0x14 +#define CS42L56_BEEP_FREQ_ONTIME	0x15 +#define CS42L56_BEEP_FREQ_OFFTIME	0x16 +#define CS42L56_BEEP_TONE_CFG		0x17 +#define CS42L56_TONE_CTL		0x18 +#define CS42L56_CHAN_MIX_SWAP		0x19 +#define CS42L56_AIN_REFCFG_ADC_MUX	0x1a +#define CS42L56_HPF_CTL			0x1b +#define CS42L56_MISC_ADC_CTL		0x1c +#define CS42L56_GAIN_BIAS_CTL		0x1d +#define CS42L56_PGAA_MUX_VOLUME		0x1e +#define CS42L56_PGAB_MUX_VOLUME		0x1f +#define CS42L56_ADCA_ATTENUATOR		0x20 +#define CS42L56_ADCB_ATTENUATOR		0x21 +#define CS42L56_ALC_EN_ATTACK_RATE	0x22 +#define CS42L56_ALC_RELEASE_RATE	0x23 +#define CS42L56_ALC_THRESHOLD		0x24 +#define CS42L56_NOISE_GATE_CTL		0x25 +#define CS42L56_ALC_LIM_SFT_ZC		0x26 +#define CS42L56_AMUTE_HPLO_MUX		0x27 +#define CS42L56_HPA_VOLUME		0x28 +#define CS42L56_HPB_VOLUME		0x29 +#define CS42L56_LOA_VOLUME		0x2a +#define CS42L56_LOB_VOLUME		0x2b +#define CS42L56_LIM_THRESHOLD_CTL	0x2c +#define CS42L56_LIM_CTL_RELEASE_RATE	0x2d +#define CS42L56_LIM_ATTACK_RATE		0x2e + +/* Device ID and Rev ID Masks */ +#define CS42L56_DEVID			0x56 +#define CS42L56_CHIP_ID_MASK		0xff +#define CS42L56_AREV_MASK		0x1c +#define CS42L56_MTLREV_MASK		0x03 + +/* Power bit masks */ +#define CS42L56_PDN_ALL_MASK		0x01 +#define CS42L56_PDN_ADCA_MASK		0x02 +#define CS42L56_PDN_ADCB_MASK		0x04 +#define CS42L56_PDN_CHRG_MASK		0x08 +#define CS42L56_PDN_BIAS_MASK		0x10 +#define CS42L56_PDN_VBUF_MASK		0x20 +#define CS42L56_PDN_LOA_MASK		0x03 +#define CS42L56_PDN_LOB_MASK		0x0c +#define CS42L56_PDN_HPA_MASK		0x30 +#define CS42L56_PDN_HPB_MASK		0xc0 + +/* serial port and clk masks */ +#define CS42L56_MASTER_MODE		0x40 +#define CS42L56_SLAVE_MODE		0 +#define CS42L56_MS_MODE_MASK		0x40 +#define CS42L56_SCLK_INV		0x20 +#define CS42L56_SCLK_INV_MASK		0x20 +#define CS42L56_SCLK_MCLK_MASK		0x18 +#define CS42L56_MCLK_PREDIV		0x04 +#define CS42L56_MCLK_PREDIV_MASK	0x04 +#define CS42L56_MCLK_DIV2		0x02 +#define CS42L56_MCLK_DIV2_MASK		0x02 +#define CS42L56_MCLK_DIS_MASK		0x01 +#define CS42L56_CLK_AUTO_MASK		0x20 +#define CS42L56_CLK_RATIO_MASK		0x1f +#define CS42L56_DIG_FMT_I2S		0 +#define CS42L56_DIG_FMT_LEFT_J		0x08 +#define CS42L56_DIG_FMT_MASK		0x08 + +/* Class H and misc ctl masks */ +#define CS42L56_ADAPT_PWR_MASK		0xc0 +#define CS42L56_CHRG_FREQ_MASK		0x0f +#define CS42L56_DIG_MUX_MASK		0x80 +#define CS42L56_ANLGSFT_MASK		0x10 +#define CS42L56_ANLGZC_MASK		0x08 +#define CS42L56_DIGSFT_MASK		0x04 +#define CS42L56_FREEZE_MASK		0x01 +#define CS42L56_MIC_BIAS_MASK		0x03 +#define CS42L56_HPFA_FREQ_MASK		0x03 +#define CS42L56_HPFB_FREQ_MASK		0xc0 +#define CS42L56_AIN1A_REF_MASK		0x10 +#define CS42L56_AIN2A_REF_MASK		0x40 +#define CS42L56_AIN1B_REF_MASK		0x20 +#define CS42L56_AIN2B_REF_MASK		0x80 + +/* Playback Capture ctl masks */ +#define CS42L56_PDN_DSP_MASK		0x80 +#define CS42L56_DEEMPH_MASK		0x40 +#define CS42L56_PLYBCK_GANG_MASK	0x10 +#define CS42L56_PCM_INV_MASK		0x0c +#define CS42L56_MUTE_ALL		0xff +#define CS42L56_UNMUTE			0 +#define CS42L56_ADCAMIX_MUTE_MASK	0x40 +#define CS42L56_ADCBMIX_MUTE_MASK	0x80 +#define CS42L56_PCMAMIX_MUTE_MASK	0x10 +#define CS42L56_PCMBMIX_MUTE_MASK	0x20 +#define CS42L56_MSTB_MUTE_MASK		0x02 +#define CS42L56_MSTA_MUTE_MASK		0x01 +#define CS42L56_ADCA_MUTE_MASK		0x01 +#define CS42L56_ADCB_MUTE_MASK		0x02 +#define CS42L56_HP_MUTE_MASK		0x80 +#define CS42L56_LO_MUTE_MASK		0x80 + +/* Beep masks */ +#define CS42L56_BEEP_FREQ_MASK		0xf0 +#define CS42L56_BEEP_ONTIME_MASK	0x0f +#define CS42L56_BEEP_OFFTIME_MASK	0xe0 +#define CS42L56_BEEP_CFG_MASK		0xc0 +#define CS42L56_BEEP_TREBCF_MASK	0x18 +#define CS42L56_BEEP_BASSCF_MASK	0x06 +#define CS42L56_BEEP_TCEN_MASK		0x01 +#define CS42L56_BEEP_RATE_SHIFT		4 +#define CS42L56_BEEP_EN_MASK		0x3f + + +/* Supported MCLKS */ +#define CS42L56_MCLK_5P6448MHZ		5644800 +#define CS42L56_MCLK_6MHZ		6000000 +#define CS42L56_MCLK_6P144MHZ		6144000 +#define CS42L56_MCLK_11P2896MHZ		11289600 +#define CS42L56_MCLK_12MHZ		12000000 +#define CS42L56_MCLK_12P288MHZ		12288000 +#define CS42L56_MCLK_22P5792MHZ		22579200 +#define CS42L56_MCLK_24MHZ		24000000 +#define CS42L56_MCLK_24P576MHZ		24576000 + +/* Clock ratios */ +#define CS42L56_MCLK_LRCLK_128		0x08 +#define CS42L56_MCLK_LRCLK_125		0x09 +#define CS42L56_MCLK_LRCLK_136		0x0b +#define CS42L56_MCLK_LRCLK_192		0x0c +#define CS42L56_MCLK_LRCLK_187P5	0x0d +#define CS42L56_MCLK_LRCLK_256		0x10 +#define CS42L56_MCLK_LRCLK_250		0x11 +#define CS42L56_MCLK_LRCLK_272		0x13 +#define CS42L56_MCLK_LRCLK_384		0x14 +#define CS42L56_MCLK_LRCLK_375		0x15 +#define CS42L56_MCLK_LRCLK_512		0x18 +#define CS42L56_MCLK_LRCLK_500		0x19 +#define CS42L56_MCLK_LRCLK_544		0x1b +#define CS42L56_MCLK_LRCLK_750		0x1c +#define CS42L56_MCLK_LRCLK_768		0x1d + + +#define CS42L56_MAX_REGISTER		0x34 + +#endif diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 3b20c86cdb0..ae3717992d5 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -17,6 +17,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/delay.h> +#include <linux/of_gpio.h>  #include <linux/pm.h>  #include <linux/i2c.h>  #include <linux/regmap.h> @@ -28,6 +29,7 @@  #include <sound/soc-dapm.h>  #include <sound/initval.h>  #include <sound/tlv.h> +#include <sound/cs42l73.h>  #include "cs42l73.h"  struct sp_config { @@ -35,6 +37,7 @@ struct sp_config {  	u32 srate;  };  struct  cs42l73_private { +	struct cs42l73_platform_data pdata;  	struct sp_config config[3];  	struct regmap *regmap;  	u32 sysclk; @@ -275,13 +278,13 @@ static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);  static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" };  static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" }; -static const struct soc_enum pgaa_enum = -	SOC_ENUM_SINGLE(CS42L73_ADCIPC, 3, -		ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text); +static SOC_ENUM_SINGLE_DECL(pgaa_enum, +			    CS42L73_ADCIPC, 3, +			    cs42l73_pgaa_text); -static const struct soc_enum pgab_enum = -	SOC_ENUM_SINGLE(CS42L73_ADCIPC, 7, -		ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text); +static SOC_ENUM_SINGLE_DECL(pgab_enum, +			    CS42L73_ADCIPC, 7, +			    cs42l73_pgab_text);  static const struct snd_kcontrol_new pgaa_mux =  	SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum); @@ -306,18 +309,9 @@ static const struct snd_kcontrol_new input_right_mixer[] = {  static const char * const cs42l73_ng_delay_text[] = {  	"50ms", "100ms", "150ms", "200ms" }; -static const struct soc_enum ng_delay_enum = -	SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, -		ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); - -static const char * const charge_pump_freq_text[] = { -	"0", "1", "2", "3", "4", -	"5", "6", "7", "8", "9", -	"10", "11", "12", "13", "14", "15" }; - -static const struct soc_enum charge_pump_enum = -	SOC_ENUM_SINGLE(CS42L73_CPFCHC, 4, -		ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text); +static SOC_ENUM_SINGLE_DECL(ng_delay_enum, +			    CS42L73_NGCAB, 0, +			    cs42l73_ng_delay_text);  static const char * const cs42l73_mono_mix_texts[] = {  	"Left", "Right", "Mono Mix"}; @@ -325,7 +319,7 @@ static const char * const cs42l73_mono_mix_texts[] = {  static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };  static const struct soc_enum spk_asp_enum = -	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 1, +	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 3,  			      ARRAY_SIZE(cs42l73_mono_mix_texts),  			      cs42l73_mono_mix_texts,  			      cs42l73_mono_mix_values); @@ -343,7 +337,7 @@ static const struct snd_kcontrol_new spk_xsp_mixer =  	SOC_DAPM_ENUM("Route", spk_xsp_enum);  static const struct soc_enum esl_asp_enum = -	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 5, +	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 3,  			      ARRAY_SIZE(cs42l73_mono_mix_texts),  			      cs42l73_mono_mix_texts,  			      cs42l73_mono_mix_values); @@ -352,7 +346,7 @@ static const struct snd_kcontrol_new esl_asp_mixer =  	SOC_DAPM_ENUM("Route", esl_asp_enum);  static const struct soc_enum esl_xsp_enum = -	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 7, +	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 3,  			      ARRAY_SIZE(cs42l73_mono_mix_texts),  			      cs42l73_mono_mix_texts,  			      cs42l73_mono_mix_values); @@ -363,19 +357,19 @@ static const struct snd_kcontrol_new esl_xsp_mixer =  static const char * const cs42l73_ip_swap_text[] = {  	"Stereo", "Mono A", "Mono B", "Swap A-B"}; -static const struct soc_enum ip_swap_enum = -	SOC_ENUM_SINGLE(CS42L73_MIOPC, 6, -		ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text); +static SOC_ENUM_SINGLE_DECL(ip_swap_enum, +			    CS42L73_MIOPC, 6, +			    cs42l73_ip_swap_text);  static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"}; -static const struct soc_enum vsp_output_mux_enum = -	SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 5, -		ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); +static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum, +			    CS42L73_MIXERCTL, 5, +			    cs42l73_spo_mixer_text); -static const struct soc_enum xsp_output_mux_enum = -	SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 4, -		ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); +static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum, +			    CS42L73_MIXERCTL, 4, +			    cs42l73_spo_mixer_text);  static const struct snd_kcontrol_new vsp_output_mux =  	SOC_DAPM_ENUM("Route", vsp_output_mux_enum); @@ -511,8 +505,6 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {  	SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0),  	SOC_ENUM("NG Delay", ng_delay_enum), -	SOC_ENUM("Charge Pump Frequency", charge_pump_enum), -  	SOC_DOUBLE_R_TLV("XSP-IP Volume",  			CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1,  			attn_tlv), @@ -1055,11 +1047,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {  	case SND_SOC_DAIFMT_CBM_CFM: -		mmcc |= MS_MASTER; +		mmcc |= CS42L73_MS_MASTER;  		break;  	case SND_SOC_DAIFMT_CBS_CFS: -		mmcc &= ~MS_MASTER; +		mmcc &= ~CS42L73_MS_MASTER;  		break;  	default: @@ -1071,11 +1063,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)  	switch (format) {  	case SND_SOC_DAIFMT_I2S: -		spc &= ~SPDIF_PCM; +		spc &= ~CS42L73_SPDIF_PCM;  		break;  	case SND_SOC_DAIFMT_DSP_A:  	case SND_SOC_DAIFMT_DSP_B: -		if (mmcc & MS_MASTER) { +		if (mmcc & CS42L73_MS_MASTER) {  			dev_err(codec->dev,  				"PCM format in slave mode only\n");  			return -EINVAL; @@ -1085,25 +1077,25 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)  				"PCM format is not supported on ASP port\n");  			return -EINVAL;  		} -		spc |= SPDIF_PCM; +		spc |= CS42L73_SPDIF_PCM;  		break;  	default:  		return -EINVAL;  	} -	if (spc & SPDIF_PCM) { +	if (spc & CS42L73_SPDIF_PCM) {  		/* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */ -		spc &= ~(PCM_MODE_MASK | PCM_BIT_ORDER); +		spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER);  		switch (format) {  		case SND_SOC_DAIFMT_DSP_B:  			if (inv == SND_SOC_DAIFMT_IB_IF) -				spc |= PCM_MODE0; +				spc |= CS42L73_PCM_MODE0;  			if (inv == SND_SOC_DAIFMT_IB_NF) -				spc |= PCM_MODE1; +				spc |= CS42L73_PCM_MODE1;  		break;  		case SND_SOC_DAIFMT_DSP_A:  			if (inv == SND_SOC_DAIFMT_IB_IF) -				spc |= PCM_MODE1; +				spc |= CS42L73_PCM_MODE1;  			break;  		default:  			return -EINVAL; @@ -1116,7 +1108,7 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)  	return 0;  } -static u32 cs42l73_asrc_rates[] = { +static const unsigned int cs42l73_asrc_rates[] = {  	8000, 11025, 12000, 16000, 22050,  	24000, 32000, 44100, 48000  }; @@ -1163,7 +1155,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,  	int mclk_coeff;  	int srate = params_rate(params); -	if (priv->config[id].mmcc & MS_MASTER) { +	if (priv->config[id].mmcc & CS42L73_MS_MASTER) {  		/* CS42L73 Master */  		/* MCLK -> srate */  		mclk_coeff = @@ -1182,13 +1174,13 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,  		priv->config[id].spc &= 0xFC;  		/* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */  		if (priv->mclk >= 6400000) -			priv->config[id].spc |= MCK_SCLK_64FS; +			priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;  		else -			priv->config[id].spc |= MCK_SCLK_MCLK; +			priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK;  	} else {  		/* CS42L73 Slave */  		priv->config[id].spc &= 0xFC; -		priv->config[id].spc |= MCK_SCLK_64FS; +		priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;  	}  	/* Update ASRCs */  	priv->config[id].srate = srate; @@ -1208,8 +1200,8 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,  	switch (level) {  	case SND_SOC_BIAS_ON: -		snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 0); -		snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 0); +		snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 0); +		snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 0);  		break;  	case SND_SOC_BIAS_PREPARE: @@ -1220,11 +1212,11 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,  			regcache_cache_only(cs42l73->regmap, false);  			regcache_sync(cs42l73->regmap);  		} -		snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); +		snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);  		break;  	case SND_SOC_BIAS_OFF: -		snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); +		snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);  		if (cs42l73->shutdwn_delay > 0) {  			mdelay(cs42l73->shutdwn_delay);  			cs42l73->shutdwn_delay = 0; @@ -1233,7 +1225,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,  				     * down.  				     */  		} -		snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1); +		snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);  		break;  	}  	codec->dapm.bias_level = level; @@ -1249,7 +1241,7 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)  					0x7F, tristate << 7);  } -static struct snd_pcm_hw_constraint_list constraints_12_24 = { +static const struct snd_pcm_hw_constraint_list constraints_12_24 = {  	.count  = ARRAY_SIZE(cs42l73_asrc_rates),  	.list   = cs42l73_asrc_rates,  }; @@ -1263,9 +1255,6 @@ static int cs42l73_pcm_startup(struct snd_pcm_substream *substream,  	return 0;  } -/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */ -#define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) -  #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\  	SNDRV_PCM_FMTBIT_S24_LE) @@ -1286,14 +1275,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {  			.stream_name = "XSP Playback",  			.channels_min = 1,  			.channels_max = 2, -			.rates = CS42L73_RATES, +			.rates = SNDRV_PCM_RATE_KNOT,  			.formats = CS42L73_FORMATS,  		},  		.capture = {  			.stream_name = "XSP Capture",  			.channels_min = 1,  			.channels_max = 2, -			.rates = CS42L73_RATES, +			.rates = SNDRV_PCM_RATE_KNOT,  			.formats = CS42L73_FORMATS,  		},  		.ops = &cs42l73_ops, @@ -1306,14 +1295,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {  			.stream_name = "ASP Playback",  			.channels_min = 2,  			.channels_max = 2, -			.rates = CS42L73_RATES, +			.rates = SNDRV_PCM_RATE_KNOT,  			.formats = CS42L73_FORMATS,  		},  		.capture = {  			.stream_name = "ASP Capture",  			.channels_min = 2,  			.channels_max = 2, -			.rates = CS42L73_RATES, +			.rates = SNDRV_PCM_RATE_KNOT,  			.formats = CS42L73_FORMATS,  		},  		.ops = &cs42l73_ops, @@ -1326,14 +1315,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {  			.stream_name = "VSP Playback",  			.channels_min = 1,  			.channels_max = 2, -			.rates = CS42L73_RATES, +			.rates = SNDRV_PCM_RATE_KNOT,  			.formats = CS42L73_FORMATS,  		},  		.capture = {  			.stream_name = "VSP Capture",  			.channels_min = 1,  			.channels_max = 2, -			.rates = CS42L73_RATES, +			.rates = SNDRV_PCM_RATE_KNOT,  			.formats = CS42L73_FORMATS,  		},  		.ops = &cs42l73_ops, @@ -1356,25 +1345,21 @@ static int cs42l73_resume(struct snd_soc_codec *codec)  static int cs42l73_probe(struct snd_soc_codec *codec)  { -	int ret;  	struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec); -	codec->control_data = cs42l73->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	regcache_cache_only(cs42l73->regmap, true); -  	cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	cs42l73->mclksel = CS42L73_CLKID_MCLK1;	/* MCLK1 as master clk */ +	/* Set Charge Pump Frequency */ +	if (cs42l73->pdata.chgfreq) +		snd_soc_update_bits(codec, CS42L73_CPFCHC, +				    CS42L73_CHARGEPUMP_MASK, +					cs42l73->pdata.chgfreq << 4); + +	/* MCLK1 as master clk */ +	cs42l73->mclksel = CS42L73_CLKID_MCLK1;  	cs42l73->mclk = 0; -	return ret; +	return 0;  }  static int cs42l73_remove(struct snd_soc_codec *codec) @@ -1415,9 +1400,11 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,  			     const struct i2c_device_id *id)  {  	struct cs42l73_private *cs42l73; +	struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev);  	int ret;  	unsigned int devid = 0;  	unsigned int reg; +	u32 val32;  	cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private),  			       GFP_KERNEL); @@ -1426,14 +1413,51 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,  		return -ENOMEM;  	} -	i2c_set_clientdata(i2c_client, cs42l73); -  	cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);  	if (IS_ERR(cs42l73->regmap)) {  		ret = PTR_ERR(cs42l73->regmap);  		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);  		return ret;  	} + +	if (pdata) { +		cs42l73->pdata = *pdata; +	} else { +		pdata = devm_kzalloc(&i2c_client->dev, +				     sizeof(struct cs42l73_platform_data), +				GFP_KERNEL); +		if (!pdata) { +			dev_err(&i2c_client->dev, "could not allocate pdata\n"); +			return -ENOMEM; +		} +		if (i2c_client->dev.of_node) { +			if (of_property_read_u32(i2c_client->dev.of_node, +				"chgfreq", &val32) >= 0) +				pdata->chgfreq = val32; +		} +		pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node, +						"reset-gpio", 0); +		cs42l73->pdata = *pdata; +	} + +	i2c_set_clientdata(i2c_client, cs42l73); + +	if (cs42l73->pdata.reset_gpio) { +		ret = devm_gpio_request_one(&i2c_client->dev, +					    cs42l73->pdata.reset_gpio, +					    GPIOF_OUT_INIT_HIGH, +					    "CS42L73 /RST"); +		if (ret < 0) { +			dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", +				cs42l73->pdata.reset_gpio, ret); +			return ret; +		} +		gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0); +		gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1); +	} + +	regcache_cache_bypass(cs42l73->regmap, true); +  	/* initialize codec */  	ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®);  	devid = (reg & 0xFF) << 12; @@ -1444,7 +1468,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,  	ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, ®);  	devid |= (reg & 0xF0) >> 4; -  	if (devid != CS42L73_DEVID) {  		ret = -ENODEV;  		dev_err(&i2c_client->dev, @@ -1462,7 +1485,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,  	dev_info(&i2c_client->dev,  		 "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); -	regcache_cache_only(cs42l73->regmap, true); +	regcache_cache_bypass(cs42l73->regmap, false);  	ret =  snd_soc_register_codec(&i2c_client->dev,  			&soc_codec_dev_cs42l73, cs42l73_dai, @@ -1478,6 +1501,12 @@ static int cs42l73_i2c_remove(struct i2c_client *client)  	return 0;  } +static const struct of_device_id cs42l73_of_match[] = { +	{ .compatible = "cirrus,cs42l73", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, cs42l73_of_match); +  static const struct i2c_device_id cs42l73_id[] = {  	{"cs42l73", 0},  	{} @@ -1489,6 +1518,7 @@ static struct i2c_driver cs42l73_i2c_driver = {  	.driver = {  		   .name = "cs42l73",  		   .owner = THIS_MODULE, +		   .of_match_table = cs42l73_of_match,  		   },  	.id_table = cs42l73_id,  	.probe = cs42l73_i2c_probe, diff --git a/sound/soc/codecs/cs42l73.h b/sound/soc/codecs/cs42l73.h index f30a4c4d62e..45746186a67 100644 --- a/sound/soc/codecs/cs42l73.h +++ b/sound/soc/codecs/cs42l73.h @@ -128,59 +128,60 @@  /* Bitfield Definitions */  /* CS42L73_PWRCTL1 */ -#define PDN_ADCB		(1 << 7) -#define PDN_DMICB		(1 << 6) -#define PDN_ADCA		(1 << 5) -#define PDN_DMICA		(1 << 4) -#define PDN_LDO			(1 << 2) -#define DISCHG_FILT		(1 << 1) -#define PDN			(1 << 0) +#define CS42L73_PDN_ADCB		(1 << 7) +#define CS42L73_PDN_DMICB		(1 << 6) +#define CS42L73_PDN_ADCA		(1 << 5) +#define CS42L73_PDN_DMICA		(1 << 4) +#define CS42L73_PDN_LDO			(1 << 2) +#define CS42L73_DISCHG_FILT		(1 << 1) +#define CS42L73_PDN			(1 << 0)  /* CS42L73_PWRCTL2 */ -#define PDN_MIC2_BIAS		(1 << 7) -#define PDN_MIC1_BIAS		(1 << 6) -#define PDN_VSP			(1 << 4) -#define PDN_ASP_SDOUT		(1 << 3) -#define PDN_ASP_SDIN		(1 << 2) -#define PDN_XSP_SDOUT		(1 << 1) -#define PDN_XSP_SDIN		(1 << 0) +#define CS42L73_PDN_MIC2_BIAS		(1 << 7) +#define CS42L73_PDN_MIC1_BIAS		(1 << 6) +#define CS42L73_PDN_VSP			(1 << 4) +#define CS42L73_PDN_ASP_SDOUT		(1 << 3) +#define CS42L73_PDN_ASP_SDIN		(1 << 2) +#define CS42L73_PDN_XSP_SDOUT		(1 << 1) +#define CS42L73_PDN_XSP_SDIN		(1 << 0)  /* CS42L73_PWRCTL3 */ -#define PDN_THMS		(1 << 5) -#define PDN_SPKLO		(1 << 4) -#define PDN_EAR			(1 << 3) -#define PDN_SPK			(1 << 2) -#define PDN_LO			(1 << 1) -#define PDN_HP			(1 << 0) +#define CS42L73_PDN_THMS		(1 << 5) +#define CS42L73_PDN_SPKLO		(1 << 4) +#define CS42L73_PDN_EAR			(1 << 3) +#define CS42L73_PDN_SPK			(1 << 2) +#define CS42L73_PDN_LO			(1 << 1) +#define CS42L73_PDN_HP			(1 << 0)  /* Thermal Overload Detect. Requires interrupt ... */ -#define THMOVLD_150C		0 -#define THMOVLD_132C		1 -#define THMOVLD_115C		2 -#define THMOVLD_098C		3 +#define CS42L73_THMOVLD_150C		0 +#define CS42L73_THMOVLD_132C		1 +#define CS42L73_THMOVLD_115C		2 +#define CS42L73_THMOVLD_098C		3 +#define CS42L73_CHARGEPUMP_MASK	(0xF0)  /* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */ -#define	SP_3ST			(1 << 7) -#define SPDIF_I2S		(0 << 6) -#define SPDIF_PCM		(1 << 6) -#define PCM_MODE0		(0 << 4) -#define PCM_MODE1		(1 << 4) -#define PCM_MODE2		(2 << 4) -#define PCM_MODE_MASK		(3 << 4) -#define PCM_BIT_ORDER		(1 << 3) -#define MCK_SCLK_64FS		(0 << 0) -#define MCK_SCLK_MCLK		(2 << 0) -#define MCK_SCLK_PREMCLK	(3 << 0) +#define	CS42L73_SP_3ST			(1 << 7) +#define CS42L73_SPDIF_I2S		(0 << 6) +#define CS42L73_SPDIF_PCM		(1 << 6) +#define CS42L73_PCM_MODE0		(0 << 4) +#define CS42L73_PCM_MODE1		(1 << 4) +#define CS42L73_PCM_MODE2		(2 << 4) +#define CS42L73_PCM_MODE_MASK		(3 << 4) +#define CS42L73_PCM_BIT_ORDER		(1 << 3) +#define CS42L73_MCK_SCLK_64FS		(0 << 0) +#define CS42L73_MCK_SCLK_MCLK		(2 << 0) +#define CS42L73_MCK_SCLK_PREMCLK	(3 << 0)  /* CS42L73_xSPMMCC */ -#define MS_MASTER		(1 << 7) +#define CS42L73_MS_MASTER		(1 << 7)  /* CS42L73_DMMCC */ -#define MCLKDIS			(1 << 0) -#define MCLKSEL_MCLK2		(1 << 4) -#define MCLKSEL_MCLK1		(0 << 4) +#define CS42L73_MCLKDIS			(1 << 0) +#define CS42L73_MCLKSEL_MCLK2		(1 << 4) +#define CS42L73_MCLKSEL_MCLK1		(0 << 4)  /* CS42L73 MCLK derived from MCLK1 or MCLK2 */  #define CS42L73_CLKID_MCLK1     0 @@ -194,28 +195,26 @@  #define CS42L73_VSP		2  /* IS1, IM1 */ -#define MIC2_SDET		(1 << 6) -#define THMOVLD			(1 << 4) -#define DIGMIXOVFL		(1 << 3) -#define IPBOVFL			(1 << 1) -#define IPAOVFL			(1 << 0) +#define CS42L73_MIC2_SDET		(1 << 6) +#define CS42L73_THMOVLD			(1 << 4) +#define CS42L73_DIGMIXOVFL		(1 << 3) +#define CS42L73_IPBOVFL			(1 << 1) +#define CS42L73_IPAOVFL			(1 << 0)  /* Analog Softramp */ -#define ANLGOSFT		(1 << 0) +#define CS42L73_ANLGOSFT		(1 << 0)  /* HP A/B Analog Mute */ -#define HPA_MUTE		(1 << 7) +#define CS42L73_HPA_MUTE		(1 << 7)  /* LO A/B Analog Mute	*/ -#define LOA_MUTE		(1 << 7) +#define CS42L73_LOA_MUTE		(1 << 7)  /* Digital Mute */ -#define HLAD_MUTE		(1 << 0) -#define HLBD_MUTE		(1 << 1) -#define SPKD_MUTE		(1 << 2) -#define ESLD_MUTE		(1 << 3) +#define CS42L73_HLAD_MUTE		(1 << 0) +#define CS42L73_HLBD_MUTE		(1 << 1) +#define CS42L73_SPKD_MUTE		(1 << 2) +#define CS42L73_ESLD_MUTE		(1 << 3)  /* Misc defines for codec */ -#define CS42L73_RESET_GPIO 143 -  #define CS42L73_DEVID		0x00042A73  #define CS42L73_MCLKX_MIN	5644800  #define CS42L73_MCLKX_MAX	38400000 diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c new file mode 100644 index 00000000000..657dce27ead --- /dev/null +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -0,0 +1,64 @@ +/* + * Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen <Guangyu.Chen@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> + +#include "cs42xx8.h" + +static int cs42xx8_i2c_probe(struct i2c_client *i2c, +			     const struct i2c_device_id *id) +{ +	u32 ret = cs42xx8_probe(&i2c->dev, +			devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config)); +	if (ret) +		return ret; + +	pm_runtime_enable(&i2c->dev); +	pm_request_idle(&i2c->dev); + +	return 0; +} + +static int cs42xx8_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); +	pm_runtime_disable(&i2c->dev); + +	return 0; +} + +static struct i2c_device_id cs42xx8_i2c_id[] = { +	{"cs42448", (kernel_ulong_t)&cs42448_data}, +	{"cs42888", (kernel_ulong_t)&cs42888_data}, +	{} +}; +MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id); + +static struct i2c_driver cs42xx8_i2c_driver = { +	.driver = { +		.name = "cs42xx8", +		.owner = THIS_MODULE, +		.pm = &cs42xx8_pm, +	}, +	.probe = cs42xx8_i2c_probe, +	.remove = cs42xx8_i2c_remove, +	.id_table = cs42xx8_i2c_id, +}; + +module_i2c_driver(cs42xx8_i2c_driver); + +MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c new file mode 100644 index 00000000000..a25bc6061a3 --- /dev/null +++ b/sound/soc/codecs/cs42xx8.c @@ -0,0 +1,600 @@ +/* + * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen <Guangyu.Chen@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "cs42xx8.h" + +#define CS42XX8_NUM_SUPPLIES 4 +static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = { +	"VA", +	"VD", +	"VLS", +	"VLC", +}; + +#define CS42XX8_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \ +			 SNDRV_PCM_FMTBIT_S20_3LE | \ +			 SNDRV_PCM_FMTBIT_S24_LE | \ +			 SNDRV_PCM_FMTBIT_S32_LE) + +/* codec private data */ +struct cs42xx8_priv { +	struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES]; +	const struct cs42xx8_driver_data *drvdata; +	struct regmap *regmap; +	struct clk *clk; + +	bool slave_mode; +	unsigned long sysclk; +}; + +/* -127.5dB to 0dB with step of 0.5dB */ +static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); +/* -64dB to 24dB with step of 0.5dB */ +static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0); + +static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" }; +static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross", +					"Soft Ramp", "Soft Ramp on Zero Cross" }; + +static const struct soc_enum adc1_single_enum = +	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single); +static const struct soc_enum adc2_single_enum = +	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single); +static const struct soc_enum adc3_single_enum = +	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single); +static const struct soc_enum dac_szc_enum = +	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc); +static const struct soc_enum adc_szc_enum = +	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc); + +static const struct snd_kcontrol_new cs42xx8_snd_controls[] = { +	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1, +			 CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv), +	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3, +			 CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv), +	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5, +			 CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv), +	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7, +			 CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv), +	SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1, +			   CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv), +	SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3, +			   CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv), +	SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0), +	SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0), +	SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0), +	SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0), +	SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0), +	SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0), +	SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1), +	SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0), +	SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum), +	SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum), +	SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0), +	SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum), +	SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0), +	SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0), +	SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0), +	SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum), +}; + +static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = { +	SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5, +			   CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv), +	SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0), +	SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum), +}; + +static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = { +	SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1), +	SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1), +	SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1), +	SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1), + +	SND_SOC_DAPM_OUTPUT("AOUT1L"), +	SND_SOC_DAPM_OUTPUT("AOUT1R"), +	SND_SOC_DAPM_OUTPUT("AOUT2L"), +	SND_SOC_DAPM_OUTPUT("AOUT2R"), +	SND_SOC_DAPM_OUTPUT("AOUT3L"), +	SND_SOC_DAPM_OUTPUT("AOUT3R"), +	SND_SOC_DAPM_OUTPUT("AOUT4L"), +	SND_SOC_DAPM_OUTPUT("AOUT4R"), + +	SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1), +	SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1), + +	SND_SOC_DAPM_INPUT("AIN1L"), +	SND_SOC_DAPM_INPUT("AIN1R"), +	SND_SOC_DAPM_INPUT("AIN2L"), +	SND_SOC_DAPM_INPUT("AIN2R"), + +	SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0), +}; + +static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = { +	SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1), + +	SND_SOC_DAPM_INPUT("AIN3L"), +	SND_SOC_DAPM_INPUT("AIN3R"), +}; + +static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = { +	/* Playback */ +	{ "AOUT1L", NULL, "DAC1" }, +	{ "AOUT1R", NULL, "DAC1" }, +	{ "DAC1", NULL, "PWR" }, + +	{ "AOUT2L", NULL, "DAC2" }, +	{ "AOUT2R", NULL, "DAC2" }, +	{ "DAC2", NULL, "PWR" }, + +	{ "AOUT3L", NULL, "DAC3" }, +	{ "AOUT3R", NULL, "DAC3" }, +	{ "DAC3", NULL, "PWR" }, + +	{ "AOUT4L", NULL, "DAC4" }, +	{ "AOUT4R", NULL, "DAC4" }, +	{ "DAC4", NULL, "PWR" }, + +	/* Capture */ +	{ "ADC1", NULL, "AIN1L" }, +	{ "ADC1", NULL, "AIN1R" }, +	{ "ADC1", NULL, "PWR" }, + +	{ "ADC2", NULL, "AIN2L" }, +	{ "ADC2", NULL, "AIN2R" }, +	{ "ADC2", NULL, "PWR" }, +}; + +static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = { +	/* Capture */ +	{ "ADC3", NULL, "AIN3L" }, +	{ "ADC3", NULL, "AIN3R" }, +	{ "ADC3", NULL, "PWR" }, +}; + +struct cs42xx8_ratios { +	unsigned int ratio; +	unsigned char speed; +	unsigned char mclk; +}; + +static const struct cs42xx8_ratios cs42xx8_ratios[] = { +	{ 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) }, +	{ 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) }, +	{ 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) }, +	{ 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) }, +	{ 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) }, +	{ 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) }, +	{ 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) }, +	{ 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) }, +	{ 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) } +}; + +static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, +				  int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + +	cs42xx8->sysclk = freq; + +	return 0; +} + +static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai, +			       unsigned int format) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); +	u32 val; + +	/* Set DAI format */ +	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_LEFT_J: +		val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ; +		break; +	case SND_SOC_DAIFMT_I2S: +		val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S; +		break; +	case SND_SOC_DAIFMT_RIGHT_J: +		val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ; +		break; +	default: +		dev_err(codec->dev, "unsupported dai format\n"); +		return -EINVAL; +	} + +	regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF, +			   CS42XX8_INTF_DAC_DIF_MASK | +			   CS42XX8_INTF_ADC_DIF_MASK, val); + +	/* Set master/slave audio interface */ +	switch (format & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBS_CFS: +		cs42xx8->slave_mode = true; +		break; +	case SND_SOC_DAIFMT_CBM_CFM: +		cs42xx8->slave_mode = false; +		break; +	default: +		dev_err(codec->dev, "unsupported master/slave mode\n"); +		return -EINVAL; +	} + +	return 0; +} + +static int cs42xx8_hw_params(struct snd_pcm_substream *substream, +			     struct snd_pcm_hw_params *params, +			     struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); +	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; +	u32 ratio = cs42xx8->sysclk / params_rate(params); +	u32 i, fm, val, mask; + +	for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { +		if (cs42xx8_ratios[i].ratio == ratio) +			break; +	} + +	if (i == ARRAY_SIZE(cs42xx8_ratios)) { +		dev_err(codec->dev, "unsupported sysclk ratio\n"); +		return -EINVAL; +	} + +	mask = CS42XX8_FUNCMOD_MFREQ_MASK; +	val = cs42xx8_ratios[i].mclk; + +	fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed; + +	regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, +			   CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask, +			   CS42XX8_FUNCMOD_xC_FM(tx, fm) | val); + +	return 0; +} + +static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + +	regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE, +			   CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0); + +	return 0; +} + +static const struct snd_soc_dai_ops cs42xx8_dai_ops = { +	.set_fmt	= cs42xx8_set_dai_fmt, +	.set_sysclk	= cs42xx8_set_dai_sysclk, +	.hw_params	= cs42xx8_hw_params, +	.digital_mute	= cs42xx8_digital_mute, +}; + +static struct snd_soc_dai_driver cs42xx8_dai = { +	.playback = { +		.stream_name = "Playback", +		.channels_min = 1, +		.channels_max = 8, +		.rates = SNDRV_PCM_RATE_8000_192000, +		.formats = CS42XX8_FORMATS, +	}, +	.capture = { +		.stream_name = "Capture", +		.channels_min = 1, +		.rates = SNDRV_PCM_RATE_8000_192000, +		.formats = CS42XX8_FORMATS, +	}, +	.ops = &cs42xx8_dai_ops, +}; + +static const struct reg_default cs42xx8_reg[] = { +	{ 0x01, 0x01 },   /* Chip I.D. and Revision Register */ +	{ 0x02, 0x00 },   /* Power Control */ +	{ 0x03, 0xF0 },   /* Functional Mode */ +	{ 0x04, 0x46 },   /* Interface Formats */ +	{ 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */ +	{ 0x06, 0x10 },   /* Transition Control */ +	{ 0x07, 0x00 },   /* DAC Channel Mute */ +	{ 0x08, 0x00 },   /* Volume Control AOUT1 */ +	{ 0x09, 0x00 },   /* Volume Control AOUT2 */ +	{ 0x0a, 0x00 },   /* Volume Control AOUT3 */ +	{ 0x0b, 0x00 },   /* Volume Control AOUT4 */ +	{ 0x0c, 0x00 },   /* Volume Control AOUT5 */ +	{ 0x0d, 0x00 },   /* Volume Control AOUT6 */ +	{ 0x0e, 0x00 },   /* Volume Control AOUT7 */ +	{ 0x0f, 0x00 },   /* Volume Control AOUT8 */ +	{ 0x10, 0x00 },   /* DAC Channel Invert */ +	{ 0x11, 0x00 },   /* Volume Control AIN1 */ +	{ 0x12, 0x00 },   /* Volume Control AIN2 */ +	{ 0x13, 0x00 },   /* Volume Control AIN3 */ +	{ 0x14, 0x00 },   /* Volume Control AIN4 */ +	{ 0x15, 0x00 },   /* Volume Control AIN5 */ +	{ 0x16, 0x00 },   /* Volume Control AIN6 */ +	{ 0x17, 0x00 },   /* ADC Channel Invert */ +	{ 0x18, 0x00 },   /* Status Control */ +	{ 0x1a, 0x00 },   /* Status Mask */ +	{ 0x1b, 0x00 },   /* MUTEC Pin Control */ +}; + +static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS42XX8_STATUS: +		return true; +	default: +		return false; +	} +} + +static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS42XX8_CHIPID: +	case CS42XX8_STATUS: +		return false; +	default: +		return true; +	} +} + +const struct regmap_config cs42xx8_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = CS42XX8_LASTREG, +	.reg_defaults = cs42xx8_reg, +	.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg), +	.volatile_reg = cs42xx8_volatile_register, +	.writeable_reg = cs42xx8_writeable_register, +	.cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs42xx8_regmap_config); + +static int cs42xx8_codec_probe(struct snd_soc_codec *codec) +{ +	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = &codec->dapm; + +	switch (cs42xx8->drvdata->num_adcs) { +	case 3: +		snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls, +					ARRAY_SIZE(cs42xx8_adc3_snd_controls)); +		snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets, +					ARRAY_SIZE(cs42xx8_adc3_dapm_widgets)); +		snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes, +					ARRAY_SIZE(cs42xx8_adc3_dapm_routes)); +		break; +	default: +		break; +	} + +	/* Mute all DAC channels */ +	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL); + +	return 0; +} + +static const struct snd_soc_codec_driver cs42xx8_driver = { +	.probe = cs42xx8_codec_probe, +	.idle_bias_off = true, + +	.controls = cs42xx8_snd_controls, +	.num_controls = ARRAY_SIZE(cs42xx8_snd_controls), +	.dapm_widgets = cs42xx8_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets), +	.dapm_routes = cs42xx8_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes), +}; + +const struct cs42xx8_driver_data cs42448_data = { +	.name = "cs42448", +	.num_adcs = 3, +}; +EXPORT_SYMBOL_GPL(cs42448_data); + +const struct cs42xx8_driver_data cs42888_data = { +	.name = "cs42888", +	.num_adcs = 2, +}; +EXPORT_SYMBOL_GPL(cs42888_data); + +const struct of_device_id cs42xx8_of_match[] = { +	{ .compatible = "cirrus,cs42448", .data = &cs42448_data, }, +	{ .compatible = "cirrus,cs42888", .data = &cs42888_data, }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, cs42xx8_of_match); +EXPORT_SYMBOL_GPL(cs42xx8_of_match); + +int cs42xx8_probe(struct device *dev, struct regmap *regmap) +{ +	const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev); +	struct cs42xx8_priv *cs42xx8; +	int ret, val, i; + +	cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL); +	if (cs42xx8 == NULL) +		return -ENOMEM; + +	dev_set_drvdata(dev, cs42xx8); + +	if (of_id) +		cs42xx8->drvdata = of_id->data; + +	if (!cs42xx8->drvdata) { +		dev_err(dev, "failed to find driver data\n"); +		return -EINVAL; +	} + +	cs42xx8->clk = devm_clk_get(dev, "mclk"); +	if (IS_ERR(cs42xx8->clk)) { +		dev_err(dev, "failed to get the clock: %ld\n", +				PTR_ERR(cs42xx8->clk)); +		return -EINVAL; +	} + +	cs42xx8->sysclk = clk_get_rate(cs42xx8->clk); + +	for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++) +		cs42xx8->supplies[i].supply = cs42xx8_supply_names[i]; + +	ret = devm_regulator_bulk_get(dev, +			ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies); +	if (ret) { +		dev_err(dev, "failed to request supplies: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies), +				    cs42xx8->supplies); +	if (ret) { +		dev_err(dev, "failed to enable supplies: %d\n", ret); +		return ret; +	} + +	/* Make sure hardware reset done */ +	msleep(5); + +	cs42xx8->regmap = regmap; +	if (IS_ERR(cs42xx8->regmap)) { +		ret = PTR_ERR(cs42xx8->regmap); +		dev_err(dev, "failed to allocate regmap: %d\n", ret); +		goto err_enable; +	} + +	/* +	 * We haven't marked the chip revision as volatile due to +	 * sharing a register with the right input volume; explicitly +	 * bypass the cache to read it. +	 */ +	regcache_cache_bypass(cs42xx8->regmap, true); + +	/* Validate the chip ID */ +	ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val); +	if (ret < 0) { +		dev_err(dev, "failed to get device ID, ret = %d", ret); +		goto err_enable; +	} + +	/* The top four bits of the chip ID should be 0000 */ +	if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) { +		dev_err(dev, "unmatched chip ID: %d\n", +			(val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4); +		ret = -EINVAL; +		goto err_enable; +	} + +	dev_info(dev, "found device, revision %X\n", +			val & CS42XX8_CHIPID_REV_ID_MASK); + +	regcache_cache_bypass(cs42xx8->regmap, false); + +	cs42xx8_dai.name = cs42xx8->drvdata->name; + +	/* Each adc supports stereo input */ +	cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2; + +	ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1); +	if (ret) { +		dev_err(dev, "failed to register codec:%d\n", ret); +		goto err_enable; +	} + +	regcache_cache_only(cs42xx8->regmap, true); + +err_enable: +	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), +			       cs42xx8->supplies); + +	return ret; +} +EXPORT_SYMBOL_GPL(cs42xx8_probe); + +#ifdef CONFIG_PM_RUNTIME +static int cs42xx8_runtime_resume(struct device *dev) +{ +	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev); +	int ret; + +	ret = clk_prepare_enable(cs42xx8->clk); +	if (ret) { +		dev_err(dev, "failed to enable mclk: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies), +				    cs42xx8->supplies); +	if (ret) { +		dev_err(dev, "failed to enable supplies: %d\n", ret); +		goto err_clk; +	} + +	/* Make sure hardware reset done */ +	msleep(5); + +	regcache_cache_only(cs42xx8->regmap, false); + +	ret = regcache_sync(cs42xx8->regmap); +	if (ret) { +		dev_err(dev, "failed to sync regmap: %d\n", ret); +		goto err_bulk; +	} + +	return 0; + +err_bulk: +	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), +			       cs42xx8->supplies); +err_clk: +	clk_disable_unprepare(cs42xx8->clk); + +	return ret; +} + +static int cs42xx8_runtime_suspend(struct device *dev) +{ +	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev); + +	regcache_cache_only(cs42xx8->regmap, true); + +	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), +			       cs42xx8->supplies); + +	clk_disable_unprepare(cs42xx8->clk); + +	return 0; +} +#endif + +const struct dev_pm_ops cs42xx8_pm = { +	SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL) +}; +EXPORT_SYMBOL_GPL(cs42xx8_pm); + +MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h new file mode 100644 index 00000000000..da0b94aee41 --- /dev/null +++ b/sound/soc/codecs/cs42xx8.h @@ -0,0 +1,238 @@ +/* + * cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen <Guangyu.Chen@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef _CS42XX8_H +#define _CS42XX8_H + +struct cs42xx8_driver_data { +	char name[32]; +	int num_adcs; +}; + +extern const struct dev_pm_ops cs42xx8_pm; +extern const struct cs42xx8_driver_data cs42448_data; +extern const struct cs42xx8_driver_data cs42888_data; +extern const struct regmap_config cs42xx8_regmap_config; +int cs42xx8_probe(struct device *dev, struct regmap *regmap); + +/* CS42888 register map */ +#define CS42XX8_CHIPID				0x01	/* Chip ID */ +#define CS42XX8_PWRCTL				0x02	/* Power Control */ +#define CS42XX8_FUNCMOD				0x03	/* Functional Mode */ +#define CS42XX8_INTF				0x04	/* Interface Formats */ +#define CS42XX8_ADCCTL				0x05	/* ADC Control */ +#define CS42XX8_TXCTL				0x06	/* Transition Control */ +#define CS42XX8_DACMUTE				0x07	/* DAC Mute Control */ +#define CS42XX8_VOLAOUT1			0x08	/* Volume Control AOUT1 */ +#define CS42XX8_VOLAOUT2			0x09	/* Volume Control AOUT2 */ +#define CS42XX8_VOLAOUT3			0x0A	/* Volume Control AOUT3 */ +#define CS42XX8_VOLAOUT4			0x0B	/* Volume Control AOUT4 */ +#define CS42XX8_VOLAOUT5			0x0C	/* Volume Control AOUT5 */ +#define CS42XX8_VOLAOUT6			0x0D	/* Volume Control AOUT6 */ +#define CS42XX8_VOLAOUT7			0x0E	/* Volume Control AOUT7 */ +#define CS42XX8_VOLAOUT8			0x0F	/* Volume Control AOUT8 */ +#define CS42XX8_DACINV				0x10	/* DAC Channel Invert */ +#define CS42XX8_VOLAIN1				0x11	/* Volume Control AIN1 */ +#define CS42XX8_VOLAIN2				0x12	/* Volume Control AIN2 */ +#define CS42XX8_VOLAIN3				0x13	/* Volume Control AIN3 */ +#define CS42XX8_VOLAIN4				0x14	/* Volume Control AIN4 */ +#define CS42XX8_VOLAIN5				0x15	/* Volume Control AIN5 */ +#define CS42XX8_VOLAIN6				0x16	/* Volume Control AIN6 */ +#define CS42XX8_ADCINV				0x17	/* ADC Channel Invert */ +#define CS42XX8_STATUSCTL			0x18	/* Status Control */ +#define CS42XX8_STATUS				0x19	/* Status */ +#define CS42XX8_STATUSM				0x1A	/* Status Mask */ +#define CS42XX8_MUTEC				0x1B	/* MUTEC Pin Control */ + +#define CS42XX8_FIRSTREG			CS42XX8_CHIPID +#define CS42XX8_LASTREG				CS42XX8_MUTEC +#define CS42XX8_NUMREGS				(CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1) +#define CS42XX8_I2C_INCR			0x80 + +/* Chip I.D. and Revision Register (Address 01h) */ +#define CS42XX8_CHIPID_CHIP_ID_MASK		0xF0 +#define CS42XX8_CHIPID_REV_ID_MASK		0x0F + +/* Power Control (Address 02h) */ +#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT		7 +#define CS42XX8_PWRCTL_PDN_ADC3_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC3			(1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT		6 +#define CS42XX8_PWRCTL_PDN_ADC2_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC2			(1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT		5 +#define CS42XX8_PWRCTL_PDN_ADC1_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC1			(1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT		4 +#define CS42XX8_PWRCTL_PDN_DAC4_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC4			(1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT		3 +#define CS42XX8_PWRCTL_PDN_DAC3_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC3			(1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT		2 +#define CS42XX8_PWRCTL_PDN_DAC2_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC2			(1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT		1 +#define CS42XX8_PWRCTL_PDN_DAC1_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC1			(1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_SHIFT		0 +#define CS42XX8_PWRCTL_PDN_MASK			(1 << CS42XX8_PWRCTL_PDN_SHIFT) +#define CS42XX8_PWRCTL_PDN			(1 << CS42XX8_PWRCTL_PDN_SHIFT) + +/* Functional Mode (Address 03h) */ +#define CS42XX8_FUNCMOD_DAC_FM_SHIFT		6 +#define CS42XX8_FUNCMOD_DAC_FM_WIDTH		2 +#define CS42XX8_FUNCMOD_DAC_FM_MASK		(((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT) +#define CS42XX8_FUNCMOD_DAC_FM(v)		((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT) +#define CS42XX8_FUNCMOD_ADC_FM_SHIFT		4 +#define CS42XX8_FUNCMOD_ADC_FM_WIDTH		2 +#define CS42XX8_FUNCMOD_ADC_FM_MASK		(((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT) +#define CS42XX8_FUNCMOD_ADC_FM(v)		((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT) +#define CS42XX8_FUNCMOD_xC_FM_MASK(x)		((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK) +#define CS42XX8_FUNCMOD_xC_FM(x, v)		((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v)) +#define CS42XX8_FUNCMOD_MFREQ_SHIFT		1 +#define CS42XX8_FUNCMOD_MFREQ_WIDTH		3 +#define CS42XX8_FUNCMOD_MFREQ_MASK		(((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT) +#define CS42XX8_FUNCMOD_MFREQ_256(s)		((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_384(s)		((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_512(s)		((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_768(s)		((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_1024(s)		((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) + +#define CS42XX8_FM_SINGLE			0 +#define CS42XX8_FM_DOUBLE			1 +#define CS42XX8_FM_QUAD				2 +#define CS42XX8_FM_AUTO				3 + +/* Interface Formats (Address 04h) */ +#define CS42XX8_INTF_FREEZE_SHIFT		7 +#define CS42XX8_INTF_FREEZE_MASK		(1 << CS42XX8_INTF_FREEZE_SHIFT) +#define CS42XX8_INTF_FREEZE			(1 << CS42XX8_INTF_FREEZE_SHIFT) +#define CS42XX8_INTF_AUX_DIF_SHIFT		6 +#define CS42XX8_INTF_AUX_DIF_MASK		(1 << CS42XX8_INTF_AUX_DIF_SHIFT) +#define CS42XX8_INTF_AUX_DIF			(1 << CS42XX8_INTF_AUX_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_SHIFT		3 +#define CS42XX8_INTF_DAC_DIF_WIDTH		3 +#define CS42XX8_INTF_DAC_DIF_MASK		(((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_LEFTJ		(0 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_I2S		(1 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_RIGHTJ		(2 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16		(3 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_ONELINE_20		(4 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_ONELINE_24		(6 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_TDM		(7 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_SHIFT		0 +#define CS42XX8_INTF_ADC_DIF_WIDTH		3 +#define CS42XX8_INTF_ADC_DIF_MASK		(((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_LEFTJ		(0 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_I2S		(1 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_RIGHTJ		(2 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16		(3 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_ONELINE_20		(4 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_ONELINE_24		(6 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_TDM		(7 << CS42XX8_INTF_ADC_DIF_SHIFT) + +/* ADC Control & DAC De-Emphasis (Address 05h) */ +#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT	7 +#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK	(1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT) +#define CS42XX8_ADCCTL_ADC_HPF_FREEZE		(1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT) +#define CS42XX8_ADCCTL_DAC_DEM_SHIFT		5 +#define CS42XX8_ADCCTL_DAC_DEM_MASK		(1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT) +#define CS42XX8_ADCCTL_DAC_DEM			(1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT) +#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT	4 +#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC1_SINGLE		(1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT	3 +#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC2_SINGLE		(1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT	2 +#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC3_SINGLE		(1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT		1 +#define CS42XX8_ADCCTL_AIN5_MUX_MASK		(1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT) +#define CS42XX8_ADCCTL_AIN5_MUX			(1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT) +#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT		0 +#define CS42XX8_ADCCTL_AIN6_MUX_MASK		(1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT) +#define CS42XX8_ADCCTL_AIN6_MUX			(1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT) + +/* Transition Control (Address 06h) */ +#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT		7 +#define CS42XX8_TXCTL_DAC_SNGVOL_MASK		(1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_DAC_SNGVOL		(1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_SHIFT		5 +#define CS42XX8_TXCTL_DAC_SZC_WIDTH		2 +#define CS42XX8_TXCTL_DAC_SZC_MASK		(((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_IC		(0 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_ZC		(1 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_SR		(2 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_SRZC		(3 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_AMUTE_SHIFT		4 +#define CS42XX8_TXCTL_AMUTE_MASK		(1 << CS42XX8_TXCTL_AMUTE_SHIFT) +#define CS42XX8_TXCTL_AMUTE			(1 << CS42XX8_TXCTL_AMUTE_SHIFT) +#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT		3 +#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK		(1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT) +#define CS42XX8_TXCTL_MUTE_ADC_SP		(1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT) +#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT		2 +#define CS42XX8_TXCTL_ADC_SNGVOL_MASK		(1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_ADC_SNGVOL		(1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_SHIFT		0 +#define CS42XX8_TXCTL_ADC_SZC_MASK		(((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_IC		(0 << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_ZC		(1 << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_SR		(2 << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_SRZC		(3 << CS42XX8_TXCTL_ADC_SZC_SHIFT) + +/* DAC Channel Mute (Address 07h) */ +#define CS42XX8_DACMUTE_AOUT(n)			(0x1 << n) +#define CS42XX8_DACMUTE_ALL			0xff + +/* Status Control (Address 18h)*/ +#define CS42XX8_STATUSCTL_INI_SHIFT		2 +#define CS42XX8_STATUSCTL_INI_WIDTH		2 +#define CS42XX8_STATUSCTL_INI_MASK		(((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT) +#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH	(0 << CS42XX8_STATUSCTL_INI_SHIFT) +#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW	(1 << CS42XX8_STATUSCTL_INI_SHIFT) +#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN	(2 << CS42XX8_STATUSCTL_INI_SHIFT) + +/* Status (Address 19h)*/ +#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT	4 +#define CS42XX8_STATUS_DAC_CLK_ERR_MASK		(1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT) +#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT	3 +#define CS42XX8_STATUS_ADC_CLK_ERR_MASK		(1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT) +#define CS42XX8_STATUS_ADC3_OVFL_SHIFT		2 +#define CS42XX8_STATUS_ADC3_OVFL_MASK		(1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT) +#define CS42XX8_STATUS_ADC2_OVFL_SHIFT		1 +#define CS42XX8_STATUS_ADC2_OVFL_MASK		(1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT) +#define CS42XX8_STATUS_ADC1_OVFL_SHIFT		0 +#define CS42XX8_STATUS_ADC1_OVFL_MASK		(1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT) + +/* Status Mask (Address 1Ah) */ +#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT	4 +#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK	(1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT) +#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT	3 +#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK	(1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT) +#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT	2 +#define CS42XX8_STATUS_ADC3_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT) +#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT	1 +#define CS42XX8_STATUS_ADC2_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT) +#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT	0 +#define CS42XX8_STATUS_ADC1_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT) + +/* MUTEC Pin Control (Address 1Bh) */ +#define CS42XX8_MUTEC_MCPOLARITY_SHIFT		1 +#define CS42XX8_MUTEC_MCPOLARITY_MASK		(1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT) +#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW	(0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT) +#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH	(1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT) +#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT	0 +#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK		(1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT) +#define CS42XX8_MUTEC_MUTEC_ACTIVE		(1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT) +#endif /* _CS42XX8_H */ diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 9c123145650..21810e5f332 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -307,35 +307,35 @@ static const char * const da7210_hpf_cutoff_txt[] = {  	"Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi"  }; -static const struct soc_enum da7210_dac_hpf_cutoff = -	SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff, +			    DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt); -static const struct soc_enum da7210_adc_hpf_cutoff = -	SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff, +			    DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt);  /* ADC and DAC voice (8kHz) high pass cutoff value */  static const char * const da7210_vf_cutoff_txt[] = {  	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"  }; -static const struct soc_enum da7210_dac_vf_cutoff = -	SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff, +			    DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt); -static const struct soc_enum da7210_adc_vf_cutoff = -	SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff, +			    DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt);  static const char *da7210_hp_mode_txt[] = {  	"Class H", "Class G"  }; -static const struct soc_enum da7210_hp_mode_sel = -	SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt); +static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel, +			    DA7210_HP_CFG, 0, da7210_hp_mode_txt);  /* ALC can be enabled only if noise suppression is disabled */  static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	if (ucontrol->value.integer.value[0]) {  		/* Check if noise suppression is enabled */ @@ -358,7 +358,7 @@ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,  static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,  				   struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	u8 val;  	if (ucontrol->value.integer.value[0]) { @@ -778,17 +778,17 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,  	dai_cfg1 = 0xFC & snd_soc_read(codec, DA7210_DAI_CFG1); -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		dai_cfg1 |= DA7210_DAI_WORD_S16_LE;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		dai_cfg1 |= DA7210_DAI_WORD_S20_3LE;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		dai_cfg1 |= DA7210_DAI_WORD_S24_LE;  		break; -	case SNDRV_PCM_FORMAT_S32_LE: +	case 32:  		dai_cfg1 |= DA7210_DAI_WORD_S32_LE;  		break;  	default: @@ -1071,17 +1071,9 @@ static struct snd_soc_dai_driver da7210_dai = {  static int da7210_probe(struct snd_soc_codec *codec)  {  	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec); -	int ret;  	dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); -	codec->control_data = da7210->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	da7210->mclk_rate       = 0;    /* This will be set from set_sysclk() */  	da7210->master          = 0;    /* This will be set from set_fmt() */ @@ -1188,7 +1180,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {  	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static struct reg_default da7210_regmap_i2c_patch[] = { @@ -1362,7 +1354,7 @@ static struct spi_driver da7210_spi_driver = {  static int __init da7210_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&da7210_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) @@ -1378,7 +1370,7 @@ module_init(da7210_modinit);  static void __exit da7210_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&da7210_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 4a6f1daf911..9ec577f0edb 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -63,30 +63,30 @@ static const char * const da7213_voice_hpf_corner_txt[] = {  	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"  }; -static const struct soc_enum da7213_dac_voice_hpf_corner = -	SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, -			DA7213_VOICE_HPF_CORNER_MAX, -			da7213_voice_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_voice_hpf_corner, +			    DA7213_DAC_FILTERS1, +			    DA7213_VOICE_HPF_CORNER_SHIFT, +			    da7213_voice_hpf_corner_txt); -static const struct soc_enum da7213_adc_voice_hpf_corner = -	SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, -			DA7213_VOICE_HPF_CORNER_MAX, -			da7213_voice_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_adc_voice_hpf_corner, +			    DA7213_ADC_FILTERS1, +			    DA7213_VOICE_HPF_CORNER_SHIFT, +			    da7213_voice_hpf_corner_txt);  /* ADC and DAC high pass filter cutoff value */  static const char * const da7213_audio_hpf_corner_txt[] = {  	"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"  }; -static const struct soc_enum da7213_dac_audio_hpf_corner = -	SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, -			DA7213_AUDIO_HPF_CORNER_MAX, -			da7213_audio_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_audio_hpf_corner, +			    DA7213_DAC_FILTERS1 +			    , DA7213_AUDIO_HPF_CORNER_SHIFT, +			    da7213_audio_hpf_corner_txt); -static const struct soc_enum da7213_adc_audio_hpf_corner = -	SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, -			DA7213_AUDIO_HPF_CORNER_MAX, -			da7213_audio_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner, +			    DA7213_ADC_FILTERS1, +			    DA7213_AUDIO_HPF_CORNER_SHIFT, +			    da7213_audio_hpf_corner_txt);  /* Gain ramping rate value */  static const char * const da7213_gain_ramp_rate_txt[] = { @@ -94,52 +94,50 @@ static const char * const da7213_gain_ramp_rate_txt[] = {  	"nominal rate / 32"  }; -static const struct soc_enum da7213_gain_ramp_rate = -	SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT, -			DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_gain_ramp_rate, +			    DA7213_GAIN_RAMP_CTRL, +			    DA7213_GAIN_RAMP_RATE_SHIFT, +			    da7213_gain_ramp_rate_txt);  /* DAC noise gate setup time value */  static const char * const da7213_dac_ng_setup_time_txt[] = {  	"256 samples", "512 samples", "1024 samples", "2048 samples"  }; -static const struct soc_enum da7213_dac_ng_setup_time = -	SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, -			DA7213_DAC_NG_SETUP_TIME_SHIFT, -			DA7213_DAC_NG_SETUP_TIME_MAX, -			da7213_dac_ng_setup_time_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_setup_time, +			    DA7213_DAC_NG_SETUP_TIME, +			    DA7213_DAC_NG_SETUP_TIME_SHIFT, +			    da7213_dac_ng_setup_time_txt);  /* DAC noise gate rampup rate value */  static const char * const da7213_dac_ng_rampup_txt[] = {  	"0.02 ms/dB", "0.16 ms/dB"  }; -static const struct soc_enum da7213_dac_ng_rampup_rate = -	SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, -			DA7213_DAC_NG_RAMPUP_RATE_SHIFT, -			DA7213_DAC_NG_RAMP_RATE_MAX, -			da7213_dac_ng_rampup_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampup_rate, +			    DA7213_DAC_NG_SETUP_TIME, +			    DA7213_DAC_NG_RAMPUP_RATE_SHIFT, +			    da7213_dac_ng_rampup_txt);  /* DAC noise gate rampdown rate value */  static const char * const da7213_dac_ng_rampdown_txt[] = {  	"0.64 ms/dB", "20.48 ms/dB"  }; -static const struct soc_enum da7213_dac_ng_rampdown_rate = -	SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, -			DA7213_DAC_NG_RAMPDN_RATE_SHIFT, -			DA7213_DAC_NG_RAMP_RATE_MAX, -			da7213_dac_ng_rampdown_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampdown_rate, +			    DA7213_DAC_NG_SETUP_TIME, +			    DA7213_DAC_NG_RAMPDN_RATE_SHIFT, +			    da7213_dac_ng_rampdown_txt);  /* DAC soft mute rate value */  static const char * const da7213_dac_soft_mute_rate_txt[] = {  	"1", "2", "4", "8", "16", "32", "64"  }; -static const struct soc_enum da7213_dac_soft_mute_rate = -	SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT, -			DA7213_DAC_SOFTMUTE_RATE_MAX, -			da7213_dac_soft_mute_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_soft_mute_rate, +			    DA7213_DAC_FILTERS5, +			    DA7213_DAC_SOFTMUTE_RATE_SHIFT, +			    da7213_dac_soft_mute_rate_txt);  /* ALC Attack Rate select */  static const char * const da7213_alc_attack_rate_txt[] = { @@ -147,9 +145,10 @@ static const char * const da7213_alc_attack_rate_txt[] = {  	"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"  }; -static const struct soc_enum da7213_alc_attack_rate = -	SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT, -			DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_attack_rate, +			    DA7213_ALC_CTRL2, +			    DA7213_ALC_ATTACK_SHIFT, +			    da7213_alc_attack_rate_txt);  /* ALC Release Rate select */  static const char * const da7213_alc_release_rate_txt[] = { @@ -157,9 +156,10 @@ static const char * const da7213_alc_release_rate_txt[] = {  	"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"  }; -static const struct soc_enum da7213_alc_release_rate = -	SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT, -			DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_release_rate, +			    DA7213_ALC_CTRL2, +			    DA7213_ALC_RELEASE_SHIFT, +			    da7213_alc_release_rate_txt);  /* ALC Hold Time select */  static const char * const da7213_alc_hold_time_txt[] = { @@ -168,22 +168,25 @@ static const char * const da7213_alc_hold_time_txt[] = {  	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"  }; -static const struct soc_enum da7213_alc_hold_time = -	SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT, -			DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_hold_time, +			    DA7213_ALC_CTRL3, +			    DA7213_ALC_HOLD_SHIFT, +			    da7213_alc_hold_time_txt);  /* ALC Input Signal Tracking rate select */  static const char * const da7213_alc_integ_rate_txt[] = {  	"1/4", "1/16", "1/256", "1/65536"  }; -static const struct soc_enum da7213_alc_integ_attack_rate = -	SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT, -			DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_attack_rate, +			    DA7213_ALC_CTRL3, +			    DA7213_ALC_INTEG_ATTACK_SHIFT, +			    da7213_alc_integ_rate_txt); -static const struct soc_enum da7213_alc_integ_release_rate = -	SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT, -			DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate, +			    DA7213_ALC_CTRL3, +			    DA7213_ALC_INTEG_RELEASE_SHIFT, +			    da7213_alc_integ_rate_txt);  /* @@ -342,7 +345,7 @@ static void da7213_alc_calib(struct snd_soc_codec *codec)  static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);  	int ret; @@ -358,7 +361,7 @@ static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,  static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol,  			    struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);  	/* Force ALC offset calibration if enabling ALC */ @@ -584,15 +587,17 @@ static const char * const da7213_mic_amp_in_sel_txt[] = {  	"Differential", "MIC_P", "MIC_N"  }; -static const struct soc_enum da7213_mic_1_amp_in_sel = -	SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, -			DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static SOC_ENUM_SINGLE_DECL(da7213_mic_1_amp_in_sel, +			    DA7213_MIC_1_CTRL, +			    DA7213_MIC_AMP_IN_SEL_SHIFT, +			    da7213_mic_amp_in_sel_txt);  static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux =  	SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); -static const struct soc_enum da7213_mic_2_amp_in_sel = -	SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, -			DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static SOC_ENUM_SINGLE_DECL(da7213_mic_2_amp_in_sel, +			    DA7213_MIC_2_CTRL, +			    DA7213_MIC_AMP_IN_SEL_SHIFT, +			    da7213_mic_amp_in_sel_txt);  static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux =  	SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); @@ -601,15 +606,17 @@ static const char * const da7213_dai_src_txt[] = {  	"ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right"  }; -static const struct soc_enum da7213_dai_l_src = -	SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT, -			DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dai_l_src, +			    DA7213_DIG_ROUTING_DAI, +			    DA7213_DAI_L_SRC_SHIFT, +			    da7213_dai_src_txt);  static const struct snd_kcontrol_new da7213_dai_l_src_mux =  	SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); -static const struct soc_enum da7213_dai_r_src = -	SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT, -			DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dai_r_src, +			    DA7213_DIG_ROUTING_DAI, +			    DA7213_DAI_R_SRC_SHIFT, +			    da7213_dai_src_txt);  static const struct snd_kcontrol_new da7213_dai_r_src_mux =  	SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); @@ -619,15 +626,17 @@ static const char * const da7213_dac_src_txt[] = {  	"DAI Input Right"  }; -static const struct soc_enum da7213_dac_l_src = -	SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT, -			DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_l_src, +			    DA7213_DIG_ROUTING_DAC, +			    DA7213_DAC_L_SRC_SHIFT, +			    da7213_dac_src_txt);  static const struct snd_kcontrol_new da7213_dac_l_src_mux =  	SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); -static const struct soc_enum da7213_dac_r_src = -	SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT, -			DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_r_src, +			    DA7213_DIG_ROUTING_DAC, +			    DA7213_DAC_R_SRC_SHIFT, +			    da7213_dac_src_txt);  static const struct snd_kcontrol_new da7213_dac_r_src_mux =  	SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); @@ -1067,17 +1076,17 @@ static int da7213_hw_params(struct snd_pcm_substream *substream,  	u8 fs;  	/* Set DAI format */ -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S20_LE;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S24_LE;  		break; -	case SNDRV_PCM_FORMAT_S32_LE: +	case 32:  		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S32_LE;  		break;  	default: @@ -1384,17 +1393,9 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,  static int da7213_probe(struct snd_soc_codec *codec)  { -	int ret;  	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);  	struct da7213_platform_data *pdata = da7213->pdata; -	codec->control_data = da7213->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Default to using ALC auto offset calibration mode. */  	snd_soc_update_bits(codec, DA7213_ALC_CTRL1,  			    DA7213_ALC_CALIB_MODE_MAN, 0); diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index dc0284dc9e6..2fae31cb006 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -269,86 +269,70 @@ static const char *da732x_hpf_voice[] = {  	"150Hz", "200Hz", "300Hz", "400Hz"  }; -static const struct soc_enum da732x_dac1_hpf_mode_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, -			DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac1_hpf_mode_enum, +			    DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, +			    da732x_hpf_mode); -static const struct soc_enum da732x_dac2_hpf_mode_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, -			DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac2_hpf_mode_enum, +			    DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, +			    da732x_hpf_mode); -static const struct soc_enum da732x_dac3_hpf_mode_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, -			DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac3_hpf_mode_enum, +			    DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, +			    da732x_hpf_mode); -static const struct soc_enum da732x_adc1_hpf_mode_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, -			DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc1_hpf_mode_enum, +			    DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, +			    da732x_hpf_mode); -static const struct soc_enum da732x_adc2_hpf_mode_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, -			DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc2_hpf_mode_enum, +			    DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, +			    da732x_hpf_mode); -static const struct soc_enum da732x_dac1_hp_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, -			DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac1_hp_filter_enum, +			    DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, +			    da732x_hpf_music); -static const struct soc_enum da732x_dac2_hp_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, -			DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac2_hp_filter_enum, +			    DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, +			    da732x_hpf_music); -static const struct soc_enum da732x_dac3_hp_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, -			DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac3_hp_filter_enum, +			    DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, +			    da732x_hpf_music); -static const struct soc_enum da732x_adc1_hp_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, -			DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc1_hp_filter_enum, +			    DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, +			    da732x_hpf_music); -static const struct soc_enum da732x_adc2_hp_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, -			DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc2_hp_filter_enum, +			    DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, +			    da732x_hpf_music); -static const struct soc_enum da732x_dac1_voice_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, -			DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac1_voice_filter_enum, +			    DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, +			    da732x_hpf_voice); -static const struct soc_enum da732x_dac2_voice_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, -			DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac2_voice_filter_enum, +			    DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, +			    da732x_hpf_voice); -static const struct soc_enum da732x_dac3_voice_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, -			DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac3_voice_filter_enum, +			    DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, +			    da732x_hpf_voice); -static const struct soc_enum da732x_adc1_voice_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, -			DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; - -static const struct soc_enum da732x_adc2_voice_filter_enum[] = { -	SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, -			DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc1_voice_filter_enum, +			    DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, +			    da732x_hpf_voice); +static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum, +			    DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, +			    da732x_hpf_voice);  static int da732x_hpf_set(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;  	unsigned int reg = enum_ctrl->reg;  	unsigned int sel = ucontrol->value.integer.value[0]; @@ -376,7 +360,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol,  static int da732x_hpf_get(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;  	unsigned int reg = enum_ctrl->reg;  	int val; @@ -714,65 +698,65 @@ static const char *enable_text[] = {  };  /* ADC1LMUX */ -static const struct soc_enum adc1l_enum = -	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, -			DA732X_ADCL_MUX_MAX, adcl_text); +static SOC_ENUM_SINGLE_DECL(adc1l_enum, +			    DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, +			    adcl_text);  static const struct snd_kcontrol_new adc1l_mux =  	SOC_DAPM_ENUM("ADC Route", adc1l_enum);  /* ADC1RMUX */ -static const struct soc_enum adc1r_enum = -	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, -			DA732X_ADCR_MUX_MAX, adcr_text); +static SOC_ENUM_SINGLE_DECL(adc1r_enum, +			    DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, +			    adcr_text);  static const struct snd_kcontrol_new adc1r_mux =  	SOC_DAPM_ENUM("ADC Route", adc1r_enum);  /* ADC2LMUX */ -static const struct soc_enum adc2l_enum = -	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, -			DA732X_ADCL_MUX_MAX, adcl_text); +static SOC_ENUM_SINGLE_DECL(adc2l_enum, +			    DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, +			    adcl_text);  static const struct snd_kcontrol_new adc2l_mux =  	SOC_DAPM_ENUM("ADC Route", adc2l_enum);  /* ADC2RMUX */ -static const struct soc_enum adc2r_enum = -	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, -			DA732X_ADCR_MUX_MAX, adcr_text); +static SOC_ENUM_SINGLE_DECL(adc2r_enum, +			    DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, +			    adcr_text);  static const struct snd_kcontrol_new adc2r_mux =  	SOC_DAPM_ENUM("ADC Route", adc2r_enum); -static const struct soc_enum da732x_hp_left_output = -	SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, -			DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_hp_left_output, +			    DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, +			    enable_text);  static const struct snd_kcontrol_new hpl_mux =  	SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); -static const struct soc_enum da732x_hp_right_output = -	SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, -			DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_hp_right_output, +			    DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, +			    enable_text);  static const struct snd_kcontrol_new hpr_mux =  	SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); -static const struct soc_enum da732x_speaker_output = -	SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, -			DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_speaker_output, +			    DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, +			    enable_text);  static const struct snd_kcontrol_new spk_mux =  	SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); -static const struct soc_enum da732x_lout4_output = -	SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, -			DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_lout4_output, +			    DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, +			    enable_text);  static const struct snd_kcontrol_new lout4_mux =  	SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); -static const struct soc_enum da732x_lout2_output = -	SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, -			DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_lout2_output, +			    DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, +			    enable_text);  static const struct snd_kcontrol_new lout2_mux =  	SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); @@ -973,17 +957,17 @@ static int da732x_hw_params(struct snd_pcm_substream *substream,  	reg_aif = dai->driver->base; -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		aif |= DA732X_AIF_WORD_16;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		aif |= DA732X_AIF_WORD_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		aif |= DA732X_AIF_WORD_24;  		break; -	case SNDRV_PCM_FORMAT_S32_LE: +	case 32:  		aif |= DA732X_AIF_WORD_32;  		break;  	default: @@ -1268,11 +1252,23 @@ static struct snd_soc_dai_driver da732x_dai[] = {  	},  }; +static bool da732x_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case DA732X_REG_HPL_DAC_OFF_CNTL: +	case DA732X_REG_HPR_DAC_OFF_CNTL: +		return true; +	default: +		return false; +	} +} +  static const struct regmap_config da732x_regmap = {  	.reg_bits		= 8,  	.val_bits		= 8,  	.max_register		= DA732X_MAX_REG, +	.volatile_reg		= da732x_volatile,  	.reg_defaults		= da732x_reg_cache,  	.num_reg_defaults	= ARRAY_SIZE(da732x_reg_cache),  	.cache_type		= REGCACHE_RBTREE, @@ -1301,9 +1297,9 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)  	msleep(DA732X_WAIT_FOR_STABILIZATION);  	/* Check DAC offset sign */ -	sign[DA732X_HPL_DAC] = (codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) & +	sign[DA732X_HPL_DAC] = (snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &  				DA732X_HP_DAC_OFF_CNTL_COMPO); -	sign[DA732X_HPR_DAC] = (codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) & +	sign[DA732X_HPR_DAC] = (snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &  				DA732X_HP_DAC_OFF_CNTL_COMPO);  	/* Binary search DAC offset values (both channels at once) */ @@ -1320,10 +1316,10 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)  		msleep(DA732X_WAIT_FOR_STABILIZATION); -		if ((codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) & +		if ((snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &  		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC])  			offset[DA732X_HPL_DAC] &= ~step; -		if ((codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) & +		if ((snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &  		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC])  			offset[DA732X_HPR_DAC] &= ~step; @@ -1364,9 +1360,9 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)  	msleep(DA732X_WAIT_FOR_STABILIZATION);  	/* Check output offset sign */ -	sign[DA732X_HPL_AMP] = codec->hw_read(codec, DA732X_REG_HPL) & +	sign[DA732X_HPL_AMP] = snd_soc_read(codec, DA732X_REG_HPL) &  			       DA732X_HP_OUT_COMPO; -	sign[DA732X_HPR_AMP] = codec->hw_read(codec, DA732X_REG_HPR) & +	sign[DA732X_HPR_AMP] = snd_soc_read(codec, DA732X_REG_HPR) &  			       DA732X_HP_OUT_COMPO;  	snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP | @@ -1387,10 +1383,10 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)  		msleep(DA732X_WAIT_FOR_STABILIZATION); -		if ((codec->hw_read(codec, DA732X_REG_HPL) & +		if ((snd_soc_read(codec, DA732X_REG_HPL) &  		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP])  			offset[DA732X_HPL_AMP] &= ~step; -		if ((codec->hw_read(codec, DA732X_REG_HPR) & +		if ((snd_soc_read(codec, DA732X_REG_HPR) &  		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP])  			offset[DA732X_HPR_AMP] &= ~step; @@ -1487,8 +1483,8 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,  			da732x_hp_dc_offset_cancellation(codec); -			regcache_cache_only(codec->control_data, false); -			regcache_sync(codec->control_data); +			regcache_cache_only(da732x->regmap, false); +			regcache_sync(da732x->regmap);  		} else {  			snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,  					    DA732X_BIAS_BOOST_MASK, @@ -1499,7 +1495,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,  		}  		break;  	case SND_SOC_BIAS_OFF: -		regcache_cache_only(codec->control_data, true); +		regcache_cache_only(da732x->regmap, true);  		da732x_set_charge_pump(codec, DA732X_DISABLE_CP);  		snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,  				    DA732X_BIAS_DIS); @@ -1516,23 +1512,14 @@ static int da732x_probe(struct snd_soc_codec *codec)  {  	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);  	struct snd_soc_dapm_context *dapm = &codec->dapm; -	int ret = 0;  	da732x->codec = codec;  	dapm->idle_bias_off = false; -	codec->control_data = da732x->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to register codec.\n"); -		goto err; -	} -  	da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -err: -	return ret; + +	return 0;  }  static int da732x_remove(struct snd_soc_codec *codec) @@ -1554,7 +1541,6 @@ static struct snd_soc_codec_driver soc_codec_dev_da732x = {  	.dapm_routes		= da732x_dapm_routes,  	.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),  	.set_pll		= da732x_set_dai_pll, -	.reg_cache_size		= ARRAY_SIZE(da732x_reg_cache),  };  static int da732x_i2c_probe(struct i2c_client *i2c, @@ -1585,7 +1571,8 @@ static int da732x_i2c_probe(struct i2c_client *i2c,  	}  	dev_info(&i2c->dev, "Revision: %d.%d\n", -		 (reg & DA732X_ID_MAJOR_MASK), (reg & DA732X_ID_MINOR_MASK)); +		 (reg & DA732X_ID_MAJOR_MASK) >> 4, +		 (reg & DA732X_ID_MINOR_MASK));  	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x,  				     da732x_dai, ARRAY_SIZE(da732x_dai)); diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index c8ce5475de2..1dceafeec41 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h @@ -113,9 +113,6 @@  #define	DA732X_EQ_OVERALL_VOL_DB_MIN	-1800  #define	DA732X_EQ_OVERALL_VOL_DB_INC	600 -#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \ -	{.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext} -  enum da732x_sysctl {  	DA732X_SR_8KHZ		= 0x1,  	DA732X_SR_11_025KHZ	= 0x2, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index fc9802d1281..ad19cc56702 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -18,6 +18,8 @@  #include <linux/regmap.h>  #include <linux/slab.h>  #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h>  #include <sound/soc.h> @@ -321,22 +323,22 @@ static const char * const da9055_hpf_cutoff_txt[] = {  	"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"  }; -static const struct soc_enum da9055_dac_hpf_cutoff = -	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff, +			    DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt); -static const struct soc_enum da9055_adc_hpf_cutoff = -	SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff, +			    DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt);  /* ADC and DAC voice mode (8kHz) high pass cutoff value */  static const char * const da9055_vf_cutoff_txt[] = {  	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"  }; -static const struct soc_enum da9055_dac_vf_cutoff = -	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff, +			    DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt); -static const struct soc_enum da9055_adc_vf_cutoff = -	SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff, +			    DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt);  /* Gain ramping rate value */  static const char * const da9055_gain_ramping_txt[] = { @@ -344,44 +346,44 @@ static const char * const da9055_gain_ramping_txt[] = {  	"nominal rate / 8"  }; -static const struct soc_enum da9055_gain_ramping_rate = -	SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt); +static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate, +			    DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt);  /* DAC noise gate setup time value */  static const char * const da9055_dac_ng_setup_time_txt[] = {  	"256 samples", "512 samples", "1024 samples", "2048 samples"  }; -static const struct soc_enum da9055_dac_ng_setup_time = -	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4, -			da9055_dac_ng_setup_time_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time, +			    DA9055_DAC_NG_SETUP_TIME, 0, +			    da9055_dac_ng_setup_time_txt);  /* DAC noise gate rampup rate value */  static const char * const da9055_dac_ng_rampup_txt[] = {  	"0.02 ms/dB", "0.16 ms/dB"  }; -static const struct soc_enum da9055_dac_ng_rampup_rate = -	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2, -			da9055_dac_ng_rampup_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate, +			    DA9055_DAC_NG_SETUP_TIME, 2, +			    da9055_dac_ng_rampup_txt);  /* DAC noise gate rampdown rate value */  static const char * const da9055_dac_ng_rampdown_txt[] = {  	"0.64 ms/dB", "20.48 ms/dB"  }; -static const struct soc_enum da9055_dac_ng_rampdown_rate = -	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2, -			da9055_dac_ng_rampdown_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate, +			    DA9055_DAC_NG_SETUP_TIME, 3, +			    da9055_dac_ng_rampdown_txt);  /* DAC soft mute rate value */  static const char * const da9055_dac_soft_mute_rate_txt[] = {  	"1", "2", "4", "8", "16", "32", "64"  }; -static const struct soc_enum da9055_dac_soft_mute_rate = -	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7, -			da9055_dac_soft_mute_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate, +			    DA9055_DAC_FILTERS5, 4, +			    da9055_dac_soft_mute_rate_txt);  /* DAC routing select */  static const char * const da9055_dac_src_txt[] = { @@ -389,40 +391,40 @@ static const char * const da9055_dac_src_txt[] = {  	"AIF input right"  }; -static const struct soc_enum da9055_dac_l_src = -	SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src, +			    DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt); -static const struct soc_enum da9055_dac_r_src = -	SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src, +			    DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt);  /* MIC PGA Left source select */  static const char * const da9055_mic_l_src_txt[] = {  	"MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L"  }; -static const struct soc_enum da9055_mic_l_src = -	SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src, +			    DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt);  /* MIC PGA Right source select */  static const char * const da9055_mic_r_src_txt[] = {  	"MIC2_R_L", "MIC2_R", "MIC2_L"  }; -static const struct soc_enum da9055_mic_r_src = -	SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src, +			    DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt);  /* ALC Input Signal Tracking rate select */  static const char * const da9055_signal_tracking_rate_txt[] = {  	"1/4", "1/16", "1/256", "1/65536"  }; -static const struct soc_enum da9055_integ_attack_rate = -	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4, -			da9055_signal_tracking_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate, +			    DA9055_ALC_CTRL3, 4, +			    da9055_signal_tracking_rate_txt); -static const struct soc_enum da9055_integ_release_rate = -	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4, -			da9055_signal_tracking_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate, +			    DA9055_ALC_CTRL3, 6, +			    da9055_signal_tracking_rate_txt);  /* ALC Attack Rate select */  static const char * const da9055_attack_rate_txt[] = { @@ -430,8 +432,8 @@ static const char * const da9055_attack_rate_txt[] = {  	"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"  }; -static const struct soc_enum da9055_attack_rate = -	SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_attack_rate, +			    DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt);  /* ALC Release Rate select */  static const char * const da9055_release_rate_txt[] = { @@ -439,8 +441,8 @@ static const char * const da9055_release_rate_txt[] = {  	"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"  }; -static const struct soc_enum da9055_release_rate = -	SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_release_rate, +			    DA9055_ALC_CTRL2, 4, da9055_release_rate_txt);  /* ALC Hold Time select */  static const char * const da9055_hold_time_txt[] = { @@ -449,8 +451,8 @@ static const char * const da9055_hold_time_txt[] = {  	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"  }; -static const struct soc_enum da9055_hold_time = -	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt); +static SOC_ENUM_SINGLE_DECL(da9055_hold_time, +			    DA9055_ALC_CTRL3, 0, da9055_hold_time_txt);  static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)  { @@ -482,7 +484,7 @@ static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)  static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	u8 reg_val, adc_left, adc_right, mic_left, mic_right;  	int avg_left_data, avg_right_data, offset_l, offset_r; @@ -1058,17 +1060,17 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,  	u8 aif_ctrl, fs;  	u32 sysclk; -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		aif_ctrl = DA9055_AIF_WORD_S16_LE;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		aif_ctrl = DA9055_AIF_WORD_S20_3LE;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		aif_ctrl = DA9055_AIF_WORD_S24_LE;  		break; -	case SNDRV_PCM_FORMAT_S32_LE: +	case 32:  		aif_ctrl = DA9055_AIF_WORD_S32_LE;  		break;  	default: @@ -1381,16 +1383,8 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,  static int da9055_probe(struct snd_soc_codec *codec)  { -	int ret;  	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec); -	codec->control_data = da9055->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Enable all Gain Ramps */  	snd_soc_update_bits(codec, DA9055_AUX_L_CTRL,  			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); @@ -1523,17 +1517,30 @@ static int da9055_remove(struct i2c_client *client)  	return 0;  } +/* + * DO NOT change the device Ids. The naming is intentionally specific as both + * the CODEC and PMIC parts of this chip are instantiated separately as I2C + * devices (both have configurable I2C addresses, and are to all intents and + * purposes separate). As a result there are specific DA9055 Ids for CODEC + * and PMIC, which must be different to operate together. + */  static const struct i2c_device_id da9055_i2c_id[] = { -	{ "da9055", 0 }, +	{ "da9055-codec", 0 },  	{ }  };  MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); +static const struct of_device_id da9055_of_match[] = { +	{ .compatible = "dlg,da9055-codec", }, +	{ } +}; +  /* I2C codec control layer */  static struct i2c_driver da9055_i2c_driver = {  	.driver = { -		.name = "da9055", +		.name = "da9055-codec",  		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(da9055_of_match),  	},  	.probe		= da9055_i2c_probe,  	.remove		= da9055_remove, diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 68342b121c9..1087fd5f991 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -20,6 +20,8 @@   */  #include <linux/module.h>  #include <sound/soc.h> +#include <linux/of.h> +#include <linux/of_device.h>  #define DRV_NAME "hdmi-audio-codec" @@ -44,7 +46,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {  			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |  			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,  		.formats = SNDRV_PCM_FMTBIT_S16_LE | -			SNDRV_PCM_FMTBIT_S24_LE, +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,  	},  	.capture = {  		.stream_name = "Capture", @@ -60,6 +62,14 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {  }; +#ifdef CONFIG_OF +static const struct of_device_id hdmi_audio_codec_ids[] = { +	{ .compatible = "linux,hdmi-audio", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids); +#endif +  static struct snd_soc_codec_driver hdmi_codec = {  	.dapm_widgets = hdmi_widgets,  	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), @@ -83,6 +93,7 @@ static struct platform_driver hdmi_codec_driver = {  	.driver		= {  		.name	= DRV_NAME,  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(hdmi_audio_codec_ids),  	},  	.probe		= hdmi_codec_probe, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 53b455b8c07..3a89ce66d51 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -140,13 +140,17 @@ static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"};  static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"};  static const struct soc_enum isabelle_rx1_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts), -	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts), +	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, +			ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts), +	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, +			ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),  };  static const struct soc_enum isabelle_rx2_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts), -	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts), +	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, +			ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts), +	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, +			ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),  };  /* Headset DAC playback switches */ @@ -161,13 +165,17 @@ static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"};  static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"};  static const struct soc_enum isabelle_atx_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts), -	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts), +	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, +			ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts), +	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, +			ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),  };  static const struct soc_enum isabelle_vtx_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts), -	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts), +	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, +			ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts), +	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, +			ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),  };  static const struct snd_kcontrol_new atx_mux_controls = @@ -183,17 +191,13 @@ static const char *isabelle_amic1_texts[] = {  /* Left analog microphone selection */  static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"}; -static const struct soc_enum isabelle_amic1_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5, -			ARRAY_SIZE(isabelle_amic1_texts), -			isabelle_amic1_texts), -}; +static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum, +			    ISABELLE_AMIC_CFG_REG, 5, +			    isabelle_amic1_texts); -static const struct soc_enum isabelle_amic2_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4, -			ARRAY_SIZE(isabelle_amic2_texts), -			isabelle_amic2_texts), -}; +static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum, +			    ISABELLE_AMIC_CFG_REG, 4, +			    isabelle_amic2_texts);  static const struct snd_kcontrol_new amic1_control =  	SOC_DAPM_ENUM("Route", isabelle_amic1_enum); @@ -206,16 +210,20 @@ static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"};  static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"};  static const struct soc_enum isabelle_st_audio_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1, +	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, +			ARRAY_SIZE(isabelle_st_audio_texts),  			isabelle_st_audio_texts), -	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1, +	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, +			ARRAY_SIZE(isabelle_st_audio_texts),  			isabelle_st_audio_texts),  };  static const struct soc_enum isabelle_st_voice_enum[] = { -	SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1, +	SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, +			ARRAY_SIZE(isabelle_st_voice_texts),  			isabelle_st_voice_texts), -	SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1, +	SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, +			ARRAY_SIZE(isabelle_st_voice_texts),  			isabelle_st_voice_texts),  }; @@ -910,8 +918,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,  			      struct snd_pcm_hw_params *params,  			      struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	u16 aif = 0;  	unsigned int fs_val = 0; @@ -951,11 +958,11 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,  			ISABELLE_FS_RATE_MASK, fs_val);  	/* bit size */ -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S20_3LE: +	switch (params_width(params)) { +	case 20:  		aif |= ISABELLE_AIF_LENGTH_20;  		break; -	case SNDRV_PCM_FORMAT_S32_LE: +	case 32:  		aif |= ISABELLE_AIF_LENGTH_32;  		break;  	default: @@ -1082,23 +1089,7 @@ static struct snd_soc_dai_driver isabelle_dai[] = {  	},  }; -static int isabelle_probe(struct snd_soc_codec *codec) -{ -	int ret = 0; - -	codec->control_data = dev_get_regmap(codec->dev, NULL); - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	return 0; -} -  static struct snd_soc_codec_driver soc_codec_dev_isabelle = { -	.probe = isabelle_probe,  	.set_bias_level = isabelle_set_bias_level,  	.controls = isabelle_snd_controls,  	.num_controls = ARRAY_SIZE(isabelle_snd_controls), diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 0e5743ea79d..a924bb9d788 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -49,7 +49,7 @@ static const struct reg_default lm4857_default_regs[] = {  static int lm4857_get_mode(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = lm4857->mode; @@ -60,7 +60,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol,  static int lm4857_set_mode(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);  	uint8_t value = ucontrol->value.integer.value[0]; @@ -101,8 +101,7 @@ static const char *lm4857_mode[] = {  	"Headphone",  }; -static const struct soc_enum lm4857_mode_enum = -	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode); +static SOC_ENUM_SINGLE_EXT_DECL(lm4857_mode_enum, lm4857_mode);  static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {  	SND_SOC_DAPM_INPUT("IN"), diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index e19490cfb3a..275b3f72f3f 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -195,33 +195,31 @@ struct lm49453_priv {  static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"}; -static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, -				  lm49453_mic2mode_text); +static SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, +			    lm49453_mic2mode_text);  static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"}; -static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, -				  LM49453_P0_DIGITAL_MIC1_CONFIG_REG, -				  7, lm49453_dmic_cfg_text); +static SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, +			    LM49453_P0_DIGITAL_MIC1_CONFIG_REG, 7, +			    lm49453_dmic_cfg_text); -static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, -				  LM49453_P0_DIGITAL_MIC2_CONFIG_REG, -				  7, lm49453_dmic_cfg_text); +static SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, +			    LM49453_P0_DIGITAL_MIC2_CONFIG_REG, 7, +			    lm49453_dmic_cfg_text);  /* MUX Controls */  static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };  static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" }; -static const struct soc_enum lm49453_adcl_enum = -	SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 0, -			ARRAY_SIZE(lm49453_adcl_mux_text), -			lm49453_adcl_mux_text); +static SOC_ENUM_SINGLE_DECL(lm49453_adcl_enum, +			    LM49453_P0_ANALOG_MIXER_ADC_REG, 0, +			    lm49453_adcl_mux_text); -static const struct soc_enum lm49453_adcr_enum = -	SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 1, -			ARRAY_SIZE(lm49453_adcr_mux_text), -			lm49453_adcr_mux_text); +static SOC_ENUM_SINGLE_DECL(lm49453_adcr_enum, +			    LM49453_P0_ANALOG_MIXER_ADC_REG, 1, +			    lm49453_adcr_mux_text);  static const struct snd_kcontrol_new lm49453_adcl_mux_control =  	SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum); @@ -1409,22 +1407,6 @@ static int lm49453_resume(struct snd_soc_codec *codec)  	return 0;  } -static int lm49453_probe(struct snd_soc_codec *codec) -{ -	struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec); -	int ret = 0; - -	codec->control_data = lm49453->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	return 0; -} -  /* power down chip */  static int lm49453_remove(struct snd_soc_codec *codec)  { @@ -1433,7 +1415,6 @@ static int lm49453_remove(struct snd_soc_codec *codec)  }  static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { -	.probe = lm49453_probe,  	.remove = lm49453_remove,  	.suspend = lm49453_suspend,  	.resume = lm49453_resume, diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 31f91560e9f..e1c196a4193 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -43,7 +43,7 @@ static struct reg_default max9768_default_regs[] = {  static int max9768_get_gpio(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);  	int val = gpio_get_value_cansleep(max9768->mute_gpio); @@ -55,7 +55,7 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol,  static int max9768_set_gpio(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);  	gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]); @@ -135,11 +135,6 @@ static int max9768_probe(struct snd_soc_codec *codec)  	struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);  	int ret; -	codec->control_data = max9768->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 2, 6, SND_SOC_REGMAP); -	if (ret) -		return ret; -  	if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) {  		ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM);  		if (ret) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 566a367c94f..9134982807b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -15,6 +15,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -38,294 +39,223 @@ struct max98088_cdata {  };  struct max98088_priv { -       enum max98088_type devtype; -       struct max98088_pdata *pdata; -       unsigned int sysclk; -       struct max98088_cdata dai[2]; -       int eq_textcnt; -       const char **eq_texts; -       struct soc_enum eq_enum; -       u8 ina_state; -       u8 inb_state; -       unsigned int ex_mode; -       unsigned int digmic; -       unsigned int mic1pre; -       unsigned int mic2pre; -       unsigned int extmic_mode; +	struct regmap *regmap; +	enum max98088_type devtype; +	struct max98088_pdata *pdata; +	unsigned int sysclk; +	struct max98088_cdata dai[2]; +	int eq_textcnt; +	const char **eq_texts; +	struct soc_enum eq_enum; +	u8 ina_state; +	u8 inb_state; +	unsigned int ex_mode; +	unsigned int digmic; +	unsigned int mic1pre; +	unsigned int mic2pre; +	unsigned int extmic_mode;  }; -static const u8 max98088_reg[M98088_REG_CNT] = { -       0x00, /* 00 IRQ status */ -       0x00, /* 01 MIC status */ -       0x00, /* 02 jack status */ -       0x00, /* 03 battery voltage */ -       0x00, /* 04 */ -       0x00, /* 05 */ -       0x00, /* 06 */ -       0x00, /* 07 */ -       0x00, /* 08 */ -       0x00, /* 09 */ -       0x00, /* 0A */ -       0x00, /* 0B */ -       0x00, /* 0C */ -       0x00, /* 0D */ -       0x00, /* 0E */ -       0x00, /* 0F interrupt enable */ - -       0x00, /* 10 master clock */ -       0x00, /* 11 DAI1 clock mode */ -       0x00, /* 12 DAI1 clock control */ -       0x00, /* 13 DAI1 clock control */ -       0x00, /* 14 DAI1 format */ -       0x00, /* 15 DAI1 clock */ -       0x00, /* 16 DAI1 config */ -       0x00, /* 17 DAI1 TDM */ -       0x00, /* 18 DAI1 filters */ -       0x00, /* 19 DAI2 clock mode */ -       0x00, /* 1A DAI2 clock control */ -       0x00, /* 1B DAI2 clock control */ -       0x00, /* 1C DAI2 format */ -       0x00, /* 1D DAI2 clock */ -       0x00, /* 1E DAI2 config */ -       0x00, /* 1F DAI2 TDM */ - -       0x00, /* 20 DAI2 filters */ -       0x00, /* 21 data config */ -       0x00, /* 22 DAC mixer */ -       0x00, /* 23 left ADC mixer */ -       0x00, /* 24 right ADC mixer */ -       0x00, /* 25 left HP mixer */ -       0x00, /* 26 right HP mixer */ -       0x00, /* 27 HP control */ -       0x00, /* 28 left REC mixer */ -       0x00, /* 29 right REC mixer */ -       0x00, /* 2A REC control */ -       0x00, /* 2B left SPK mixer */ -       0x00, /* 2C right SPK mixer */ -       0x00, /* 2D SPK control */ -       0x00, /* 2E sidetone */ -       0x00, /* 2F DAI1 playback level */ - -       0x00, /* 30 DAI1 playback level */ -       0x00, /* 31 DAI2 playback level */ -       0x00, /* 32 DAI2 playbakc level */ -       0x00, /* 33 left ADC level */ -       0x00, /* 34 right ADC level */ -       0x00, /* 35 MIC1 level */ -       0x00, /* 36 MIC2 level */ -       0x00, /* 37 INA level */ -       0x00, /* 38 INB level */ -       0x00, /* 39 left HP volume */ -       0x00, /* 3A right HP volume */ -       0x00, /* 3B left REC volume */ -       0x00, /* 3C right REC volume */ -       0x00, /* 3D left SPK volume */ -       0x00, /* 3E right SPK volume */ -       0x00, /* 3F MIC config */ - -       0x00, /* 40 MIC threshold */ -       0x00, /* 41 excursion limiter filter */ -       0x00, /* 42 excursion limiter threshold */ -       0x00, /* 43 ALC */ -       0x00, /* 44 power limiter threshold */ -       0x00, /* 45 power limiter config */ -       0x00, /* 46 distortion limiter config */ -       0x00, /* 47 audio input */ -       0x00, /* 48 microphone */ -       0x00, /* 49 level control */ -       0x00, /* 4A bypass switches */ -       0x00, /* 4B jack detect */ -       0x00, /* 4C input enable */ -       0x00, /* 4D output enable */ -       0xF0, /* 4E bias control */ -       0x00, /* 4F DAC power */ - -       0x0F, /* 50 DAC power */ -       0x00, /* 51 system */ -       0x00, /* 52 DAI1 EQ1 */ -       0x00, /* 53 DAI1 EQ1 */ -       0x00, /* 54 DAI1 EQ1 */ -       0x00, /* 55 DAI1 EQ1 */ -       0x00, /* 56 DAI1 EQ1 */ -       0x00, /* 57 DAI1 EQ1 */ -       0x00, /* 58 DAI1 EQ1 */ -       0x00, /* 59 DAI1 EQ1 */ -       0x00, /* 5A DAI1 EQ1 */ -       0x00, /* 5B DAI1 EQ1 */ -       0x00, /* 5C DAI1 EQ2 */ -       0x00, /* 5D DAI1 EQ2 */ -       0x00, /* 5E DAI1 EQ2 */ -       0x00, /* 5F DAI1 EQ2 */ - -       0x00, /* 60 DAI1 EQ2 */ -       0x00, /* 61 DAI1 EQ2 */ -       0x00, /* 62 DAI1 EQ2 */ -       0x00, /* 63 DAI1 EQ2 */ -       0x00, /* 64 DAI1 EQ2 */ -       0x00, /* 65 DAI1 EQ2 */ -       0x00, /* 66 DAI1 EQ3 */ -       0x00, /* 67 DAI1 EQ3 */ -       0x00, /* 68 DAI1 EQ3 */ -       0x00, /* 69 DAI1 EQ3 */ -       0x00, /* 6A DAI1 EQ3 */ -       0x00, /* 6B DAI1 EQ3 */ -       0x00, /* 6C DAI1 EQ3 */ -       0x00, /* 6D DAI1 EQ3 */ -       0x00, /* 6E DAI1 EQ3 */ -       0x00, /* 6F DAI1 EQ3 */ - -       0x00, /* 70 DAI1 EQ4 */ -       0x00, /* 71 DAI1 EQ4 */ -       0x00, /* 72 DAI1 EQ4 */ -       0x00, /* 73 DAI1 EQ4 */ -       0x00, /* 74 DAI1 EQ4 */ -       0x00, /* 75 DAI1 EQ4 */ -       0x00, /* 76 DAI1 EQ4 */ -       0x00, /* 77 DAI1 EQ4 */ -       0x00, /* 78 DAI1 EQ4 */ -       0x00, /* 79 DAI1 EQ4 */ -       0x00, /* 7A DAI1 EQ5 */ -       0x00, /* 7B DAI1 EQ5 */ -       0x00, /* 7C DAI1 EQ5 */ -       0x00, /* 7D DAI1 EQ5 */ -       0x00, /* 7E DAI1 EQ5 */ -       0x00, /* 7F DAI1 EQ5 */ - -       0x00, /* 80 DAI1 EQ5 */ -       0x00, /* 81 DAI1 EQ5 */ -       0x00, /* 82 DAI1 EQ5 */ -       0x00, /* 83 DAI1 EQ5 */ -       0x00, /* 84 DAI2 EQ1 */ -       0x00, /* 85 DAI2 EQ1 */ -       0x00, /* 86 DAI2 EQ1 */ -       0x00, /* 87 DAI2 EQ1 */ -       0x00, /* 88 DAI2 EQ1 */ -       0x00, /* 89 DAI2 EQ1 */ -       0x00, /* 8A DAI2 EQ1 */ -       0x00, /* 8B DAI2 EQ1 */ -       0x00, /* 8C DAI2 EQ1 */ -       0x00, /* 8D DAI2 EQ1 */ -       0x00, /* 8E DAI2 EQ2 */ -       0x00, /* 8F DAI2 EQ2 */ - -       0x00, /* 90 DAI2 EQ2 */ -       0x00, /* 91 DAI2 EQ2 */ -       0x00, /* 92 DAI2 EQ2 */ -       0x00, /* 93 DAI2 EQ2 */ -       0x00, /* 94 DAI2 EQ2 */ -       0x00, /* 95 DAI2 EQ2 */ -       0x00, /* 96 DAI2 EQ2 */ -       0x00, /* 97 DAI2 EQ2 */ -       0x00, /* 98 DAI2 EQ3 */ -       0x00, /* 99 DAI2 EQ3 */ -       0x00, /* 9A DAI2 EQ3 */ -       0x00, /* 9B DAI2 EQ3 */ -       0x00, /* 9C DAI2 EQ3 */ -       0x00, /* 9D DAI2 EQ3 */ -       0x00, /* 9E DAI2 EQ3 */ -       0x00, /* 9F DAI2 EQ3 */ - -       0x00, /* A0 DAI2 EQ3 */ -       0x00, /* A1 DAI2 EQ3 */ -       0x00, /* A2 DAI2 EQ4 */ -       0x00, /* A3 DAI2 EQ4 */ -       0x00, /* A4 DAI2 EQ4 */ -       0x00, /* A5 DAI2 EQ4 */ -       0x00, /* A6 DAI2 EQ4 */ -       0x00, /* A7 DAI2 EQ4 */ -       0x00, /* A8 DAI2 EQ4 */ -       0x00, /* A9 DAI2 EQ4 */ -       0x00, /* AA DAI2 EQ4 */ -       0x00, /* AB DAI2 EQ4 */ -       0x00, /* AC DAI2 EQ5 */ -       0x00, /* AD DAI2 EQ5 */ -       0x00, /* AE DAI2 EQ5 */ -       0x00, /* AF DAI2 EQ5 */ - -       0x00, /* B0 DAI2 EQ5 */ -       0x00, /* B1 DAI2 EQ5 */ -       0x00, /* B2 DAI2 EQ5 */ -       0x00, /* B3 DAI2 EQ5 */ -       0x00, /* B4 DAI2 EQ5 */ -       0x00, /* B5 DAI2 EQ5 */ -       0x00, /* B6 DAI1 biquad */ -       0x00, /* B7 DAI1 biquad */ -       0x00, /* B8 DAI1 biquad */ -       0x00, /* B9 DAI1 biquad */ -       0x00, /* BA DAI1 biquad */ -       0x00, /* BB DAI1 biquad */ -       0x00, /* BC DAI1 biquad */ -       0x00, /* BD DAI1 biquad */ -       0x00, /* BE DAI1 biquad */ -       0x00, /* BF DAI1 biquad */ - -       0x00, /* C0 DAI2 biquad */ -       0x00, /* C1 DAI2 biquad */ -       0x00, /* C2 DAI2 biquad */ -       0x00, /* C3 DAI2 biquad */ -       0x00, /* C4 DAI2 biquad */ -       0x00, /* C5 DAI2 biquad */ -       0x00, /* C6 DAI2 biquad */ -       0x00, /* C7 DAI2 biquad */ -       0x00, /* C8 DAI2 biquad */ -       0x00, /* C9 DAI2 biquad */ -       0x00, /* CA */ -       0x00, /* CB */ -       0x00, /* CC */ -       0x00, /* CD */ -       0x00, /* CE */ -       0x00, /* CF */ - -       0x00, /* D0 */ -       0x00, /* D1 */ -       0x00, /* D2 */ -       0x00, /* D3 */ -       0x00, /* D4 */ -       0x00, /* D5 */ -       0x00, /* D6 */ -       0x00, /* D7 */ -       0x00, /* D8 */ -       0x00, /* D9 */ -       0x00, /* DA */ -       0x70, /* DB */ -       0x00, /* DC */ -       0x00, /* DD */ -       0x00, /* DE */ -       0x00, /* DF */ - -       0x00, /* E0 */ -       0x00, /* E1 */ -       0x00, /* E2 */ -       0x00, /* E3 */ -       0x00, /* E4 */ -       0x00, /* E5 */ -       0x00, /* E6 */ -       0x00, /* E7 */ -       0x00, /* E8 */ -       0x00, /* E9 */ -       0x00, /* EA */ -       0x00, /* EB */ -       0x00, /* EC */ -       0x00, /* ED */ -       0x00, /* EE */ -       0x00, /* EF */ - -       0x00, /* F0 */ -       0x00, /* F1 */ -       0x00, /* F2 */ -       0x00, /* F3 */ -       0x00, /* F4 */ -       0x00, /* F5 */ -       0x00, /* F6 */ -       0x00, /* F7 */ -       0x00, /* F8 */ -       0x00, /* F9 */ -       0x00, /* FA */ -       0x00, /* FB */ -       0x00, /* FC */ -       0x00, /* FD */ -       0x00, /* FE */ -       0x00, /* FF */ +static const struct reg_default max98088_reg[] = { +	{  0xf, 0x00 }, /* 0F interrupt enable */ + +	{ 0x10, 0x00 }, /* 10 master clock */ +	{ 0x11, 0x00 }, /* 11 DAI1 clock mode */ +	{ 0x12, 0x00 }, /* 12 DAI1 clock control */ +	{ 0x13, 0x00 }, /* 13 DAI1 clock control */ +	{ 0x14, 0x00 }, /* 14 DAI1 format */ +	{ 0x15, 0x00 }, /* 15 DAI1 clock */ +	{ 0x16, 0x00 }, /* 16 DAI1 config */ +	{ 0x17, 0x00 }, /* 17 DAI1 TDM */ +	{ 0x18, 0x00 }, /* 18 DAI1 filters */ +	{ 0x19, 0x00 }, /* 19 DAI2 clock mode */ +	{ 0x1a, 0x00 }, /* 1A DAI2 clock control */ +	{ 0x1b, 0x00 }, /* 1B DAI2 clock control */ +	{ 0x1c, 0x00 }, /* 1C DAI2 format */ +	{ 0x1d, 0x00 }, /* 1D DAI2 clock */ +	{ 0x1e, 0x00 }, /* 1E DAI2 config */ +	{ 0x1f, 0x00 }, /* 1F DAI2 TDM */ + +	{ 0x20, 0x00 }, /* 20 DAI2 filters */ +	{ 0x21, 0x00 }, /* 21 data config */ +	{ 0x22, 0x00 }, /* 22 DAC mixer */ +	{ 0x23, 0x00 }, /* 23 left ADC mixer */ +	{ 0x24, 0x00 }, /* 24 right ADC mixer */ +	{ 0x25, 0x00 }, /* 25 left HP mixer */ +	{ 0x26, 0x00 }, /* 26 right HP mixer */ +	{ 0x27, 0x00 }, /* 27 HP control */ +	{ 0x28, 0x00 }, /* 28 left REC mixer */ +	{ 0x29, 0x00 }, /* 29 right REC mixer */ +	{ 0x2a, 0x00 }, /* 2A REC control */ +	{ 0x2b, 0x00 }, /* 2B left SPK mixer */ +	{ 0x2c, 0x00 }, /* 2C right SPK mixer */ +	{ 0x2d, 0x00 }, /* 2D SPK control */ +	{ 0x2e, 0x00 }, /* 2E sidetone */ +	{ 0x2f, 0x00 }, /* 2F DAI1 playback level */ + +	{ 0x30, 0x00 }, /* 30 DAI1 playback level */ +	{ 0x31, 0x00 }, /* 31 DAI2 playback level */ +	{ 0x32, 0x00 }, /* 32 DAI2 playbakc level */ +	{ 0x33, 0x00 }, /* 33 left ADC level */ +	{ 0x34, 0x00 }, /* 34 right ADC level */ +	{ 0x35, 0x00 }, /* 35 MIC1 level */ +	{ 0x36, 0x00 }, /* 36 MIC2 level */ +	{ 0x37, 0x00 }, /* 37 INA level */ +	{ 0x38, 0x00 }, /* 38 INB level */ +	{ 0x39, 0x00 }, /* 39 left HP volume */ +	{ 0x3a, 0x00 }, /* 3A right HP volume */ +	{ 0x3b, 0x00 }, /* 3B left REC volume */ +	{ 0x3c, 0x00 }, /* 3C right REC volume */ +	{ 0x3d, 0x00 }, /* 3D left SPK volume */ +	{ 0x3e, 0x00 }, /* 3E right SPK volume */ +	{ 0x3f, 0x00 }, /* 3F MIC config */ + +	{ 0x40, 0x00 }, /* 40 MIC threshold */ +	{ 0x41, 0x00 }, /* 41 excursion limiter filter */ +	{ 0x42, 0x00 }, /* 42 excursion limiter threshold */ +	{ 0x43, 0x00 }, /* 43 ALC */ +	{ 0x44, 0x00 }, /* 44 power limiter threshold */ +	{ 0x45, 0x00 }, /* 45 power limiter config */ +	{ 0x46, 0x00 }, /* 46 distortion limiter config */ +	{ 0x47, 0x00 }, /* 47 audio input */ +        { 0x48, 0x00 }, /* 48 microphone */ +	{ 0x49, 0x00 }, /* 49 level control */ +	{ 0x4a, 0x00 }, /* 4A bypass switches */ +	{ 0x4b, 0x00 }, /* 4B jack detect */ +	{ 0x4c, 0x00 }, /* 4C input enable */ +	{ 0x4d, 0x00 }, /* 4D output enable */ +	{ 0x4e, 0xF0 }, /* 4E bias control */ +	{ 0x4f, 0x00 }, /* 4F DAC power */ + +	{ 0x50, 0x0F }, /* 50 DAC power */ +	{ 0x51, 0x00 }, /* 51 system */ +	{ 0x52, 0x00 }, /* 52 DAI1 EQ1 */ +	{ 0x53, 0x00 }, /* 53 DAI1 EQ1 */ +	{ 0x54, 0x00 }, /* 54 DAI1 EQ1 */ +	{ 0x55, 0x00 }, /* 55 DAI1 EQ1 */ +	{ 0x56, 0x00 }, /* 56 DAI1 EQ1 */ +	{ 0x57, 0x00 }, /* 57 DAI1 EQ1 */ +	{ 0x58, 0x00 }, /* 58 DAI1 EQ1 */ +	{ 0x59, 0x00 }, /* 59 DAI1 EQ1 */ +	{ 0x5a, 0x00 }, /* 5A DAI1 EQ1 */ +	{ 0x5b, 0x00 }, /* 5B DAI1 EQ1 */ +	{ 0x5c, 0x00 }, /* 5C DAI1 EQ2 */ +	{ 0x5d, 0x00 }, /* 5D DAI1 EQ2 */ +	{ 0x5e, 0x00 }, /* 5E DAI1 EQ2 */ +	{ 0x5f, 0x00 }, /* 5F DAI1 EQ2 */ + +	{ 0x60, 0x00 }, /* 60 DAI1 EQ2 */ +	{ 0x61, 0x00 }, /* 61 DAI1 EQ2 */ +	{ 0x62, 0x00 }, /* 62 DAI1 EQ2 */ +	{ 0x63, 0x00 }, /* 63 DAI1 EQ2 */ +	{ 0x64, 0x00 }, /* 64 DAI1 EQ2 */ +	{ 0x65, 0x00 }, /* 65 DAI1 EQ2 */ +	{ 0x66, 0x00 }, /* 66 DAI1 EQ3 */ +	{ 0x67, 0x00 }, /* 67 DAI1 EQ3 */ +	{ 0x68, 0x00 }, /* 68 DAI1 EQ3 */ +	{ 0x69, 0x00 }, /* 69 DAI1 EQ3 */ +	{ 0x6a, 0x00 }, /* 6A DAI1 EQ3 */ +	{ 0x6b, 0x00 }, /* 6B DAI1 EQ3 */ +	{ 0x6c, 0x00 }, /* 6C DAI1 EQ3 */ +	{ 0x6d, 0x00 }, /* 6D DAI1 EQ3 */ +	{ 0x6e, 0x00 }, /* 6E DAI1 EQ3 */ +	{ 0x6f, 0x00 }, /* 6F DAI1 EQ3 */ + +	{ 0x70, 0x00 }, /* 70 DAI1 EQ4 */ +	{ 0x71, 0x00 }, /* 71 DAI1 EQ4 */ +	{ 0x72, 0x00 }, /* 72 DAI1 EQ4 */ +	{ 0x73, 0x00 }, /* 73 DAI1 EQ4 */ +	{ 0x74, 0x00 }, /* 74 DAI1 EQ4 */ +	{ 0x75, 0x00 }, /* 75 DAI1 EQ4 */ +	{ 0x76, 0x00 }, /* 76 DAI1 EQ4 */ +	{ 0x77, 0x00 }, /* 77 DAI1 EQ4 */ +	{ 0x78, 0x00 }, /* 78 DAI1 EQ4 */ +	{ 0x79, 0x00 }, /* 79 DAI1 EQ4 */ +	{ 0x7a, 0x00 }, /* 7A DAI1 EQ5 */ +	{ 0x7b, 0x00 }, /* 7B DAI1 EQ5 */ +	{ 0x7c, 0x00 }, /* 7C DAI1 EQ5 */ +	{ 0x7d, 0x00 }, /* 7D DAI1 EQ5 */ +	{ 0x7e, 0x00 }, /* 7E DAI1 EQ5 */ +	{ 0x7f, 0x00 }, /* 7F DAI1 EQ5 */ + +	{ 0x80, 0x00 }, /* 80 DAI1 EQ5 */ +	{ 0x81, 0x00 }, /* 81 DAI1 EQ5 */ +	{ 0x82, 0x00 }, /* 82 DAI1 EQ5 */ +	{ 0x83, 0x00 }, /* 83 DAI1 EQ5 */ +	{ 0x84, 0x00 }, /* 84 DAI2 EQ1 */ +	{ 0x85, 0x00 }, /* 85 DAI2 EQ1 */ +	{ 0x86, 0x00 }, /* 86 DAI2 EQ1 */ +	{ 0x87, 0x00 }, /* 87 DAI2 EQ1 */ +	{ 0x88, 0x00 }, /* 88 DAI2 EQ1 */ +	{ 0x89, 0x00 }, /* 89 DAI2 EQ1 */ +	{ 0x8a, 0x00 }, /* 8A DAI2 EQ1 */ +	{ 0x8b, 0x00 }, /* 8B DAI2 EQ1 */ +	{ 0x8c, 0x00 }, /* 8C DAI2 EQ1 */ +	{ 0x8d, 0x00 }, /* 8D DAI2 EQ1 */ +	{ 0x8e, 0x00 }, /* 8E DAI2 EQ2 */ +	{ 0x8f, 0x00 }, /* 8F DAI2 EQ2 */ + +	{ 0x90, 0x00 }, /* 90 DAI2 EQ2 */ +	{ 0x91, 0x00 }, /* 91 DAI2 EQ2 */ +	{ 0x92, 0x00 }, /* 92 DAI2 EQ2 */ +	{ 0x93, 0x00 }, /* 93 DAI2 EQ2 */ +	{ 0x94, 0x00 }, /* 94 DAI2 EQ2 */ +	{ 0x95, 0x00 }, /* 95 DAI2 EQ2 */ +	{ 0x96, 0x00 }, /* 96 DAI2 EQ2 */ +	{ 0x97, 0x00 }, /* 97 DAI2 EQ2 */ +	{ 0x98, 0x00 }, /* 98 DAI2 EQ3 */ +	{ 0x99, 0x00 }, /* 99 DAI2 EQ3 */ +	{ 0x9a, 0x00 }, /* 9A DAI2 EQ3 */ +        { 0x9b, 0x00 }, /* 9B DAI2 EQ3 */ +	{ 0x9c, 0x00 }, /* 9C DAI2 EQ3 */ +	{ 0x9d, 0x00 }, /* 9D DAI2 EQ3 */ +	{ 0x9e, 0x00 }, /* 9E DAI2 EQ3 */ +	{ 0x9f, 0x00 }, /* 9F DAI2 EQ3 */ + +	{ 0xa0, 0x00 }, /* A0 DAI2 EQ3 */ +	{ 0xa1, 0x00 }, /* A1 DAI2 EQ3 */ +	{ 0xa2, 0x00 }, /* A2 DAI2 EQ4 */ +	{ 0xa3, 0x00 }, /* A3 DAI2 EQ4 */ +	{ 0xa4, 0x00 }, /* A4 DAI2 EQ4 */ +	{ 0xa5, 0x00 }, /* A5 DAI2 EQ4 */ +	{ 0xa6, 0x00 }, /* A6 DAI2 EQ4 */ +	{ 0xa7, 0x00 }, /* A7 DAI2 EQ4 */ +	{ 0xa8, 0x00 }, /* A8 DAI2 EQ4 */ +	{ 0xa9, 0x00 }, /* A9 DAI2 EQ4 */ +	{ 0xaa, 0x00 }, /* AA DAI2 EQ4 */ +	{ 0xab, 0x00 }, /* AB DAI2 EQ4 */ +	{ 0xac, 0x00 }, /* AC DAI2 EQ5 */ +	{ 0xad, 0x00 }, /* AD DAI2 EQ5 */ +	{ 0xae, 0x00 }, /* AE DAI2 EQ5 */ +	{ 0xaf, 0x00 }, /* AF DAI2 EQ5 */ + +	{ 0xb0, 0x00 }, /* B0 DAI2 EQ5 */ +	{ 0xb1, 0x00 }, /* B1 DAI2 EQ5 */ +	{ 0xb2, 0x00 }, /* B2 DAI2 EQ5 */ +	{ 0xb3, 0x00 }, /* B3 DAI2 EQ5 */ +	{ 0xb4, 0x00 }, /* B4 DAI2 EQ5 */ +	{ 0xb5, 0x00 }, /* B5 DAI2 EQ5 */ +	{ 0xb6, 0x00 }, /* B6 DAI1 biquad */ +	{ 0xb7, 0x00 }, /* B7 DAI1 biquad */ +	{ 0xb8 ,0x00 }, /* B8 DAI1 biquad */ +	{ 0xb9, 0x00 }, /* B9 DAI1 biquad */ +	{ 0xba, 0x00 }, /* BA DAI1 biquad */ +	{ 0xbb, 0x00 }, /* BB DAI1 biquad */ +	{ 0xbc, 0x00 }, /* BC DAI1 biquad */ +	{ 0xbd, 0x00 }, /* BD DAI1 biquad */ +	{ 0xbe, 0x00 }, /* BE DAI1 biquad */ +        { 0xbf, 0x00 }, /* BF DAI1 biquad */ + +	{ 0xc0, 0x00 }, /* C0 DAI2 biquad */ +	{ 0xc1, 0x00 }, /* C1 DAI2 biquad */ +	{ 0xc2, 0x00 }, /* C2 DAI2 biquad */ +	{ 0xc3, 0x00 }, /* C3 DAI2 biquad */ +	{ 0xc4, 0x00 }, /* C4 DAI2 biquad */ +	{ 0xc5, 0x00 }, /* C5 DAI2 biquad */ +	{ 0xc6, 0x00 }, /* C6 DAI2 biquad */ +	{ 0xc7, 0x00 }, /* C7 DAI2 biquad */ +	{ 0xc8, 0x00 }, /* C8 DAI2 biquad */ +	{ 0xc9, 0x00 }, /* C9 DAI2 biquad */  };  static struct { @@ -606,11 +536,28 @@ static struct {         { 0xFF, 0x00, 1 }, /* FF */  }; -static int max98088_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +static bool max98088_readable_register(struct device *dev, unsigned int reg) +{ +       return max98088_access[reg].readable; +} + +static bool max98088_volatile_register(struct device *dev, unsigned int reg)  {         return max98088_access[reg].vol;  } +static const struct regmap_config max98088_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.readable_reg = max98088_readable_register, +	.volatile_reg = max98088_volatile_register, +	.max_register = 0xff, + +	.reg_defaults = max98088_reg, +	.num_reg_defaults = ARRAY_SIZE(max98088_reg), +	.cache_type = REGCACHE_RBTREE, +};  /*   * Load equalizer DSP coefficient configurations registers @@ -621,8 +568,9 @@ static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,         unsigned int eq_reg;         unsigned int i; -       BUG_ON(band > 4); -       BUG_ON(dai > 1); +	if (WARN_ON(band > 4) || +	    WARN_ON(dai > 1)) +		return;         /* Load the base register address */         eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE; @@ -649,28 +597,27 @@ static const unsigned int max98088_exmode_values[] = {         0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32  }; -static const struct soc_enum max98088_exmode_enum = -       SOC_VALUE_ENUM_SINGLE(M98088_REG_41_SPKDHP, 0, 127, -                             ARRAY_SIZE(max98088_exmode_texts), -                             max98088_exmode_texts, -                             max98088_exmode_values); +static SOC_VALUE_ENUM_SINGLE_DECL(max98088_exmode_enum, +				  M98088_REG_41_SPKDHP, 0, 127, +				  max98088_exmode_texts, +				  max98088_exmode_values);  static const char *max98088_ex_thresh[] = { /* volts PP */         "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"}; -static const struct soc_enum max98088_ex_thresh_enum[] = { -       SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8, -               max98088_ex_thresh), -}; +static SOC_ENUM_SINGLE_DECL(max98088_ex_thresh_enum, +			    M98088_REG_42_SPKDHP_THRESH, 0, +			    max98088_ex_thresh);  static const char *max98088_fltr_mode[] = {"Voice", "Music" }; -static const struct soc_enum max98088_filter_mode_enum[] = { -       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode), -}; +static SOC_ENUM_SINGLE_DECL(max98088_filter_mode_enum, +			    M98088_REG_18_DAI1_FILTERS, 7, +			    max98088_fltr_mode);  static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" }; -static const struct soc_enum max98088_extmic_enum = -       SOC_ENUM_SINGLE(M98088_REG_48_CFG_MIC, 0, 3, max98088_extmic_text); +static SOC_ENUM_SINGLE_DECL(max98088_extmic_enum, +			    M98088_REG_48_CFG_MIC, 0, +			    max98088_extmic_text);  static const struct snd_kcontrol_new max98088_extmic_mux =         SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum); @@ -678,17 +625,17 @@ static const struct snd_kcontrol_new max98088_extmic_mux =  static const char *max98088_dai1_fltr[] = {         "Off", "fc=258/fs=16k", "fc=500/fs=16k",         "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"}; -static const struct soc_enum max98088_dai1_dac_filter_enum[] = { -       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr), -}; -static const struct soc_enum max98088_dai1_adc_filter_enum[] = { -       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr), -}; +static SOC_ENUM_SINGLE_DECL(max98088_dai1_dac_filter_enum, +			    M98088_REG_18_DAI1_FILTERS, 0, +			    max98088_dai1_fltr); +static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum, +			    M98088_REG_18_DAI1_FILTERS, 4, +			    max98088_dai1_fltr);  static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,                                 struct snd_ctl_elem_value *ucontrol)  { -       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);         struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);         unsigned int sel = ucontrol->value.integer.value[0]; @@ -702,7 +649,7 @@ static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,  static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,                                 struct snd_ctl_elem_value *ucontrol)  { -       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);         struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);         ucontrol->value.integer.value[0] = max98088->mic1pre; @@ -712,7 +659,7 @@ static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,  static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,                                 struct snd_ctl_elem_value *ucontrol)  { -       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);         struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);         unsigned int sel = ucontrol->value.integer.value[0]; @@ -726,7 +673,7 @@ static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,  static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,                                 struct snd_ctl_elem_value *ucontrol)  { -       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);         struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);         ucontrol->value.integer.value[0] = max98088->mic2pre; @@ -962,7 +909,8 @@ static int max98088_line_pga(struct snd_soc_dapm_widget *w,         struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);         u8 *state; -       BUG_ON(!((channel == 1) || (channel == 2))); +	if (WARN_ON(!(channel == 1 || channel == 2))) +		return -EINVAL;         switch (line) {         case LINE_INA: @@ -1284,12 +1232,12 @@ static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,         rate = params_rate(params); -       switch (params_format(params)) { -       case SNDRV_PCM_FORMAT_S16_LE: +       switch (params_width(params)) { +       case 16:                 snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,                         M98088_DAI_WS, 0);                 break; -       case SNDRV_PCM_FORMAT_S24_LE: +       case 24:                 snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,                         M98088_DAI_WS, M98088_DAI_WS);                 break; @@ -1610,58 +1558,34 @@ static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)         return 0;  } -static void max98088_sync_cache(struct snd_soc_codec *codec) -{ -       u8 *reg_cache = codec->reg_cache; -       int i; - -       if (!codec->cache_sync) -               return; - -       codec->cache_only = 0; - -       /* write back cached values if they're writeable and -        * different from the hardware default. -        */ -       for (i = 1; i < codec->driver->reg_cache_size; i++) { -               if (!max98088_access[i].writable) -                       continue; - -               if (reg_cache[i] == max98088_reg[i]) -                       continue; - -               snd_soc_write(codec, i, reg_cache[i]); -       } - -       codec->cache_sync = 0; -} -  static int max98088_set_bias_level(struct snd_soc_codec *codec,                                    enum snd_soc_bias_level level)  { -       switch (level) { -       case SND_SOC_BIAS_ON: -               break; - -       case SND_SOC_BIAS_PREPARE: -               break; - -       case SND_SOC_BIAS_STANDBY: -               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) -                       max98088_sync_cache(codec); - -               snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, -                               M98088_MBEN, M98088_MBEN); -               break; - -       case SND_SOC_BIAS_OFF: -               snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, -                               M98088_MBEN, 0); -               codec->cache_sync = 1; -               break; -       } -       codec->dapm.bias_level = level; -       return 0; +	struct max98088_priv *max98088 = 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: +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) +			regcache_sync(max98088->regmap); + +		snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, +				   M98088_MBEN, M98088_MBEN); +		break; + +	case SND_SOC_BIAS_OFF: +		snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, +				    M98088_MBEN, 0); +		regcache_mark_dirty(max98088->regmap); +		break; +	} +	codec->dapm.bias_level = level; +	return 0;  }  #define MAX98088_RATES SNDRV_PCM_RATE_8000_96000 @@ -1826,7 +1750,7 @@ static void max98088_setup_eq2(struct snd_soc_codec *codec)  static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,                                  struct snd_ctl_elem_value *ucontrol)  { -       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);         struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);         struct max98088_pdata *pdata = max98088->pdata;         int channel = max98088_get_channel(codec, kcontrol->id.name); @@ -1858,7 +1782,7 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,  static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,                                  struct snd_ctl_elem_value *ucontrol)  { -       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);         struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);         int channel = max98088_get_channel(codec, kcontrol->id.name);         struct max98088_cdata *cdata; @@ -1924,7 +1848,7 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)         /* Now point the soc_enum to .texts array items */         max98088->eq_enum.texts = max98088->eq_texts; -       max98088->eq_enum.max = max98088->eq_textcnt; +       max98088->eq_enum.items = max98088->eq_textcnt;         ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));         if (ret != 0) @@ -1988,13 +1912,7 @@ static int max98088_probe(struct snd_soc_codec *codec)         struct max98088_cdata *cdata;         int ret = 0; -       codec->cache_sync = 1; - -       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); -       if (ret != 0) { -               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -               return ret; -       } +       regcache_mark_dirty(max98088->regmap);         /* initialize private data */ @@ -2048,9 +1966,6 @@ static int max98088_probe(struct snd_soc_codec *codec)         max98088_handle_pdata(codec); -       snd_soc_add_codec_controls(codec, max98088_snd_controls, -                            ARRAY_SIZE(max98088_snd_controls)); -  err_access:         return ret;  } @@ -2066,15 +1981,13 @@ static int max98088_remove(struct snd_soc_codec *codec)  }  static struct snd_soc_codec_driver soc_codec_dev_max98088 = { -       .probe   = max98088_probe, -       .remove  = max98088_remove, -       .suspend = max98088_suspend, -       .resume  = max98088_resume, -       .set_bias_level = max98088_set_bias_level, -       .reg_cache_size = ARRAY_SIZE(max98088_reg), -       .reg_word_size = sizeof(u8), -       .reg_cache_default = max98088_reg, -       .volatile_register = max98088_volatile_register, +	.probe   = max98088_probe, +	.remove  = max98088_remove, +	.suspend = max98088_suspend, +	.resume  = max98088_resume, +	.set_bias_level = max98088_set_bias_level, +	.controls = max98088_snd_controls, +	.num_controls = ARRAY_SIZE(max98088_snd_controls),  	.dapm_widgets = max98088_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),  	.dapm_routes = max98088_audio_map, @@ -2082,7 +1995,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {  };  static int max98088_i2c_probe(struct i2c_client *i2c, -                            const struct i2c_device_id *id) +			      const struct i2c_device_id *id)  {         struct max98088_priv *max98088;         int ret; @@ -2092,6 +2005,10 @@ static int max98088_i2c_probe(struct i2c_client *i2c,         if (max98088 == NULL)                 return -ENOMEM; +       max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap); +       if (IS_ERR(max98088->regmap)) +	       return PTR_ERR(max98088->regmap); +         max98088->devtype = id->driver_data;         i2c_set_clientdata(i2c, max98088); diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 0569a4c3ae0..f5fccc7a8e8 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -11,10 +11,13 @@  #include <linux/delay.h>  #include <linux/i2c.h>  #include <linux/module.h> +#include <linux/of.h>  #include <linux/pm.h>  #include <linux/pm_runtime.h>  #include <linux/regmap.h>  #include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/clk.h>  #include <sound/jack.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -255,6 +258,7 @@ static struct reg_default max98090_reg[] = {  static bool max98090_volatile_register(struct device *dev, unsigned int reg)  {  	switch (reg) { +	case M98090_REG_SOFTWARE_RESET:  	case M98090_REG_DEVICE_STATUS:  	case M98090_REG_JACK_STATUS:  	case M98090_REG_REVISION_ID: @@ -336,6 +340,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg)  	case M98090_REG_RECORD_TDM_SLOT:  	case M98090_REG_SAMPLE_RATE:  	case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: +	case M98090_REG_REVISION_ID:  		return true;  	default:  		return false; @@ -388,6 +393,7 @@ static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0);  static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0);  static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0);  static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); +static const DECLARE_TLV_DB_SCALE(max98090_sdg_tlv, 50, 200, 0);  static const unsigned int max98090_mixout_tlv[] = {  	TLV_DB_RANGE_HEAD(2), @@ -425,7 +431,7 @@ static const unsigned int max98090_rcv_lout_tlv[] = {  static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; @@ -465,7 +471,7 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,  static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; @@ -512,65 +518,75 @@ static const char *max98090_perf_pwr_text[] =  static const char *max98090_pwr_perf_text[] =  	{ "Low Power", "High Performance" }; -static const struct soc_enum max98090_vcmbandgap_enum = -	SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT, -		ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); +static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum, +			    M98090_REG_BIAS_CONTROL, +			    M98090_VCM_MODE_SHIFT, +			    max98090_pwr_perf_text);  static const char *max98090_osr128_text[] = { "64*fs", "128*fs" }; -static const struct soc_enum max98090_osr128_enum = -	SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT, -		ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text); +static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum, +			    M98090_REG_ADC_CONTROL, +			    M98090_OSR128_SHIFT, +			    max98090_osr128_text);  static const char *max98090_mode_text[] = { "Voice", "Music" }; -static const struct soc_enum max98090_mode_enum = -	SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT, -		ARRAY_SIZE(max98090_mode_text), max98090_mode_text); +static SOC_ENUM_SINGLE_DECL(max98090_mode_enum, +			    M98090_REG_FILTER_CONFIG, +			    M98090_MODE_SHIFT, +			    max98090_mode_text); -static const struct soc_enum max98090_filter_dmic34mode_enum = -	SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, -		M98090_FLT_DMIC34MODE_SHIFT, -		ARRAY_SIZE(max98090_mode_text), max98090_mode_text); +static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum, +			    M98090_REG_FILTER_CONFIG, +			    M98090_FLT_DMIC34MODE_SHIFT, +			    max98090_mode_text);  static const char *max98090_drcatk_text[] =  	{ "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; -static const struct soc_enum max98090_drcatk_enum = -	SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT, -		ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text); +static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum, +			    M98090_REG_DRC_TIMING, +			    M98090_DRCATK_SHIFT, +			    max98090_drcatk_text);  static const char *max98090_drcrls_text[] =  	{ "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; -static const struct soc_enum max98090_drcrls_enum = -	SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT, -		ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text); +static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum, +			    M98090_REG_DRC_TIMING, +			    M98090_DRCRLS_SHIFT, +			    max98090_drcrls_text);  static const char *max98090_alccmp_text[] =  	{ "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; -static const struct soc_enum max98090_alccmp_enum = -	SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT, -		ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text); +static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum, +			    M98090_REG_DRC_COMPRESSOR, +			    M98090_DRCCMP_SHIFT, +			    max98090_alccmp_text);  static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; -static const struct soc_enum max98090_drcexp_enum = -	SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT, -		ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text); +static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum, +			    M98090_REG_DRC_EXPANDER, +			    M98090_DRCEXP_SHIFT, +			    max98090_drcexp_text); -static const struct soc_enum max98090_dac_perfmode_enum = -	SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT, -		ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text); +static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum, +			    M98090_REG_DAC_CONTROL, +			    M98090_PERFMODE_SHIFT, +			    max98090_perf_pwr_text); -static const struct soc_enum max98090_dachp_enum = -	SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT, -		ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); +static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum, +			    M98090_REG_DAC_CONTROL, +			    M98090_DACHP_SHIFT, +			    max98090_pwr_perf_text); -static const struct soc_enum max98090_adchp_enum = -	SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT, -		ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); +static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum, +			    M98090_REG_ADC_CONTROL, +			    M98090_ADCHP_SHIFT, +			    max98090_pwr_perf_text);  static const struct snd_kcontrol_new max98090_snd_controls[] = {  	SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), @@ -654,7 +670,7 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = {  	SOC_SINGLE_EXT_TLV("Digital Sidetone Volume",  		M98090_REG_ADC_SIDETONE, M98090_DVST_SHIFT,  		M98090_DVST_NUM - 1, 1, max98090_get_enab_tlv, -		max98090_put_enab_tlv, max98090_micboost_tlv), +		max98090_put_enab_tlv, max98090_sdg_tlv),  	SOC_SINGLE_TLV("Digital Coarse Volume", M98090_REG_DAI_PLAYBACK_LEVEL,  		M98090_DVG_SHIFT, M98090_DVG_NUM - 1, 0,  		max98090_dvg_tlv), @@ -841,39 +857,42 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,  static const char *mic1_mux_text[] = { "IN12", "IN56" }; -static const struct soc_enum mic1_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT, -		ARRAY_SIZE(mic1_mux_text), mic1_mux_text); +static SOC_ENUM_SINGLE_DECL(mic1_mux_enum, +			    M98090_REG_INPUT_MODE, +			    M98090_EXTMIC1_SHIFT, +			    mic1_mux_text);  static const struct snd_kcontrol_new max98090_mic1_mux =  	SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum);  static const char *mic2_mux_text[] = { "IN34", "IN56" }; -static const struct soc_enum mic2_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT, -		ARRAY_SIZE(mic2_mux_text), mic2_mux_text); +static SOC_ENUM_SINGLE_DECL(mic2_mux_enum, +			    M98090_REG_INPUT_MODE, +			    M98090_EXTMIC2_SHIFT, +			    mic2_mux_text);  static const struct snd_kcontrol_new max98090_mic2_mux =  	SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);  static const char *dmic_mux_text[] = { "ADC", "DMIC" }; -static const struct soc_enum dmic_mux_enum = -	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text); +static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text);  static const struct snd_kcontrol_new max98090_dmic_mux = -	SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum); +	SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum);  static const char *max98090_micpre_text[] = { "Off", "On" }; -static const struct soc_enum max98090_pa1en_enum = -	SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, -		ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); +static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, +			    M98090_REG_MIC1_INPUT_LEVEL, +			    M98090_MIC_PA1EN_SHIFT, +			    max98090_micpre_text); -static const struct soc_enum max98090_pa2en_enum = -	SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT, -		ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); +static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, +			    M98090_REG_MIC2_INPUT_LEVEL, +			    M98090_MIC_PA2EN_SHIFT, +			    max98090_micpre_text);  /* LINEA mixer switch */  static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { @@ -937,13 +956,15 @@ static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = {  static const char *lten_mux_text[] = { "Normal", "Loopthrough" }; -static const struct soc_enum ltenl_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, -		ARRAY_SIZE(lten_mux_text), lten_mux_text); +static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum, +			    M98090_REG_IO_CONFIGURATION, +			    M98090_LTEN_SHIFT, +			    lten_mux_text); -static const struct soc_enum ltenr_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, -		ARRAY_SIZE(lten_mux_text), lten_mux_text); +static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum, +			    M98090_REG_IO_CONFIGURATION, +			    M98090_LTEN_SHIFT, +			    lten_mux_text);  static const struct snd_kcontrol_new max98090_ltenl_mux =  	SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); @@ -953,13 +974,15 @@ static const struct snd_kcontrol_new max98090_ltenr_mux =  static const char *lben_mux_text[] = { "Normal", "Loopback" }; -static const struct soc_enum lbenl_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, -		ARRAY_SIZE(lben_mux_text), lben_mux_text); +static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum, +			    M98090_REG_IO_CONFIGURATION, +			    M98090_LBEN_SHIFT, +			    lben_mux_text); -static const struct soc_enum lbenr_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, -		ARRAY_SIZE(lben_mux_text), lben_mux_text); +static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum, +			    M98090_REG_IO_CONFIGURATION, +			    M98090_LBEN_SHIFT, +			    lben_mux_text);  static const struct snd_kcontrol_new max98090_lbenl_mux =  	SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); @@ -971,13 +994,15 @@ static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" };  static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" }; -static const struct soc_enum stenl_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT, -		ARRAY_SIZE(stenl_mux_text), stenl_mux_text); +static SOC_ENUM_SINGLE_DECL(stenl_mux_enum, +			    M98090_REG_ADC_SIDETONE, +			    M98090_DSTSL_SHIFT, +			    stenl_mux_text); -static const struct soc_enum stenr_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT, -		ARRAY_SIZE(stenr_mux_text), stenr_mux_text); +static SOC_ENUM_SINGLE_DECL(stenr_mux_enum, +			    M98090_REG_ADC_SIDETONE, +			    M98090_DSTSR_SHIFT, +			    stenr_mux_text);  static const struct snd_kcontrol_new max98090_stenl_mux =  	SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum); @@ -1085,9 +1110,10 @@ static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = {  static const char *linmod_mux_text[] = { "Left Only", "Left and Right" }; -static const struct soc_enum linmod_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT, -		ARRAY_SIZE(linmod_mux_text), linmod_mux_text); +static SOC_ENUM_SINGLE_DECL(linmod_mux_enum, +			    M98090_REG_LOUTR_MIXER, +			    M98090_LINMOD_SHIFT, +			    linmod_mux_text);  static const struct snd_kcontrol_new max98090_linmod_mux =  	SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum); @@ -1097,16 +1123,18 @@ static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" };  /*   * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable   */ -static const struct soc_enum mixhplsel_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT, -		ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); +static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum, +			    M98090_REG_HP_CONTROL, +			    M98090_MIXHPLSEL_SHIFT, +			    mixhpsel_mux_text);  static const struct snd_kcontrol_new max98090_mixhplsel_mux =  	SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum); -static const struct soc_enum mixhprsel_mux_enum = -	SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT, -		ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); +static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum, +			    M98090_REG_HP_CONTROL, +			    M98090_MIXHPRSEL_SHIFT, +			    mixhpsel_mux_text);  static const struct snd_kcontrol_new max98090_mixhprsel_mux =  	SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); @@ -1152,8 +1180,7 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {  	SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM,  		0, 0, &max98090_mic2_mux), -	SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM, -		0, 0, &max98090_dmic_mux), +	SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux),  	SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,  		M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event, @@ -1521,19 +1548,19 @@ static const int lrclk_rates[] = {  };  static const int user_pclk_rates[] = { -	13000000, 13000000 +	13000000, 13000000, 19200000, 19200000,  };  static const int user_lrclk_rates[] = { -	44100, 48000 +	44100, 48000, 44100, 48000,  };  static const unsigned long long ni_value[] = { -	3528, 768 +	3528, 768, 441, 8  };  static const unsigned long long mi_value[] = { -	8125, 1625 +	8125, 1625, 1500, 25  };  static void max98090_configure_bclk(struct snd_soc_codec *codec) @@ -1650,6 +1677,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,  				M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);  			snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,  				M98090_USE_M1_MASK, 0); +			max98090->master = false;  			break;  		case SND_SOC_DAIFMT_CBM_CFM:  			/* Set to master mode */ @@ -1666,6 +1694,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,  				regval |= M98090_MAS_MASK |  					M98090_BSEL_32;  			} +			max98090->master = true;  			break;  		case SND_SOC_DAIFMT_CBS_CFM:  		case SND_SOC_DAIFMT_CBM_CFS: @@ -1769,29 +1798,35 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,  	switch (level) {  	case SND_SOC_BIAS_ON: +		break; + +	case SND_SOC_BIAS_PREPARE: +		/* +		 * SND_SOC_BIAS_PREPARE is called while preparing for a +		 * transition to ON or away from ON. If current bias_level +		 * is SND_SOC_BIAS_ON, then it is preparing for a transition +		 * away from ON. Disable the clock in that case, otherwise +		 * enable it. +		 */ +		if (!IS_ERR(max98090->mclk)) { +			if (codec->dapm.bias_level == SND_SOC_BIAS_ON) +				clk_disable_unprepare(max98090->mclk); +			else +				clk_prepare_enable(max98090->mclk); +		} +		break; + +	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {  			ret = regcache_sync(max98090->regmap); -  			if (ret != 0) {  				dev_err(codec->dev,  					"Failed to sync cache: %d\n", ret);  				return ret;  			}  		} - -		if (max98090->jack_state == M98090_JACK_STATE_HEADSET) { -			/* -			 * Set to normal bias level. -			 */ -			snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, -				M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); -		}  		break; -	case SND_SOC_BIAS_PREPARE: -		break; - -	case SND_SOC_BIAS_STANDBY:  	case SND_SOC_BIAS_OFF:  		/* Set internal pull-up to lowest power mode */  		snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, @@ -1840,8 +1875,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,  	max98090->lrclk = params_rate(params); -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		snd_soc_update_bits(codec, M98090_REG_INTERFACE_FORMAT,  			M98090_WS_MASK, 0);  		break; @@ -1849,7 +1884,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,  		return -EINVAL;  	} -	max98090_configure_bclk(codec); +	if (max98090->master) +		max98090_configure_bclk(codec);  	cdata->rate = max98090->lrclk; @@ -1907,6 +1943,11 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,  	if (freq == max98090->sysclk)  		return 0; +	if (!IS_ERR(max98090->mclk)) { +		freq = clk_round_rate(max98090->mclk, freq); +		clk_set_rate(max98090->mclk, freq); +	} +  	/* Setup clocks for slave mode, and using the PLL  	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)  	 *		 0x02 (when master clk is 20MHz to 40MHz).. @@ -1928,8 +1969,6 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,  	max98090->sysclk = freq; -	max98090_configure_bclk(codec); -  	return 0;  } @@ -2193,15 +2232,11 @@ static int max98090_probe(struct snd_soc_codec *codec)  	dev_dbg(codec->dev, "max98090_probe\n"); -	max98090->codec = codec; - -	codec->control_data = max98090->regmap; +	max98090->mclk = devm_clk_get(codec->dev, "mclk"); +	if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER) +		return -EPROBE_DEFER; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} +	max98090->codec = codec;  	/* Reset the codec, the DSP core, and disable all interrupts */  	max98090_reset(max98090); @@ -2209,6 +2244,7 @@ static int max98090_probe(struct snd_soc_codec *codec)  	/* Initialize private data */  	max98090->sysclk = (unsigned)-1; +	max98090->master = false;  	cdata = &max98090->dai[0];  	cdata->rate = (unsigned)-1; @@ -2278,6 +2314,9 @@ static int max98090_probe(struct snd_soc_codec *codec)  	snd_soc_write(codec, M98090_REG_BIAS_CONTROL,  		M98090_VCM_MODE_MASK); +	snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, +		M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); +  	max98090_handle_pdata(codec);  	max98090_add_widgets(codec); @@ -2314,9 +2353,11 @@ static const struct regmap_config max98090_regmap = {  };  static int max98090_i2c_probe(struct i2c_client *i2c, -				 const struct i2c_device_id *id) +				 const struct i2c_device_id *i2c_id)  {  	struct max98090_priv *max98090; +	const struct acpi_device_id *acpi_id; +	kernel_ulong_t driver_data = 0;  	int ret;  	pr_debug("max98090_i2c_probe\n"); @@ -2326,9 +2367,20 @@ static int max98090_i2c_probe(struct i2c_client *i2c,  	if (max98090 == NULL)  		return -ENOMEM; -	max98090->devtype = id->driver_data; +	if (ACPI_HANDLE(&i2c->dev)) { +		acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table, +					    &i2c->dev); +		if (!acpi_id) { +			dev_err(&i2c->dev, "No driver data\n"); +			return -EINVAL; +		} +		driver_data = acpi_id->driver_data; +	} else if (i2c_id) { +		driver_data = i2c_id->driver_data; +	} + +	max98090->devtype = driver_data;  	i2c_set_clientdata(i2c, max98090); -	max98090->control_data = i2c;  	max98090->pdata = i2c->dev.platform_data;  	max98090->irq = i2c->irq; @@ -2359,6 +2411,8 @@ static int max98090_runtime_resume(struct device *dev)  	regcache_cache_only(max98090->regmap, false); +	max98090_reset(max98090); +  	regcache_sync(max98090->regmap);  	return 0; @@ -2374,9 +2428,34 @@ static int max98090_runtime_suspend(struct device *dev)  }  #endif +#ifdef CONFIG_PM +static int max98090_resume(struct device *dev) +{ +	struct max98090_priv *max98090 = dev_get_drvdata(dev); +	unsigned int status; + +	regcache_mark_dirty(max98090->regmap); + +	max98090_reset(max98090); + +	/* clear IRQ status */ +	regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status); + +	regcache_sync(max98090->regmap); + +	return 0; +} + +static int max98090_suspend(struct device *dev) +{ +	return 0; +} +#endif +  static const struct dev_pm_ops max98090_pm = {  	SET_RUNTIME_PM_OPS(max98090_runtime_suspend,  		max98090_runtime_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(max98090_suspend, max98090_resume)  };  static const struct i2c_device_id max98090_i2c_id[] = { @@ -2385,11 +2464,27 @@ static const struct i2c_device_id max98090_i2c_id[] = {  };  MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); +static const struct of_device_id max98090_of_match[] = { +	{ .compatible = "maxim,max98090", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, max98090_of_match); + +#ifdef CONFIG_ACPI +static struct acpi_device_id max98090_acpi_match[] = { +	{ "193C9890", MAX98090 }, +	{ } +}; +MODULE_DEVICE_TABLE(acpi, max98090_acpi_match); +#endif +  static struct i2c_driver max98090_i2c_driver = {  	.driver = {  		.name = "max98090",  		.owner = THIS_MODULE,  		.pm = &max98090_pm, +		.of_match_table = of_match_ptr(max98090_of_match), +		.acpi_match_table = ACPI_PTR(max98090_acpi_match),  	},  	.probe  = max98090_i2c_probe,  	.remove = max98090_i2c_remove, diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index 7e103f24905..cf1b6062ba8 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1523,8 +1523,8 @@ struct max98090_priv {  	struct regmap *regmap;  	struct snd_soc_codec *codec;  	enum max98090_type devtype; -	void *control_data;  	struct max98090_pdata *pdata; +	struct clk *mclk;  	unsigned int sysclk;  	unsigned int bclk;  	unsigned int lrclk; @@ -1541,6 +1541,7 @@ struct max98090_priv {  	unsigned int pa2en;  	unsigned int extmic_mux;  	unsigned int sidetone; +	bool master;  };  int max98090_mic_detect(struct snd_soc_codec *codec, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 41cdd164297..89ec0042488 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -15,6 +15,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/clk.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -39,8 +40,10 @@ struct max98095_cdata {  };  struct max98095_priv { +	struct regmap *regmap;  	enum max98095_type devtype;  	struct max98095_pdata *pdata; +	struct clk *mclk;  	unsigned int sysclk;  	struct max98095_cdata dai[3];  	const char **eq_texts; @@ -56,263 +59,145 @@ struct max98095_priv {  	struct snd_soc_jack *mic_jack;  }; -static const u8 max98095_reg_def[M98095_REG_CNT] = { -	0x00, /* 00 */ -	0x00, /* 01 */ -	0x00, /* 02 */ -	0x00, /* 03 */ -	0x00, /* 04 */ -	0x00, /* 05 */ -	0x00, /* 06 */ -	0x00, /* 07 */ -	0x00, /* 08 */ -	0x00, /* 09 */ -	0x00, /* 0A */ -	0x00, /* 0B */ -	0x00, /* 0C */ -	0x00, /* 0D */ -	0x00, /* 0E */ -	0x00, /* 0F */ -	0x00, /* 10 */ -	0x00, /* 11 */ -	0x00, /* 12 */ -	0x00, /* 13 */ -	0x00, /* 14 */ -	0x00, /* 15 */ -	0x00, /* 16 */ -	0x00, /* 17 */ -	0x00, /* 18 */ -	0x00, /* 19 */ -	0x00, /* 1A */ -	0x00, /* 1B */ -	0x00, /* 1C */ -	0x00, /* 1D */ -	0x00, /* 1E */ -	0x00, /* 1F */ -	0x00, /* 20 */ -	0x00, /* 21 */ -	0x00, /* 22 */ -	0x00, /* 23 */ -	0x00, /* 24 */ -	0x00, /* 25 */ -	0x00, /* 26 */ -	0x00, /* 27 */ -	0x00, /* 28 */ -	0x00, /* 29 */ -	0x00, /* 2A */ -	0x00, /* 2B */ -	0x00, /* 2C */ -	0x00, /* 2D */ -	0x00, /* 2E */ -	0x00, /* 2F */ -	0x00, /* 30 */ -	0x00, /* 31 */ -	0x00, /* 32 */ -	0x00, /* 33 */ -	0x00, /* 34 */ -	0x00, /* 35 */ -	0x00, /* 36 */ -	0x00, /* 37 */ -	0x00, /* 38 */ -	0x00, /* 39 */ -	0x00, /* 3A */ -	0x00, /* 3B */ -	0x00, /* 3C */ -	0x00, /* 3D */ -	0x00, /* 3E */ -	0x00, /* 3F */ -	0x00, /* 40 */ -	0x00, /* 41 */ -	0x00, /* 42 */ -	0x00, /* 43 */ -	0x00, /* 44 */ -	0x00, /* 45 */ -	0x00, /* 46 */ -	0x00, /* 47 */ -	0x00, /* 48 */ -	0x00, /* 49 */ -	0x00, /* 4A */ -	0x00, /* 4B */ -	0x00, /* 4C */ -	0x00, /* 4D */ -	0x00, /* 4E */ -	0x00, /* 4F */ -	0x00, /* 50 */ -	0x00, /* 51 */ -	0x00, /* 52 */ -	0x00, /* 53 */ -	0x00, /* 54 */ -	0x00, /* 55 */ -	0x00, /* 56 */ -	0x00, /* 57 */ -	0x00, /* 58 */ -	0x00, /* 59 */ -	0x00, /* 5A */ -	0x00, /* 5B */ -	0x00, /* 5C */ -	0x00, /* 5D */ -	0x00, /* 5E */ -	0x00, /* 5F */ -	0x00, /* 60 */ -	0x00, /* 61 */ -	0x00, /* 62 */ -	0x00, /* 63 */ -	0x00, /* 64 */ -	0x00, /* 65 */ -	0x00, /* 66 */ -	0x00, /* 67 */ -	0x00, /* 68 */ -	0x00, /* 69 */ -	0x00, /* 6A */ -	0x00, /* 6B */ -	0x00, /* 6C */ -	0x00, /* 6D */ -	0x00, /* 6E */ -	0x00, /* 6F */ -	0x00, /* 70 */ -	0x00, /* 71 */ -	0x00, /* 72 */ -	0x00, /* 73 */ -	0x00, /* 74 */ -	0x00, /* 75 */ -	0x00, /* 76 */ -	0x00, /* 77 */ -	0x00, /* 78 */ -	0x00, /* 79 */ -	0x00, /* 7A */ -	0x00, /* 7B */ -	0x00, /* 7C */ -	0x00, /* 7D */ -	0x00, /* 7E */ -	0x00, /* 7F */ -	0x00, /* 80 */ -	0x00, /* 81 */ -	0x00, /* 82 */ -	0x00, /* 83 */ -	0x00, /* 84 */ -	0x00, /* 85 */ -	0x00, /* 86 */ -	0x00, /* 87 */ -	0x00, /* 88 */ -	0x00, /* 89 */ -	0x00, /* 8A */ -	0x00, /* 8B */ -	0x00, /* 8C */ -	0x00, /* 8D */ -	0x00, /* 8E */ -	0x00, /* 8F */ -	0x00, /* 90 */ -	0x00, /* 91 */ -	0x30, /* 92 */ -	0xF0, /* 93 */ -	0x00, /* 94 */ -	0x00, /* 95 */ -	0x3F, /* 96 */ -	0x00, /* 97 */ -	0x00, /* 98 */ -	0x00, /* 99 */ -	0x00, /* 9A */ -	0x00, /* 9B */ -	0x00, /* 9C */ -	0x00, /* 9D */ -	0x00, /* 9E */ -	0x00, /* 9F */ -	0x00, /* A0 */ -	0x00, /* A1 */ -	0x00, /* A2 */ -	0x00, /* A3 */ -	0x00, /* A4 */ -	0x00, /* A5 */ -	0x00, /* A6 */ -	0x00, /* A7 */ -	0x00, /* A8 */ -	0x00, /* A9 */ -	0x00, /* AA */ -	0x00, /* AB */ -	0x00, /* AC */ -	0x00, /* AD */ -	0x00, /* AE */ -	0x00, /* AF */ -	0x00, /* B0 */ -	0x00, /* B1 */ -	0x00, /* B2 */ -	0x00, /* B3 */ -	0x00, /* B4 */ -	0x00, /* B5 */ -	0x00, /* B6 */ -	0x00, /* B7 */ -	0x00, /* B8 */ -	0x00, /* B9 */ -	0x00, /* BA */ -	0x00, /* BB */ -	0x00, /* BC */ -	0x00, /* BD */ -	0x00, /* BE */ -	0x00, /* BF */ -	0x00, /* C0 */ -	0x00, /* C1 */ -	0x00, /* C2 */ -	0x00, /* C3 */ -	0x00, /* C4 */ -	0x00, /* C5 */ -	0x00, /* C6 */ -	0x00, /* C7 */ -	0x00, /* C8 */ -	0x00, /* C9 */ -	0x00, /* CA */ -	0x00, /* CB */ -	0x00, /* CC */ -	0x00, /* CD */ -	0x00, /* CE */ -	0x00, /* CF */ -	0x00, /* D0 */ -	0x00, /* D1 */ -	0x00, /* D2 */ -	0x00, /* D3 */ -	0x00, /* D4 */ -	0x00, /* D5 */ -	0x00, /* D6 */ -	0x00, /* D7 */ -	0x00, /* D8 */ -	0x00, /* D9 */ -	0x00, /* DA */ -	0x00, /* DB */ -	0x00, /* DC */ -	0x00, /* DD */ -	0x00, /* DE */ -	0x00, /* DF */ -	0x00, /* E0 */ -	0x00, /* E1 */ -	0x00, /* E2 */ -	0x00, /* E3 */ -	0x00, /* E4 */ -	0x00, /* E5 */ -	0x00, /* E6 */ -	0x00, /* E7 */ -	0x00, /* E8 */ -	0x00, /* E9 */ -	0x00, /* EA */ -	0x00, /* EB */ -	0x00, /* EC */ -	0x00, /* ED */ -	0x00, /* EE */ -	0x00, /* EF */ -	0x00, /* F0 */ -	0x00, /* F1 */ -	0x00, /* F2 */ -	0x00, /* F3 */ -	0x00, /* F4 */ -	0x00, /* F5 */ -	0x00, /* F6 */ -	0x00, /* F7 */ -	0x00, /* F8 */ -	0x00, /* F9 */ -	0x00, /* FA */ -	0x00, /* FB */ -	0x00, /* FC */ -	0x00, /* FD */ -	0x00, /* FE */ -	0x00, /* FF */ +static const struct reg_default max98095_reg_def[] = { +	{  0xf, 0x00 }, /* 0F */ +	{ 0x10, 0x00 }, /* 10 */ +	{ 0x11, 0x00 }, /* 11 */ +	{ 0x12, 0x00 }, /* 12 */ +	{ 0x13, 0x00 }, /* 13 */ +	{ 0x14, 0x00 }, /* 14 */ +	{ 0x15, 0x00 }, /* 15 */ +	{ 0x16, 0x00 }, /* 16 */ +	{ 0x17, 0x00 }, /* 17 */ +	{ 0x18, 0x00 }, /* 18 */ +	{ 0x19, 0x00 }, /* 19 */ +	{ 0x1a, 0x00 }, /* 1A */ +	{ 0x1b, 0x00 }, /* 1B */ +	{ 0x1c, 0x00 }, /* 1C */ +	{ 0x1d, 0x00 }, /* 1D */ +	{ 0x1e, 0x00 }, /* 1E */ +	{ 0x1f, 0x00 }, /* 1F */ +	{ 0x20, 0x00 }, /* 20 */ +	{ 0x21, 0x00 }, /* 21 */ +	{ 0x22, 0x00 }, /* 22 */ +	{ 0x23, 0x00 }, /* 23 */ +	{ 0x24, 0x00 }, /* 24 */ +	{ 0x25, 0x00 }, /* 25 */ +	{ 0x26, 0x00 }, /* 26 */ +	{ 0x27, 0x00 }, /* 27 */ +	{ 0x28, 0x00 }, /* 28 */ +	{ 0x29, 0x00 }, /* 29 */ +	{ 0x2a, 0x00 }, /* 2A */ +	{ 0x2b, 0x00 }, /* 2B */ +	{ 0x2c, 0x00 }, /* 2C */ +	{ 0x2d, 0x00 }, /* 2D */ +	{ 0x2e, 0x00 }, /* 2E */ +	{ 0x2f, 0x00 }, /* 2F */ +	{ 0x30, 0x00 }, /* 30 */ +	{ 0x31, 0x00 }, /* 31 */ +	{ 0x32, 0x00 }, /* 32 */ +	{ 0x33, 0x00 }, /* 33 */ +	{ 0x34, 0x00 }, /* 34 */ +	{ 0x35, 0x00 }, /* 35 */ +	{ 0x36, 0x00 }, /* 36 */ +	{ 0x37, 0x00 }, /* 37 */ +	{ 0x38, 0x00 }, /* 38 */ +	{ 0x39, 0x00 }, /* 39 */ +	{ 0x3a, 0x00 }, /* 3A */ +	{ 0x3b, 0x00 }, /* 3B */ +	{ 0x3c, 0x00 }, /* 3C */ +	{ 0x3d, 0x00 }, /* 3D */ +	{ 0x3e, 0x00 }, /* 3E */ +	{ 0x3f, 0x00 }, /* 3F */ +	{ 0x40, 0x00 }, /* 40 */ +	{ 0x41, 0x00 }, /* 41 */ +	{ 0x42, 0x00 }, /* 42 */ +	{ 0x43, 0x00 }, /* 43 */ +	{ 0x44, 0x00 }, /* 44 */ +	{ 0x45, 0x00 }, /* 45 */ +	{ 0x46, 0x00 }, /* 46 */ +	{ 0x47, 0x00 }, /* 47 */ +	{ 0x48, 0x00 }, /* 48 */ +	{ 0x49, 0x00 }, /* 49 */ +	{ 0x4a, 0x00 }, /* 4A */ +	{ 0x4b, 0x00 }, /* 4B */ +	{ 0x4c, 0x00 }, /* 4C */ +	{ 0x4d, 0x00 }, /* 4D */ +	{ 0x4e, 0x00 }, /* 4E */ +	{ 0x4f, 0x00 }, /* 4F */ +	{ 0x50, 0x00 }, /* 50 */ +	{ 0x51, 0x00 }, /* 51 */ +	{ 0x52, 0x00 }, /* 52 */ +	{ 0x53, 0x00 }, /* 53 */ +	{ 0x54, 0x00 }, /* 54 */ +	{ 0x55, 0x00 }, /* 55 */ +	{ 0x56, 0x00 }, /* 56 */ +	{ 0x57, 0x00 }, /* 57 */ +	{ 0x58, 0x00 }, /* 58 */ +	{ 0x59, 0x00 }, /* 59 */ +	{ 0x5a, 0x00 }, /* 5A */ +	{ 0x5b, 0x00 }, /* 5B */ +	{ 0x5c, 0x00 }, /* 5C */ +	{ 0x5d, 0x00 }, /* 5D */ +	{ 0x5e, 0x00 }, /* 5E */ +	{ 0x5f, 0x00 }, /* 5F */ +	{ 0x60, 0x00 }, /* 60 */ +	{ 0x61, 0x00 }, /* 61 */ +	{ 0x62, 0x00 }, /* 62 */ +	{ 0x63, 0x00 }, /* 63 */ +	{ 0x64, 0x00 }, /* 64 */ +	{ 0x65, 0x00 }, /* 65 */ +	{ 0x66, 0x00 }, /* 66 */ +	{ 0x67, 0x00 }, /* 67 */ +	{ 0x68, 0x00 }, /* 68 */ +	{ 0x69, 0x00 }, /* 69 */ +	{ 0x6a, 0x00 }, /* 6A */ +	{ 0x6b, 0x00 }, /* 6B */ +	{ 0x6c, 0x00 }, /* 6C */ +	{ 0x6d, 0x00 }, /* 6D */ +	{ 0x6e, 0x00 }, /* 6E */ +	{ 0x6f, 0x00 }, /* 6F */ +	{ 0x70, 0x00 }, /* 70 */ +	{ 0x71, 0x00 }, /* 71 */ +	{ 0x72, 0x00 }, /* 72 */ +	{ 0x73, 0x00 }, /* 73 */ +	{ 0x74, 0x00 }, /* 74 */ +	{ 0x75, 0x00 }, /* 75 */ +	{ 0x76, 0x00 }, /* 76 */ +	{ 0x77, 0x00 }, /* 77 */ +	{ 0x78, 0x00 }, /* 78 */ +	{ 0x79, 0x00 }, /* 79 */ +	{ 0x7a, 0x00 }, /* 7A */ +	{ 0x7b, 0x00 }, /* 7B */ +	{ 0x7c, 0x00 }, /* 7C */ +	{ 0x7d, 0x00 }, /* 7D */ +	{ 0x7e, 0x00 }, /* 7E */ +	{ 0x7f, 0x00 }, /* 7F */ +	{ 0x80, 0x00 }, /* 80 */ +	{ 0x81, 0x00 }, /* 81 */ +	{ 0x82, 0x00 }, /* 82 */ +	{ 0x83, 0x00 }, /* 83 */ +	{ 0x84, 0x00 }, /* 84 */ +	{ 0x85, 0x00 }, /* 85 */ +	{ 0x86, 0x00 }, /* 86 */ +	{ 0x87, 0x00 }, /* 87 */ +	{ 0x88, 0x00 }, /* 88 */ +	{ 0x89, 0x00 }, /* 89 */ +	{ 0x8a, 0x00 }, /* 8A */ +	{ 0x8b, 0x00 }, /* 8B */ +	{ 0x8c, 0x00 }, /* 8C */ +	{ 0x8d, 0x00 }, /* 8D */ +	{ 0x8e, 0x00 }, /* 8E */ +	{ 0x8f, 0x00 }, /* 8F */ +	{ 0x90, 0x00 }, /* 90 */ +	{ 0x91, 0x00 }, /* 91 */ +	{ 0x92, 0x30 }, /* 92 */ +	{ 0x93, 0xF0 }, /* 93 */ +	{ 0x94, 0x00 }, /* 94 */ +	{ 0x95, 0x00 }, /* 95 */ +	{ 0x96, 0x3F }, /* 96 */ +	{ 0x97, 0x00 }, /* 97 */ +	{ 0xff, 0x00 }, /* FF */  };  static struct { @@ -577,14 +462,14 @@ static struct {  	{ 0xFF, 0x00 }, /* FF */  }; -static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg) +static bool max98095_readable(struct device *dev, unsigned int reg)  {  	if (reg >= M98095_REG_CNT)  		return 0;  	return max98095_access[reg].readable != 0;  } -static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg) +static bool max98095_volatile(struct device *dev, unsigned int reg)  {  	if (reg > M98095_REG_MAX_CACHED)  		return 1; @@ -611,22 +496,18 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)  	return 0;  } -/* - * Filter coefficients are in a separate register segment - * and they share the address space of the normal registers. - * The coefficient registers do not need or share the cache. - */ -static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg, -			     unsigned int value) -{ -	int ret; +static const struct regmap_config max98095_regmap = { +	.reg_bits = 8, +	.val_bits = 8, -	codec->cache_bypass = 1; -	ret = snd_soc_write(codec, reg, value); -	codec->cache_bypass = 0; +	.reg_defaults = max98095_reg_def, +	.num_reg_defaults = ARRAY_SIZE(max98095_reg_def), +	.max_register = M98095_0FF_REV_ID, +	.cache_type = REGCACHE_RBTREE, -	return ret ? -EIO : 0; -} +	.readable_reg = max98095_readable, +	.volatile_reg = max98095_volatile, +};  /*   * Load equalizer DSP coefficient configurations registers @@ -637,8 +518,9 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,  	unsigned int eq_reg;  	unsigned int i; -	BUG_ON(band > 4); -	BUG_ON(dai > 1); +	if (WARN_ON(band > 4) || +	    WARN_ON(dai > 1)) +		return;  	/* Load the base register address */  	eq_reg = dai ? M98095_142_DAI2_EQ_BASE : M98095_110_DAI1_EQ_BASE; @@ -648,8 +530,8 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,  	/* Step through the registers and coefs */  	for (i = 0; i < M98095_COEFS_PER_BAND; i++) { -		max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i])); -		max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i])); +		snd_soc_write(codec, eq_reg++, M98095_BYTE1(coefs[i])); +		snd_soc_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));  	}  } @@ -662,8 +544,9 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,  	unsigned int bq_reg;  	unsigned int i; -	BUG_ON(band > 1); -	BUG_ON(dai > 1); +	if (WARN_ON(band > 1) || +	    WARN_ON(dai > 1)) +		return;  	/* Load the base register address */  	bq_reg = dai ? M98095_17E_DAI2_BQ_BASE : M98095_174_DAI1_BQ_BASE; @@ -673,31 +556,33 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,  	/* Step through the registers and coefs */  	for (i = 0; i < M98095_COEFS_PER_BAND; i++) { -		max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i])); -		max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i])); +		snd_soc_write(codec, bq_reg++, M98095_BYTE1(coefs[i])); +		snd_soc_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));  	}  }  static const char * const max98095_fltr_mode[] = { "Voice", "Music" }; -static const struct soc_enum max98095_dai1_filter_mode_enum[] = { -	SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 7, 2, max98095_fltr_mode), -}; -static const struct soc_enum max98095_dai2_filter_mode_enum[] = { -	SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 7, 2, max98095_fltr_mode), -}; +static SOC_ENUM_SINGLE_DECL(max98095_dai1_filter_mode_enum, +			    M98095_02E_DAI1_FILTERS, 7, +			    max98095_fltr_mode); +static SOC_ENUM_SINGLE_DECL(max98095_dai2_filter_mode_enum, +			    M98095_038_DAI2_FILTERS, 7, +			    max98095_fltr_mode);  static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" }; -static const struct soc_enum max98095_extmic_enum = -	SOC_ENUM_SINGLE(M98095_087_CFG_MIC, 0, 3, max98095_extmic_text); +static SOC_ENUM_SINGLE_DECL(max98095_extmic_enum, +			    M98095_087_CFG_MIC, 0, +			    max98095_extmic_text);  static const struct snd_kcontrol_new max98095_extmic_mux =  	SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum);  static const char * const max98095_linein_text[] = { "INA", "INB" }; -static const struct soc_enum max98095_linein_enum = -	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 6, 2, max98095_linein_text); +static SOC_ENUM_SINGLE_DECL(max98095_linein_enum, +			    M98095_086_CFG_LINE, 6, +			    max98095_linein_text);  static const struct snd_kcontrol_new max98095_linein_mux =  	SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum); @@ -705,29 +590,31 @@ static const struct snd_kcontrol_new max98095_linein_mux =  static const char * const max98095_line_mode_text[] = {  	"Stereo", "Differential"}; -static const struct soc_enum max98095_linein_mode_enum = -	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 7, 2, max98095_line_mode_text); +static SOC_ENUM_SINGLE_DECL(max98095_linein_mode_enum, +			    M98095_086_CFG_LINE, 7, +			    max98095_line_mode_text); -static const struct soc_enum max98095_lineout_mode_enum = -	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 4, 2, max98095_line_mode_text); +static SOC_ENUM_SINGLE_DECL(max98095_lineout_mode_enum, +			    M98095_086_CFG_LINE, 4, +			    max98095_line_mode_text);  static const char * const max98095_dai_fltr[] = {  	"Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k",  	"Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"}; -static const struct soc_enum max98095_dai1_dac_filter_enum[] = { -	SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 0, 6, max98095_dai_fltr), -}; -static const struct soc_enum max98095_dai2_dac_filter_enum[] = { -	SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 0, 6, max98095_dai_fltr), -}; -static const struct soc_enum max98095_dai3_dac_filter_enum[] = { -	SOC_ENUM_SINGLE(M98095_042_DAI3_FILTERS, 0, 6, max98095_dai_fltr), -}; +static SOC_ENUM_SINGLE_DECL(max98095_dai1_dac_filter_enum, +			    M98095_02E_DAI1_FILTERS, 0, +			    max98095_dai_fltr); +static SOC_ENUM_SINGLE_DECL(max98095_dai2_dac_filter_enum, +			    M98095_038_DAI2_FILTERS, 0, +			    max98095_dai_fltr); +static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum, +			    M98095_042_DAI3_FILTERS, 0, +			    max98095_dai_fltr);  static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	unsigned int sel = ucontrol->value.integer.value[0]; @@ -741,7 +628,7 @@ static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,  static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = max98095->mic1pre; @@ -751,7 +638,7 @@ static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,  static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	unsigned int sel = ucontrol->value.integer.value[0]; @@ -765,7 +652,7 @@ static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,  static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = max98095->mic2pre; @@ -1011,7 +898,8 @@ static int max98095_line_pga(struct snd_soc_dapm_widget *w,  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	u8 *state; -	BUG_ON(!((channel == 1) || (channel == 2))); +	if (WARN_ON(!(channel == 1 || channel == 2))) +		return -EINVAL;  	state = &max98095->lin_state; @@ -1285,14 +1173,6 @@ static const struct snd_soc_dapm_route max98095_audio_map[] = {  	{"MIC2 Input", NULL, "MIC2"},  }; -static int max98095_add_widgets(struct snd_soc_codec *codec) -{ -	snd_soc_add_codec_controls(codec, max98095_snd_controls, -			     ARRAY_SIZE(max98095_snd_controls)); - -	return 0; -} -  /* codec mclk clock divider coefficients */  static const struct {  	u32 rate; @@ -1339,12 +1219,12 @@ static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,  	rate = params_rate(params); -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,  			M98095_DAI_WS, 0);  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,  			M98095_DAI_WS, M98095_DAI_WS);  		break; @@ -1517,6 +1397,11 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,  	if (freq == max98095->sysclk)  		return 0; +	if (!IS_ERR(max98095->mclk)) { +		freq = clk_round_rate(max98095->mclk, freq); +		clk_set_rate(max98095->mclk, freq); +	} +  	/* Setup clocks for slave mode, and using the PLL  	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)  	 *         0x02 (when master clk is 20MHz to 40MHz).. @@ -1748,6 +1633,7 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,  static int max98095_set_bias_level(struct snd_soc_codec *codec,  				   enum snd_soc_bias_level level)  { +	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	int ret;  	switch (level) { @@ -1755,11 +1641,24 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_PREPARE: +		/* +		 * SND_SOC_BIAS_PREPARE is called while preparing for a +		 * transition to ON or away from ON. If current bias_level +		 * is SND_SOC_BIAS_ON, then it is preparing for a transition +		 * away from ON. Disable the clock in that case, otherwise +		 * enable it. +		 */ +		if (!IS_ERR(max98095->mclk)) { +			if (codec->dapm.bias_level == SND_SOC_BIAS_ON) +				clk_disable_unprepare(max98095->mclk); +			else +				clk_prepare_enable(max98095->mclk); +		}  		break;  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			ret = snd_soc_cache_sync(codec); +			ret = regcache_sync(max98095->regmap);  			if (ret != 0) {  				dev_err(codec->dev, "Failed to sync cache: %d\n", ret); @@ -1774,7 +1673,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_OFF:  		snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,  				M98095_MBEN, 0); -		codec->cache_sync = 1; +		regcache_mark_dirty(max98095->regmap);  		break;  	}  	codec->dapm.bias_level = level; @@ -1858,17 +1757,18 @@ static int max98095_get_eq_channel(const char *name)  static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,  				 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	struct max98095_pdata *pdata = max98095->pdata;  	int channel = max98095_get_eq_channel(kcontrol->id.name);  	struct max98095_cdata *cdata; -	int sel = ucontrol->value.integer.value[0]; +	unsigned int sel = ucontrol->value.integer.value[0];  	struct max98095_eq_cfg *coef_set;  	int fs, best, best_val, i;  	int regmask, regsave; -	BUG_ON(channel > 1); +	if (WARN_ON(channel > 1)) +		return -EINVAL;  	if (!pdata || !max98095->eq_textcnt)  		return 0; @@ -1921,7 +1821,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,  static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,  				 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	int channel = max98095_get_eq_channel(kcontrol->id.name);  	struct max98095_cdata *cdata; @@ -1985,7 +1885,7 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)  	/* Now point the soc_enum to .texts array items */  	max98095->eq_enum.texts = max98095->eq_texts; -	max98095->eq_enum.max = max98095->eq_textcnt; +	max98095->eq_enum.items = max98095->eq_textcnt;  	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));  	if (ret != 0) @@ -2011,12 +1911,12 @@ static int max98095_get_bq_channel(struct snd_soc_codec *codec,  static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,  				 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	struct max98095_pdata *pdata = max98095->pdata;  	int channel = max98095_get_bq_channel(codec, kcontrol->id.name);  	struct max98095_cdata *cdata; -	int sel = ucontrol->value.integer.value[0]; +	unsigned int sel = ucontrol->value.integer.value[0];  	struct max98095_biquad_cfg *coef_set;  	int fs, best, best_val, i;  	int regmask, regsave; @@ -2072,7 +1972,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,  static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,  				 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);  	int channel = max98095_get_bq_channel(codec, kcontrol->id.name);  	struct max98095_cdata *cdata; @@ -2140,7 +2040,7 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)  	/* Now point the soc_enum to .texts array items */  	max98095->bq_enum.texts = max98095->bq_texts; -	max98095->bq_enum.max = max98095->bq_textcnt; +	max98095->bq_enum.items = max98095->bq_textcnt;  	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));  	if (ret != 0) @@ -2341,7 +2241,7 @@ static int max98095_reset(struct snd_soc_codec *codec)  	/* Reset to hardware default for registers, as there is not  	 * a soft reset hardware control register */  	for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) { -		ret = snd_soc_write(codec, i, max98095_reg_def[i]); +		ret = snd_soc_write(codec, i, snd_soc_read(codec, i));  		if (ret < 0) {  			dev_err(codec->dev, "Failed to reset: %d\n", ret);  			return ret; @@ -2358,11 +2258,9 @@ static int max98095_probe(struct snd_soc_codec *codec)  	struct i2c_client *client;  	int ret = 0; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} +	max98095->mclk = devm_clk_get(codec->dev, "mclk"); +	if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER) +		return -EPROBE_DEFER;  	/* reset the codec, the DSP core, and disable all interrupts */  	max98095_reset(codec); @@ -2447,8 +2345,6 @@ static int max98095_probe(struct snd_soc_codec *codec)  	snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN,  		M98095_SHDNRUN); -	max98095_add_widgets(codec); -  	return 0;  err_irq: @@ -2480,11 +2376,8 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = {  	.suspend = max98095_suspend,  	.resume  = max98095_resume,  	.set_bias_level = max98095_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(max98095_reg_def), -	.reg_word_size = sizeof(u8), -	.reg_cache_default = max98095_reg_def, -	.readable_register = max98095_readable, -	.volatile_register = max98095_volatile, +	.controls = max98095_snd_controls, +	.num_controls = ARRAY_SIZE(max98095_snd_controls),  	.dapm_widgets	  = max98095_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),  	.dapm_routes     = max98095_audio_map, @@ -2502,6 +2395,13 @@ static int max98095_i2c_probe(struct i2c_client *i2c,  	if (max98095 == NULL)  		return -ENOMEM; +	max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); +	if (IS_ERR(max98095->regmap)) { +		ret = PTR_ERR(max98095->regmap); +		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); +		return ret; +	} +  	max98095->devtype = id->driver_data;  	i2c_set_clientdata(i2c, max98095);  	max98095->pdata = i2c->dev.platform_data; @@ -2523,10 +2423,17 @@ static const struct i2c_device_id max98095_i2c_id[] = {  };  MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); +static const struct of_device_id max98095_of_match[] = { +	{ .compatible = "maxim,max98095", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, max98095_of_match); +  static struct i2c_driver max98095_i2c_driver = {  	.driver = {  		.name = "max98095",  		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(max98095_of_match),  	},  	.probe  = max98095_i2c_probe,  	.remove = max98095_i2c_remove, diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 58c38a5b481..4fdf5aaa236 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -18,6 +18,7 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -27,18 +28,26 @@  #include "max9850.h"  struct max9850_priv { +	struct regmap *regmap;  	unsigned int sysclk;  };  /* max9850 register cache */ -static const u8 max9850_reg[MAX9850_CACHEREGNUM] = { -	0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +static const struct reg_default max9850_reg[] = { +	{  2, 0x0c }, +	{  3, 0x00 }, +	{  4, 0x00 }, +	{  5, 0x00 }, +	{  6, 0x00 }, +	{  7, 0x00 }, +	{  8, 0x00 }, +	{  9, 0x00 }, +	{ 10, 0x00 },  };  /* these registers are not used at the moment but provided for the sake of   * completeness */ -static int max9850_volatile_register(struct snd_soc_codec *codec, -		unsigned int reg) +static bool max9850_volatile_register(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case MAX9850_STATUSA: @@ -49,6 +58,15 @@ static int max9850_volatile_register(struct snd_soc_codec *codec,  	}  } +static const struct regmap_config max9850_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = MAX9850_DIGITAL_AUDIO, +	.volatile_reg = max9850_volatile_register, +	.cache_type = REGCACHE_RBTREE, +}; +  static const unsigned int max9850_tlv[] = {  	TLV_DB_RANGE_HEAD(4),  	0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0), @@ -131,14 +149,14 @@ static int max9850_hw_params(struct snd_pcm_substream *substream,  	snd_soc_write(codec, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);  	snd_soc_write(codec, MAX9850_LRCLK_LSB, lrclk_div & 0xff); -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		da = 0;  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		da = 0x2;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		da = 0x3;  		break;  	default: @@ -225,6 +243,7 @@ static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)  static int max9850_set_bias_level(struct snd_soc_codec *codec,  				  enum snd_soc_bias_level level)  { +	struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);  	int ret;  	switch (level) { @@ -234,7 +253,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			ret = snd_soc_cache_sync(codec); +			ret = regcache_sync(max9850->regmap);  			if (ret) {  				dev_err(codec->dev,  					"Failed to sync cache: %d\n", ret); @@ -293,14 +312,6 @@ static int max9850_resume(struct snd_soc_codec *codec)  static int max9850_probe(struct snd_soc_codec *codec)  { -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* enable zero-detect */  	snd_soc_update_bits(codec, MAX9850_GENERAL_PURPOSE, 1, 1);  	/* enable slew-rate control */ @@ -316,10 +327,6 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = {  	.suspend =	max9850_suspend,  	.resume =	max9850_resume,  	.set_bias_level = max9850_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(max9850_reg), -	.reg_word_size = sizeof(u8), -	.reg_cache_default = max9850_reg, -	.volatile_register = max9850_volatile_register,  	.controls = max9850_controls,  	.num_controls = ARRAY_SIZE(max9850_controls), @@ -340,6 +347,10 @@ static int max9850_i2c_probe(struct i2c_client *i2c,  	if (max9850 == NULL)  		return -ENOMEM; +	max9850->regmap = devm_regmap_init_i2c(i2c, &max9850_regmap); +	if (IS_ERR(max9850->regmap)) +		return PTR_ERR(max9850->regmap); +  	i2c_set_clientdata(i2c, max9850);  	ret = snd_soc_register_codec(&i2c->dev, diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index ea141e1d6f2..9965277b595 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -22,6 +22,7 @@   */  #include <linux/module.h>  #include <linux/device.h> +#include <linux/of.h>  #include <linux/mfd/mc13xxx.h>  #include <linux/slab.h>  #include <sound/core.h> @@ -30,16 +31,10 @@  #include <sound/soc.h>  #include <sound/initval.h>  #include <sound/soc-dapm.h> +#include <linux/regmap.h>  #include "mc13783.h" -#define MC13783_AUDIO_RX0	36 -#define MC13783_AUDIO_RX1	37 -#define MC13783_AUDIO_TX	38 -#define MC13783_SSI_NETWORK	39 -#define MC13783_AUDIO_CODEC	40 -#define MC13783_AUDIO_DAC	41 -  #define AUDIO_RX0_ALSPEN		(1 << 5)  #define AUDIO_RX0_ALSPSEL		(1 << 7)  #define AUDIO_RX0_ADDCDC		(1 << 21) @@ -95,45 +90,12 @@  struct mc13783_priv {  	struct mc13xxx *mc13xxx; +	struct regmap *regmap;  	enum mc13783_ssi_port adc_ssi_port;  	enum mc13783_ssi_port dac_ssi_port;  }; -static unsigned int mc13783_read(struct snd_soc_codec *codec, -	unsigned int reg) -{ -	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	unsigned int value = 0; - -	mc13xxx_lock(priv->mc13xxx); - -	mc13xxx_reg_read(priv->mc13xxx, reg, &value); - -	mc13xxx_unlock(priv->mc13xxx); - -	return value; -} - -static int mc13783_write(struct snd_soc_codec *codec, -	unsigned int reg, unsigned int value) -{ -	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	int ret; - -	mc13xxx_lock(priv->mc13xxx); - -	ret = mc13xxx_reg_write(priv->mc13xxx, reg, value); - -	/* include errata fix for spi audio problems */ -	if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC) -		ret = mc13xxx_reg_write(priv->mc13xxx, reg, value); - -	mc13xxx_unlock(priv->mc13xxx); - -	return ret; -} -  /* Mapping between sample rates and register value */  static unsigned int mc13783_rates[] = {  	8000, 11025, 12000, 16000, @@ -145,8 +107,7 @@ static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,  				struct snd_pcm_hw_params *params,  				struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	unsigned int rate = params_rate(params);  	int i; @@ -165,8 +126,7 @@ static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,  				struct snd_pcm_hw_params *params,  				struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	unsigned int rate = params_rate(params);  	unsigned int val; @@ -382,7 +342,7 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,  		break;  	default:  		return -EINVAL; -	}; +	}  	snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val); @@ -447,25 +407,46 @@ static const char * const adcl_enum_text[] = {  	"MC1L", "RXINL",  }; -static const struct soc_enum adcl_enum = -	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);  static const struct snd_kcontrol_new left_input_mux = -	SOC_DAPM_ENUM_VIRT("Route", adcl_enum); +	SOC_DAPM_ENUM("Route", adcl_enum);  static const char * const adcr_enum_text[] = {  	"MC1R", "MC2", "RXINR", "TXIN",  }; -static const struct soc_enum adcr_enum = -	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);  static const struct snd_kcontrol_new right_input_mux = -	SOC_DAPM_ENUM_VIRT("Route", adcr_enum); +	SOC_DAPM_ENUM("Route", adcr_enum);  static const struct snd_kcontrol_new samp_ctl =  	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0); +static const char * const speaker_amp_source_text[] = { +	"CODEC", "Right" +}; +static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, +			    speaker_amp_source_text); +static const struct snd_kcontrol_new speaker_amp_source_mux = +	SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); + +static const char * const headset_amp_source_text[] = { +	"CODEC", "Mixer" +}; + +static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, +			    headset_amp_source_text); +static const struct snd_kcontrol_new headset_amp_source_mux = +	SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); + +static const struct snd_kcontrol_new cdcout_ctl = +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0); + +static const struct snd_kcontrol_new adc_bypass_ctl = +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0); +  static const struct snd_kcontrol_new lamp_ctl =  	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0); @@ -498,17 +479,27 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  	SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl),  	SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl), -	SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0, +	SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,  			      &left_input_mux), -	SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, +	SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,  			      &right_input_mux), +	SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0, +			 &speaker_amp_source_mux), + +	SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0, +			 &headset_amp_source_mux), +  	SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),  	SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0), +	SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0, +			&adc_bypass_ctl), +  /* Output */  	SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0), @@ -516,10 +507,15 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("RXOUTR"),  	SND_SOC_DAPM_OUTPUT("HSL"),  	SND_SOC_DAPM_OUTPUT("HSR"), +	SND_SOC_DAPM_OUTPUT("LSPL"),  	SND_SOC_DAPM_OUTPUT("LSP"),  	SND_SOC_DAPM_OUTPUT("SP"), +	SND_SOC_DAPM_OUTPUT("CDCOUT"), -	SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl), +	SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0, +			&cdcout_ctl), +	SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0, +			&samp_ctl),  	SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),  	SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,  			&hlamp_ctl), @@ -554,42 +550,66 @@ static struct snd_soc_dapm_route mc13783_routes[] = {  	{ "ADC", NULL, "PGA Right Input"},  	{ "ADC", NULL, "ADC_Reset"}, +	{ "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" }, + +	{ "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"}, +	{ "Speaker Amp Source MUX", "Right", "DAC PGA"}, + +	{ "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"}, +	{ "Headset Amp Source MUX", "Mixer", "DAC PGA"}, +  /* Output */  	{ "HSL", NULL, "Headset Amp Left" },  	{ "HSR", NULL, "Headset Amp Right"},  	{ "RXOUTL", NULL, "Line out Amp Left"},  	{ "RXOUTR", NULL, "Line out Amp Right"}, -	{ "SP", NULL, "Speaker Amp"}, -	{ "Speaker Amp", NULL, "DAC PGA"}, -	{ "LSP", NULL, "DAC PGA"}, -	{ "Headset Amp Left", NULL, "DAC PGA"}, -	{ "Headset Amp Right", NULL, "DAC PGA"}, +	{ "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"}, +	{ "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"}, +	{ "HSL", "Headset Amp Left", "Headset Amp Source MUX"}, +	{ "HSR", "Headset Amp Right", "Headset Amp Source MUX"},  	{ "Line out Amp Left", NULL, "DAC PGA"},  	{ "Line out Amp Right", NULL, "DAC PGA"},  	{ "DAC PGA", NULL, "DAC"},  	{ "DAC", NULL, "DAC_E"}, +	{ "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"},  };  static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",  						"Mono", "Mono Mix"}; -static const struct soc_enum mc13783_enum_3d_mixer = -	SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer), -			mc13783_3d_mixer); +static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer, +			    MC13783_AUDIO_RX1, 16, +			    mc13783_3d_mixer);  static struct snd_kcontrol_new mc13783_control_list[] = {  	SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),  	SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0), +	SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0),  	SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),  	SOC_ENUM("3D Control", mc13783_enum_3d_mixer), + +	SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0), +	SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0), +	SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0), +	SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0), + +	SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0), +	SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0), + +	SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0), +	SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0), + +	SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0), +	SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0), + +	SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0), +	SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),  };  static int mc13783_probe(struct snd_soc_codec *codec)  {  	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	mc13xxx_lock(priv->mc13xxx); -  	/* these are the reset values */  	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);  	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A); @@ -612,8 +632,6 @@ static int mc13783_probe(struct snd_soc_codec *codec)  		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,  				0, AUDIO_SSI_SEL); -	mc13xxx_unlock(priv->mc13xxx); -  	return 0;  } @@ -621,13 +639,9 @@ static int mc13783_remove(struct snd_soc_codec *codec)  {  	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	mc13xxx_lock(priv->mc13xxx); -  	/* Make sure VAUDIOON is off */  	mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0); -	mc13xxx_unlock(priv->mc13xxx); -  	return 0;  } @@ -714,11 +728,15 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {  	}  }; +static struct regmap *mc13783_get_regmap(struct device *dev) +{ +	return dev_get_regmap(dev->parent, NULL); +} +  static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {  	.probe		= mc13783_probe,  	.remove		= mc13783_remove, -	.read		= mc13783_read, -	.write		= mc13783_write, +	.get_regmap	= mc13783_get_regmap,  	.controls	= mc13783_control_list,  	.num_controls	= ARRAY_SIZE(mc13783_control_list),  	.dapm_widgets	= mc13783_dapm_widgets, @@ -727,30 +745,37 @@ static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {  	.num_dapm_routes = ARRAY_SIZE(mc13783_routes),  }; -static int mc13783_codec_probe(struct platform_device *pdev) +static int __init mc13783_codec_probe(struct platform_device *pdev)  { -	struct mc13xxx *mc13xxx;  	struct mc13783_priv *priv;  	struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data; +	struct device_node *np;  	int ret; -	mc13xxx = dev_get_drvdata(pdev->dev.parent); - -  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -	if (priv == NULL) +	if (!priv)  		return -ENOMEM; -	dev_set_drvdata(&pdev->dev, priv); -	priv->mc13xxx = mc13xxx;  	if (pdata) {  		priv->adc_ssi_port = pdata->adc_ssi_port;  		priv->dac_ssi_port = pdata->dac_ssi_port;  	} else { -		priv->adc_ssi_port = MC13783_SSI1_PORT; -		priv->dac_ssi_port = MC13783_SSI2_PORT; +		np = of_get_child_by_name(pdev->dev.parent->of_node, "codec"); +		if (!np) +			return -ENOSYS; + +		ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port); +		if (ret) +			return ret; + +		ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port); +		if (ret) +			return ret;  	} +	dev_set_drvdata(&pdev->dev, priv); +	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent); +  	if (priv->adc_ssi_port == priv->dac_ssi_port)  		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,  			mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync)); @@ -758,14 +783,6 @@ static int mc13783_codec_probe(struct platform_device *pdev)  		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,  			mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async)); -	if (ret) -		goto err_register_codec; - -	return 0; - -err_register_codec: -	dev_err(&pdev->dev, "register codec failed with %d\n", ret); -  	return ret;  } @@ -778,14 +795,12 @@ static int mc13783_codec_remove(struct platform_device *pdev)  static struct platform_driver mc13783_codec_driver = {  	.driver = { -		   .name = "mc13783-codec", -		   .owner = THIS_MODULE, -		   }, -	.probe = mc13783_codec_probe, +		.name	= "mc13783-codec", +		.owner	= THIS_MODULE, +	},  	.remove = mc13783_codec_remove,  }; - -module_platform_driver(mc13783_codec_driver); +module_platform_driver_probe(mc13783_codec_driver, mc13783_codec_probe);  MODULE_DESCRIPTION("ASoC MC13783 driver");  MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>"); diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 26118828782..e661e8420e3 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -73,11 +73,11 @@ static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);  static const char * const ml26124_companding[] = {"16bit PCM", "u-law",  						  "A-law"}; -static const struct soc_enum ml26124_adc_companding_enum -	= SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding); +static SOC_ENUM_SINGLE_DECL(ml26124_adc_companding_enum, +			    ML26124_SAI_TRANS_CTL, 6, ml26124_companding); -static const struct soc_enum ml26124_dac_companding_enum -	= SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding); +static SOC_ENUM_SINGLE_DECL(ml26124_dac_companding_enum, +			    ML26124_SAI_RCV_CTL, 6, ml26124_companding);  static const struct snd_kcontrol_new ml26124_snd_controls[] = {  	SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0, @@ -136,8 +136,8 @@ static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {  static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",  				"Digital MIC in", "Analog MIC Differential in"}; -static const struct soc_enum ml26124_insel_enum = -	SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select); +static SOC_ENUM_SINGLE_DECL(ml26124_insel_enum, +			    ML26124_MIC_IF_CTL, 0, ml26124_input_select);  static const struct snd_kcontrol_new ml26124_input_mux_controls =  	SOC_DAPM_ENUM("Input Select", ml26124_insel_enum); @@ -342,6 +342,8 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream,  	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);  	int i = get_coeff(priv->mclk, params_rate(hw_params)); +	if (i < 0) +		return i;  	priv->substream = substream;  	priv->rate = params_rate(hw_params); @@ -584,16 +586,6 @@ static int ml26124_resume(struct snd_soc_codec *codec)  static int ml26124_probe(struct snd_soc_codec *codec)  { -	int ret; -	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec); -	codec->control_data = priv->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Software Reset */  	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);  	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0); diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 651ce092367..a722a023c26 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -21,6 +21,7 @@  #include <linux/gpio.h>  #include <linux/i2c.h>  #include <linux/regmap.h> +#include <linux/of.h>  #include <linux/of_device.h>  #include <linux/of_gpio.h>  #include <sound/pcm.h> @@ -114,7 +115,7 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec)  static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = priv->deemph; @@ -125,7 +126,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,  static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);  	priv->deemph = ucontrol->value.enumerated.item[0]; @@ -171,16 +172,21 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,  	struct snd_soc_codec *codec = dai->codec;  	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);  	int val = 0, ret; -	int pcm_format = params_format(params);  	priv->rate = params_rate(params);  	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {  	case SND_SOC_DAIFMT_RIGHT_J: -		if (pcm_format == SNDRV_PCM_FORMAT_S24_LE) -			val = 0x00; -		else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) -			val = 0x03; +		switch (params_width(params)) { +		case 24: +			val = 0; +			break; +		case 16: +			val = 3; +			break; +		default: +			return -EINVAL; +		}  		break;  	case SND_SOC_DAIFMT_I2S:  		val = 0x04; @@ -270,7 +276,7 @@ MODULE_DEVICE_TABLE(of, pcm1681_dt_ids);  static const struct regmap_config pcm1681_regmap = {  	.reg_bits		= 8,  	.val_bits		= 8, -	.max_register		= ARRAY_SIZE(pcm1681_reg_defaults) + 1, +	.max_register		= 0x13,  	.reg_defaults		= pcm1681_reg_defaults,  	.num_reg_defaults	= ARRAY_SIZE(pcm1681_reg_defaults),  	.writeable_reg		= pcm1681_writeable_reg, diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 2a8eccf64c7..3a80ba4452d 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c @@ -28,6 +28,7 @@  #include <sound/initval.h>  #include <sound/soc.h>  #include <sound/tlv.h> +#include <linux/of.h>  #include <linux/of_device.h>  #include "pcm1792a.h" @@ -106,24 +107,35 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream,  	struct snd_soc_codec *codec = dai->codec;  	struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);  	int val = 0, ret; -	int pcm_format = params_format(params);  	priv->rate = params_rate(params);  	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {  	case SND_SOC_DAIFMT_RIGHT_J: -		if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || -		    pcm_format == SNDRV_PCM_FORMAT_S32_LE) -			val = 0x02; -		else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) -			val = 0x00; +		switch (params_width(params)) { +		case 24: +		case 32: +			val = 2; +			break; +		case 16: +			val = 0; +			break; +		default: +			return -EINVAL; +		}  		break;  	case SND_SOC_DAIFMT_I2S: -		if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || -		    pcm_format == SNDRV_PCM_FORMAT_S32_LE) -			val = 0x05; -		else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) -			val = 0x04; +		switch (params_width(params)) { +		case 24: +		case 32: +			val = 5; +			break; +		case 16: +			val = 4; +			break; +		default: +			return -EINVAL; +		}  		break;  	default:  		dev_err(codec->dev, "Invalid DAI format\n"); @@ -188,7 +200,7 @@ MODULE_DEVICE_TABLE(of, pcm1792a_of_match);  static const struct regmap_config pcm1792a_regmap = {  	.reg_bits		= 8,  	.val_bits		= 8, -	.max_register		= 24, +	.max_register		= 23,  	.reg_defaults		= pcm1792a_reg_defaults,  	.num_reg_defaults	= ARRAY_SIZE(pcm1792a_reg_defaults),  	.writeable_reg		= pcm1792a_writeable_reg, diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c new file mode 100644 index 00000000000..4d62230bd37 --- /dev/null +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -0,0 +1,71 @@ +/* + * Driver for the PCM512x CODECs + * + * Author:	Mark Brown <broonie@linaro.org> + *		Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/i2c.h> + +#include "pcm512x.h" + +static int pcm512x_i2c_probe(struct i2c_client *i2c, +			     const struct i2c_device_id *id) +{ +	struct regmap *regmap; + +	regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); + +	return pcm512x_probe(&i2c->dev, regmap); +} + +static int pcm512x_i2c_remove(struct i2c_client *i2c) +{ +	pcm512x_remove(&i2c->dev); +	return 0; +} + +static const struct i2c_device_id pcm512x_i2c_id[] = { +	{ "pcm5121", }, +	{ "pcm5122", }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); + +static const struct of_device_id pcm512x_of_match[] = { +	{ .compatible = "ti,pcm5121", }, +	{ .compatible = "ti,pcm5122", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, pcm512x_of_match); + +static struct i2c_driver pcm512x_i2c_driver = { +	.probe 		= pcm512x_i2c_probe, +	.remove 	= pcm512x_i2c_remove, +	.id_table	= pcm512x_i2c_id, +	.driver		= { +		.name	= "pcm512x", +		.owner	= THIS_MODULE, +		.of_match_table = pcm512x_of_match, +		.pm     = &pcm512x_pm_ops, +	}, +}; + +module_i2c_driver(pcm512x_i2c_driver); + +MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C"); +MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c new file mode 100644 index 00000000000..f297058c003 --- /dev/null +++ b/sound/soc/codecs/pcm512x-spi.c @@ -0,0 +1,69 @@ +/* + * Driver for the PCM512x CODECs + * + * Author:	Mark Brown <broonie@linaro.org> + *		Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include "pcm512x.h" + +static int pcm512x_spi_probe(struct spi_device *spi) +{ +	struct regmap *regmap; +	int ret; + +	regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); +	if (IS_ERR(regmap)) { +		ret = PTR_ERR(regmap); +		return ret; +	} + +	return pcm512x_probe(&spi->dev, regmap); +} + +static int pcm512x_spi_remove(struct spi_device *spi) +{ +	pcm512x_remove(&spi->dev); +	return 0; +} + +static const struct spi_device_id pcm512x_spi_id[] = { +	{ "pcm5121", }, +	{ "pcm5122", }, +	{ }, +}; +MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); + +static const struct of_device_id pcm512x_of_match[] = { +	{ .compatible = "ti,pcm5121", }, +	{ .compatible = "ti,pcm5122", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, pcm512x_of_match); + +static struct spi_driver pcm512x_spi_driver = { +	.probe		= pcm512x_spi_probe, +	.remove		= pcm512x_spi_remove, +	.id_table	= pcm512x_spi_id, +	.driver = { +		.name	= "pcm512x", +		.owner	= THIS_MODULE, +		.of_match_table = pcm512x_of_match, +		.pm     = &pcm512x_pm_ops, +	}, +}; + +module_spi_driver(pcm512x_spi_driver); diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c new file mode 100644 index 00000000000..163ec3855fd --- /dev/null +++ b/sound/soc/codecs/pcm512x.c @@ -0,0 +1,591 @@ +/* + * Driver for the PCM512x CODECs + * + * Author:	Mark Brown <broonie@linaro.org> + *		Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#include "pcm512x.h" + +#define PCM512x_NUM_SUPPLIES 3 +static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { +	"AVDD", +	"DVDD", +	"CPVDD", +}; + +struct pcm512x_priv { +	struct regmap *regmap; +	struct clk *sclk; +	struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; +	struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; +}; + +/* + * We can't use the same notifier block for more than one supply and + * there's no way I can see to get from a callback to the caller + * except container_of(). + */ +#define PCM512x_REGULATOR_EVENT(n) \ +static int pcm512x_regulator_event_##n(struct notifier_block *nb, \ +				      unsigned long event, void *data)    \ +{ \ +	struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ +						    supply_nb[n]); \ +	if (event & REGULATOR_EVENT_DISABLE) { \ +		regcache_mark_dirty(pcm512x->regmap);	\ +		regcache_cache_only(pcm512x->regmap, true);	\ +	} \ +	return 0; \ +} + +PCM512x_REGULATOR_EVENT(0) +PCM512x_REGULATOR_EVENT(1) +PCM512x_REGULATOR_EVENT(2) + +static const struct reg_default pcm512x_reg_defaults[] = { +	{ PCM512x_RESET,             0x00 }, +	{ PCM512x_POWER,             0x00 }, +	{ PCM512x_MUTE,              0x00 }, +	{ PCM512x_DSP,               0x00 }, +	{ PCM512x_PLL_REF,           0x00 }, +	{ PCM512x_DAC_ROUTING,       0x11 }, +	{ PCM512x_DSP_PROGRAM,       0x01 }, +	{ PCM512x_CLKDET,            0x00 }, +	{ PCM512x_AUTO_MUTE,         0x00 }, +	{ PCM512x_ERROR_DETECT,      0x00 }, +	{ PCM512x_DIGITAL_VOLUME_1,  0x00 }, +	{ PCM512x_DIGITAL_VOLUME_2,  0x30 }, +	{ PCM512x_DIGITAL_VOLUME_3,  0x30 }, +	{ PCM512x_DIGITAL_MUTE_1,    0x22 }, +	{ PCM512x_DIGITAL_MUTE_2,    0x00 }, +	{ PCM512x_DIGITAL_MUTE_3,    0x07 }, +	{ PCM512x_OUTPUT_AMPLITUDE,  0x00 }, +	{ PCM512x_ANALOG_GAIN_CTRL,  0x00 }, +	{ PCM512x_UNDERVOLTAGE_PROT, 0x00 }, +	{ PCM512x_ANALOG_MUTE_CTRL,  0x00 }, +	{ PCM512x_ANALOG_GAIN_BOOST, 0x00 }, +	{ PCM512x_VCOM_CTRL_1,       0x00 }, +	{ PCM512x_VCOM_CTRL_2,       0x01 }, +}; + +static bool pcm512x_readable(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case PCM512x_RESET: +	case PCM512x_POWER: +	case PCM512x_MUTE: +	case PCM512x_PLL_EN: +	case PCM512x_SPI_MISO_FUNCTION: +	case PCM512x_DSP: +	case PCM512x_GPIO_EN: +	case PCM512x_BCLK_LRCLK_CFG: +	case PCM512x_DSP_GPIO_INPUT: +	case PCM512x_MASTER_MODE: +	case PCM512x_PLL_REF: +	case PCM512x_PLL_COEFF_0: +	case PCM512x_PLL_COEFF_1: +	case PCM512x_PLL_COEFF_2: +	case PCM512x_PLL_COEFF_3: +	case PCM512x_PLL_COEFF_4: +	case PCM512x_DSP_CLKDIV: +	case PCM512x_DAC_CLKDIV: +	case PCM512x_NCP_CLKDIV: +	case PCM512x_OSR_CLKDIV: +	case PCM512x_MASTER_CLKDIV_1: +	case PCM512x_MASTER_CLKDIV_2: +	case PCM512x_FS_SPEED_MODE: +	case PCM512x_IDAC_1: +	case PCM512x_IDAC_2: +	case PCM512x_ERROR_DETECT: +	case PCM512x_I2S_1: +	case PCM512x_I2S_2: +	case PCM512x_DAC_ROUTING: +	case PCM512x_DSP_PROGRAM: +	case PCM512x_CLKDET: +	case PCM512x_AUTO_MUTE: +	case PCM512x_DIGITAL_VOLUME_1: +	case PCM512x_DIGITAL_VOLUME_2: +	case PCM512x_DIGITAL_VOLUME_3: +	case PCM512x_DIGITAL_MUTE_1: +	case PCM512x_DIGITAL_MUTE_2: +	case PCM512x_DIGITAL_MUTE_3: +	case PCM512x_GPIO_OUTPUT_1: +	case PCM512x_GPIO_OUTPUT_2: +	case PCM512x_GPIO_OUTPUT_3: +	case PCM512x_GPIO_OUTPUT_4: +	case PCM512x_GPIO_OUTPUT_5: +	case PCM512x_GPIO_OUTPUT_6: +	case PCM512x_GPIO_CONTROL_1: +	case PCM512x_GPIO_CONTROL_2: +	case PCM512x_OVERFLOW: +	case PCM512x_RATE_DET_1: +	case PCM512x_RATE_DET_2: +	case PCM512x_RATE_DET_3: +	case PCM512x_RATE_DET_4: +	case PCM512x_ANALOG_MUTE_DET: +	case PCM512x_GPIN: +	case PCM512x_DIGITAL_MUTE_DET: +	case PCM512x_OUTPUT_AMPLITUDE: +	case PCM512x_ANALOG_GAIN_CTRL: +	case PCM512x_UNDERVOLTAGE_PROT: +	case PCM512x_ANALOG_MUTE_CTRL: +	case PCM512x_ANALOG_GAIN_BOOST: +	case PCM512x_VCOM_CTRL_1: +	case PCM512x_VCOM_CTRL_2: +	case PCM512x_CRAM_CTRL: +		return true; +	default: +		/* There are 256 raw register addresses */ +		return reg < 0xff; +	} +} + +static bool pcm512x_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case PCM512x_PLL_EN: +	case PCM512x_OVERFLOW: +	case PCM512x_RATE_DET_1: +	case PCM512x_RATE_DET_2: +	case PCM512x_RATE_DET_3: +	case PCM512x_RATE_DET_4: +	case PCM512x_ANALOG_MUTE_DET: +	case PCM512x_GPIN: +	case PCM512x_DIGITAL_MUTE_DET: +	case PCM512x_CRAM_CTRL: +		return true; +	default: +		/* There are 256 raw register addresses */ +		return reg < 0xff; +	} +} + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); +static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); + +static const char * const pcm512x_dsp_program_texts[] = { +	"FIR interpolation with de-emphasis", +	"Low latency IIR with de-emphasis", +	"Fixed process flow", +	"High attenuation with de-emphasis", +	"Ringing-less low latency FIR", +}; + +static const unsigned int pcm512x_dsp_program_values[] = { +	1, +	2, +	3, +	5, +	7, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, +				  PCM512x_DSP_PROGRAM, 0, 0x1f, +				  pcm512x_dsp_program_texts, +				  pcm512x_dsp_program_values); + +static const char * const pcm512x_clk_missing_text[] = { +	"1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" +}; + +static const struct soc_enum pcm512x_clk_missing = +	SOC_ENUM_SINGLE(PCM512x_CLKDET, 0,  8, pcm512x_clk_missing_text); + +static const char * const pcm512x_autom_text[] = { +	"21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" +}; + +static const struct soc_enum pcm512x_autom_l = +	SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, +			pcm512x_autom_text); + +static const struct soc_enum pcm512x_autom_r = +	SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, +			pcm512x_autom_text); + +static const char * const pcm512x_ramp_rate_text[] = { +	"1 sample/update", "2 samples/update", "4 samples/update", +	"Immediate" +}; + +static const struct soc_enum pcm512x_vndf = +	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, +			pcm512x_ramp_rate_text); + +static const struct soc_enum pcm512x_vnuf = +	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, +			pcm512x_ramp_rate_text); + +static const struct soc_enum pcm512x_vedf = +	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, +			pcm512x_ramp_rate_text); + +static const char * const pcm512x_ramp_step_text[] = { +	"4dB/step", "2dB/step", "1dB/step", "0.5dB/step" +}; + +static const struct soc_enum pcm512x_vnds = +	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, +			pcm512x_ramp_step_text); + +static const struct soc_enum pcm512x_vnus = +	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, +			pcm512x_ramp_step_text); + +static const struct soc_enum pcm512x_veds = +	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, +			pcm512x_ramp_step_text); + +static const struct snd_kcontrol_new pcm512x_controls[] = { +SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, +		 PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), +SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, +	       PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), +SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, +	       PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), +SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, +	   PCM512x_RQMR_SHIFT, 1, 1), + +SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), +SOC_ENUM("DSP Program", pcm512x_dsp_program), + +SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), +SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), +SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), +SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, +	   PCM512x_ACTL_SHIFT, 1, 0), +SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, +	   PCM512x_AMLR_SHIFT, 1, 0), + +SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), +SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), +SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), +SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), +SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), +SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), +}; + +static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_OUTPUT("OUTL"), +SND_SOC_DAPM_OUTPUT("OUTR"), +}; + +static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { +	{ "DACL", NULL, "Playback" }, +	{ "DACR", NULL, "Playback" }, + +	{ "OUTL", NULL, "DACL" }, +	{ "OUTR", NULL, "DACR" }, +}; + +static int pcm512x_set_bias_level(struct snd_soc_codec *codec, +				  enum snd_soc_bias_level level) +{ +	struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev); +	int ret; + +	switch (level) { +	case SND_SOC_BIAS_ON: +	case SND_SOC_BIAS_PREPARE: +		break; + +	case SND_SOC_BIAS_STANDBY: +		ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, +					 PCM512x_RQST, 0); +		if (ret != 0) { +			dev_err(codec->dev, "Failed to remove standby: %d\n", +				ret); +			return ret; +		} +		break; + +	case SND_SOC_BIAS_OFF: +		ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, +					 PCM512x_RQST, PCM512x_RQST); +		if (ret != 0) { +			dev_err(codec->dev, "Failed to request standby: %d\n", +				ret); +			return ret; +		} +		break; +	} + +	codec->dapm.bias_level = level; + +	return 0; +} + +static struct snd_soc_dai_driver pcm512x_dai = { +	.name = "pcm512x-hifi", +	.playback = { +		.stream_name = "Playback", +		.channels_min = 2, +		.channels_max = 2, +		.rates = SNDRV_PCM_RATE_8000_192000, +		.formats = SNDRV_PCM_FMTBIT_S16_LE | +			   SNDRV_PCM_FMTBIT_S24_LE | +			   SNDRV_PCM_FMTBIT_S32_LE +	}, +}; + +static struct snd_soc_codec_driver pcm512x_codec_driver = { +	.set_bias_level = pcm512x_set_bias_level, +	.idle_bias_off = true, + +	.controls = pcm512x_controls, +	.num_controls = ARRAY_SIZE(pcm512x_controls), +	.dapm_widgets = pcm512x_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), +	.dapm_routes = pcm512x_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), +}; + +static const struct regmap_range_cfg pcm512x_range = { +	.name = "Pages", .range_min = PCM512x_VIRT_BASE, +	.range_max = PCM512x_MAX_REGISTER, +	.selector_reg = PCM512x_PAGE, +	.selector_mask = 0xff, +	.window_start = 0, .window_len = 0x100, +}; + +const struct regmap_config pcm512x_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.readable_reg = pcm512x_readable, +	.volatile_reg = pcm512x_volatile, + +	.ranges = &pcm512x_range, +	.num_ranges = 1, + +	.max_register = PCM512x_MAX_REGISTER, +	.reg_defaults = pcm512x_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(pcm512x_regmap); + +int pcm512x_probe(struct device *dev, struct regmap *regmap) +{ +	struct pcm512x_priv *pcm512x; +	int i, ret; + +	pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); +	if (!pcm512x) +		return -ENOMEM; + +	dev_set_drvdata(dev, pcm512x); +	pcm512x->regmap = regmap; + +	for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) +		pcm512x->supplies[i].supply = pcm512x_supply_names[i]; + +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), +				      pcm512x->supplies); +	if (ret != 0) { +		dev_err(dev, "Failed to get supplies: %d\n", ret); +		return ret; +	} + +	pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; +	pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; +	pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; + +	for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { +		ret = regulator_register_notifier(pcm512x->supplies[i].consumer, +						  &pcm512x->supply_nb[i]); +		if (ret != 0) { +			dev_err(dev, +				"Failed to register regulator notifier: %d\n", +				ret); +		} +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), +				    pcm512x->supplies); +	if (ret != 0) { +		dev_err(dev, "Failed to enable supplies: %d\n", ret); +		return ret; +	} + +	/* Reset the device, verifying I/O in the process for I2C */ +	ret = regmap_write(regmap, PCM512x_RESET, +			   PCM512x_RSTM | PCM512x_RSTR); +	if (ret != 0) { +		dev_err(dev, "Failed to reset device: %d\n", ret); +		goto err; +	} + +	ret = regmap_write(regmap, PCM512x_RESET, 0); +	if (ret != 0) { +		dev_err(dev, "Failed to reset device: %d\n", ret); +		goto err; +	} + +	pcm512x->sclk = devm_clk_get(dev, NULL); +	if (IS_ERR(pcm512x->sclk)) { +		if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) +			return -EPROBE_DEFER; + +		dev_info(dev, "No SCLK, using BCLK: %ld\n", +			 PTR_ERR(pcm512x->sclk)); + +		/* Disable reporting of missing SCLK as an error */ +		regmap_update_bits(regmap, PCM512x_ERROR_DETECT, +				   PCM512x_IDCH, PCM512x_IDCH); + +		/* Switch PLL input to BCLK */ +		regmap_update_bits(regmap, PCM512x_PLL_REF, +				   PCM512x_SREF, PCM512x_SREF); +	} else { +		ret = clk_prepare_enable(pcm512x->sclk); +		if (ret != 0) { +			dev_err(dev, "Failed to enable SCLK: %d\n", ret); +			return ret; +		} +	} + +	/* Default to standby mode */ +	ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, +				 PCM512x_RQST, PCM512x_RQST); +	if (ret != 0) { +		dev_err(dev, "Failed to request standby: %d\n", +			ret); +		goto err_clk; +	} + +	pm_runtime_set_active(dev); +	pm_runtime_enable(dev); +	pm_runtime_idle(dev); + +	ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, +				    &pcm512x_dai, 1); +	if (ret != 0) { +		dev_err(dev, "Failed to register CODEC: %d\n", ret); +		goto err_pm; +	} + +	return 0; + +err_pm: +	pm_runtime_disable(dev); +err_clk: +	if (!IS_ERR(pcm512x->sclk)) +		clk_disable_unprepare(pcm512x->sclk); +err: +	regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), +				     pcm512x->supplies); +	return ret; +} +EXPORT_SYMBOL_GPL(pcm512x_probe); + +void pcm512x_remove(struct device *dev) +{ +	struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); + +	snd_soc_unregister_codec(dev); +	pm_runtime_disable(dev); +	if (!IS_ERR(pcm512x->sclk)) +		clk_disable_unprepare(pcm512x->sclk); +	regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), +			       pcm512x->supplies); +} +EXPORT_SYMBOL_GPL(pcm512x_remove); + +#ifdef CONFIG_PM_RUNTIME +static int pcm512x_suspend(struct device *dev) +{ +	struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); +	int ret; + +	ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, +				 PCM512x_RQPD, PCM512x_RQPD); +	if (ret != 0) { +		dev_err(dev, "Failed to request power down: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), +				     pcm512x->supplies); +	if (ret != 0) { +		dev_err(dev, "Failed to disable supplies: %d\n", ret); +		return ret; +	} + +	if (!IS_ERR(pcm512x->sclk)) +		clk_disable_unprepare(pcm512x->sclk); + +	return 0; +} + +static int pcm512x_resume(struct device *dev) +{ +	struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); +	int ret; + +	if (!IS_ERR(pcm512x->sclk)) { +		ret = clk_prepare_enable(pcm512x->sclk); +		if (ret != 0) { +			dev_err(dev, "Failed to enable SCLK: %d\n", ret); +			return ret; +		} +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), +				    pcm512x->supplies); +	if (ret != 0) { +		dev_err(dev, "Failed to enable supplies: %d\n", ret); +		return ret; +	} + +	regcache_cache_only(pcm512x->regmap, false); +	ret = regcache_sync(pcm512x->regmap); +	if (ret != 0) { +		dev_err(dev, "Failed to sync cache: %d\n", ret); +		return ret; +	} + +	ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, +				 PCM512x_RQPD, 0); +	if (ret != 0) { +		dev_err(dev, "Failed to remove power down: %d\n", ret); +		return ret; +	} + +	return 0; +} +#endif + +const struct dev_pm_ops pcm512x_pm_ops = { +	SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) +}; +EXPORT_SYMBOL_GPL(pcm512x_pm_ops); + +MODULE_DESCRIPTION("ASoC PCM512x codec driver"); +MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h new file mode 100644 index 00000000000..6ee76aaca09 --- /dev/null +++ b/sound/soc/codecs/pcm512x.h @@ -0,0 +1,171 @@ +/* + * Driver for the PCM512x CODECs + * + * Author:	Mark Brown <broonie@linaro.org> + *		Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _SND_SOC_PCM512X +#define _SND_SOC_PCM512X + +#include <linux/pm.h> +#include <linux/regmap.h> + +#define PCM512x_VIRT_BASE 0x100 +#define PCM512x_PAGE_LEN  0x100 +#define PCM512x_PAGE_BASE(n)  (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n)) + +#define PCM512x_PAGE              0 + +#define PCM512x_RESET             (PCM512x_PAGE_BASE(0) +   1) +#define PCM512x_POWER             (PCM512x_PAGE_BASE(0) +   2) +#define PCM512x_MUTE              (PCM512x_PAGE_BASE(0) +   3) +#define PCM512x_PLL_EN            (PCM512x_PAGE_BASE(0) +   4) +#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) +   6) +#define PCM512x_DSP               (PCM512x_PAGE_BASE(0) +   7) +#define PCM512x_GPIO_EN           (PCM512x_PAGE_BASE(0) +   8) +#define PCM512x_BCLK_LRCLK_CFG    (PCM512x_PAGE_BASE(0) +   9) +#define PCM512x_DSP_GPIO_INPUT    (PCM512x_PAGE_BASE(0) +  10) +#define PCM512x_MASTER_MODE       (PCM512x_PAGE_BASE(0) +  12) +#define PCM512x_PLL_REF           (PCM512x_PAGE_BASE(0) +  13) +#define PCM512x_PLL_COEFF_0       (PCM512x_PAGE_BASE(0) +  20) +#define PCM512x_PLL_COEFF_1       (PCM512x_PAGE_BASE(0) +  21) +#define PCM512x_PLL_COEFF_2       (PCM512x_PAGE_BASE(0) +  22) +#define PCM512x_PLL_COEFF_3       (PCM512x_PAGE_BASE(0) +  23) +#define PCM512x_PLL_COEFF_4       (PCM512x_PAGE_BASE(0) +  24) +#define PCM512x_DSP_CLKDIV        (PCM512x_PAGE_BASE(0) +  27) +#define PCM512x_DAC_CLKDIV        (PCM512x_PAGE_BASE(0) +  28) +#define PCM512x_NCP_CLKDIV        (PCM512x_PAGE_BASE(0) +  29) +#define PCM512x_OSR_CLKDIV        (PCM512x_PAGE_BASE(0) +  30) +#define PCM512x_MASTER_CLKDIV_1   (PCM512x_PAGE_BASE(0) +  32) +#define PCM512x_MASTER_CLKDIV_2   (PCM512x_PAGE_BASE(0) +  33) +#define PCM512x_FS_SPEED_MODE     (PCM512x_PAGE_BASE(0) +  34) +#define PCM512x_IDAC_1            (PCM512x_PAGE_BASE(0) +  35) +#define PCM512x_IDAC_2            (PCM512x_PAGE_BASE(0) +  36) +#define PCM512x_ERROR_DETECT      (PCM512x_PAGE_BASE(0) +  37) +#define PCM512x_I2S_1             (PCM512x_PAGE_BASE(0) +  40) +#define PCM512x_I2S_2             (PCM512x_PAGE_BASE(0) +  41) +#define PCM512x_DAC_ROUTING       (PCM512x_PAGE_BASE(0) +  42) +#define PCM512x_DSP_PROGRAM       (PCM512x_PAGE_BASE(0) +  43) +#define PCM512x_CLKDET            (PCM512x_PAGE_BASE(0) +  44) +#define PCM512x_AUTO_MUTE         (PCM512x_PAGE_BASE(0) +  59) +#define PCM512x_DIGITAL_VOLUME_1  (PCM512x_PAGE_BASE(0) +  60) +#define PCM512x_DIGITAL_VOLUME_2  (PCM512x_PAGE_BASE(0) +  61) +#define PCM512x_DIGITAL_VOLUME_3  (PCM512x_PAGE_BASE(0) +  62) +#define PCM512x_DIGITAL_MUTE_1    (PCM512x_PAGE_BASE(0) +  63) +#define PCM512x_DIGITAL_MUTE_2    (PCM512x_PAGE_BASE(0) +  64) +#define PCM512x_DIGITAL_MUTE_3    (PCM512x_PAGE_BASE(0) +  65) +#define PCM512x_GPIO_OUTPUT_1     (PCM512x_PAGE_BASE(0) +  80) +#define PCM512x_GPIO_OUTPUT_2     (PCM512x_PAGE_BASE(0) +  81) +#define PCM512x_GPIO_OUTPUT_3     (PCM512x_PAGE_BASE(0) +  82) +#define PCM512x_GPIO_OUTPUT_4     (PCM512x_PAGE_BASE(0) +  83) +#define PCM512x_GPIO_OUTPUT_5     (PCM512x_PAGE_BASE(0) +  84) +#define PCM512x_GPIO_OUTPUT_6     (PCM512x_PAGE_BASE(0) +  85) +#define PCM512x_GPIO_CONTROL_1    (PCM512x_PAGE_BASE(0) +  86) +#define PCM512x_GPIO_CONTROL_2    (PCM512x_PAGE_BASE(0) +  87) +#define PCM512x_OVERFLOW          (PCM512x_PAGE_BASE(0) +  90) +#define PCM512x_RATE_DET_1        (PCM512x_PAGE_BASE(0) +  91) +#define PCM512x_RATE_DET_2        (PCM512x_PAGE_BASE(0) +  92) +#define PCM512x_RATE_DET_3        (PCM512x_PAGE_BASE(0) +  93) +#define PCM512x_RATE_DET_4        (PCM512x_PAGE_BASE(0) +  94) +#define PCM512x_ANALOG_MUTE_DET   (PCM512x_PAGE_BASE(0) + 108) +#define PCM512x_GPIN              (PCM512x_PAGE_BASE(0) + 119) +#define PCM512x_DIGITAL_MUTE_DET  (PCM512x_PAGE_BASE(0) + 120) + +#define PCM512x_OUTPUT_AMPLITUDE  (PCM512x_PAGE_BASE(1) +   1) +#define PCM512x_ANALOG_GAIN_CTRL  (PCM512x_PAGE_BASE(1) +   2) +#define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) +   5) +#define PCM512x_ANALOG_MUTE_CTRL  (PCM512x_PAGE_BASE(1) +   6) +#define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) +   7) +#define PCM512x_VCOM_CTRL_1       (PCM512x_PAGE_BASE(1) +   8) +#define PCM512x_VCOM_CTRL_2       (PCM512x_PAGE_BASE(1) +   9) + +#define PCM512x_CRAM_CTRL         (PCM512x_PAGE_BASE(44) +  1) + +#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(44) +  1) + +/* Page 0, Register 1 - reset */ +#define PCM512x_RSTR (1 << 0) +#define PCM512x_RSTM (1 << 4) + +/* Page 0, Register 2 - power */ +#define PCM512x_RQPD       (1 << 0) +#define PCM512x_RQPD_SHIFT 0 +#define PCM512x_RQST       (1 << 4) +#define PCM512x_RQST_SHIFT 4 + +/* Page 0, Register 3 - mute */ +#define PCM512x_RQMR_SHIFT 0 +#define PCM512x_RQML_SHIFT 4 + +/* Page 0, Register 4 - PLL */ +#define PCM512x_PLCE       (1 << 0) +#define PCM512x_RLCE_SHIFT 0 +#define PCM512x_PLCK       (1 << 4) +#define PCM512x_PLCK_SHIFT 4 + +/* Page 0, Register 7 - DSP */ +#define PCM512x_SDSL       (1 << 0) +#define PCM512x_SDSL_SHIFT 0 +#define PCM512x_DEMP       (1 << 4) +#define PCM512x_DEMP_SHIFT 4 + +/* Page 0, Register 13 - PLL reference */ +#define PCM512x_SREF (1 << 4) + +/* Page 0, Register 37 - Error detection */ +#define PCM512x_IPLK (1 << 0) +#define PCM512x_DCAS (1 << 1) +#define PCM512x_IDCM (1 << 2) +#define PCM512x_IDCH (1 << 3) +#define PCM512x_IDSK (1 << 4) +#define PCM512x_IDBK (1 << 5) +#define PCM512x_IDFS (1 << 6) + +/* Page 0, Register 42 - DAC routing */ +#define PCM512x_AUPR_SHIFT 0 +#define PCM512x_AUPL_SHIFT 4 + +/* Page 0, Register 59 - auto mute */ +#define PCM512x_ATMR_SHIFT 0 +#define PCM512x_ATML_SHIFT 4 + +/* Page 0, Register 63 - ramp rates */ +#define PCM512x_VNDF_SHIFT 6 +#define PCM512x_VNDS_SHIFT 4 +#define PCM512x_VNUF_SHIFT 2 +#define PCM512x_VNUS_SHIFT 0 + +/* Page 0, Register 64 - emergency ramp rates */ +#define PCM512x_VEDF_SHIFT 6 +#define PCM512x_VEDS_SHIFT 4 + +/* Page 0, Register 65 - Digital mute enables */ +#define PCM512x_ACTL_SHIFT 2 +#define PCM512x_AMLE_SHIFT 1 +#define PCM512x_AMLR_SHIFT 0 + +/* Page 1, Register 2 - analog volume control */ +#define PCM512x_RAGN_SHIFT 0 +#define PCM512x_LAGN_SHIFT 4 + +/* Page 1, Register 7 - analog boost control */ +#define PCM512x_AGBR_SHIFT 0 +#define PCM512x_AGBL_SHIFT 4 + +extern const struct dev_pm_ops pcm512x_pm_ops; +extern const struct regmap_config pcm512x_regmap; + +int pcm512x_probe(struct device *dev, struct regmap *regmap); +void pcm512x_remove(struct device *dev); + +#endif diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c new file mode 100644 index 00000000000..7b82fbe0d14 --- /dev/null +++ b/sound/soc/codecs/rl6231.c @@ -0,0 +1,152 @@ +/* + * rl6231.c - RL6231 class device shared support + * + * Copyright 2014 Realtek Semiconductor Corp. + * + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rl6231.h" + +/** + * rl6231_calc_dmic_clk - Calculate the parameter of dmic. + * + * @rate: base clock rate. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +int rl6231_calc_dmic_clk(int rate) +{ +	int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL; +	int i, red, bound, temp; + +	red = 3000000 * 12; +	for (i = 0; i < ARRAY_SIZE(div); i++) { +		bound = div[i] * 3000000; +		if (rate > bound) +			continue; +		temp = bound - rate; +		if (temp < red) { +			red = temp; +			idx = i; +		} +	} + +	return idx; +} +EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk); + +/** + * rl6231_pll_calc - Calcualte PLL M/N/K code. + * @freq_in: external clock provided to codec. + * @freq_out: target clock which codec works on. + * @pll_code: Pointer to structure with M, N, K and bypass flag. + * + * Calcualte M/N/K code to configure PLL for codec. + * + * Returns 0 for success or negative error code. + */ +int rl6231_pll_calc(const unsigned int freq_in, +	const unsigned int freq_out, struct rl6231_pll_code *pll_code) +{ +	int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX; +	int k, red, n_t, pll_out, in_t, out_t; +	int n = 0, m = 0, m_t = 0; +	int red_t = abs(freq_out - freq_in); +	bool bypass = false; + +	if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in) +		return -EINVAL; + +	k = 100000000 / freq_out - 2; +	if (k > RL6231_PLL_K_MAX) +		k = RL6231_PLL_K_MAX; +	for (n_t = 0; n_t <= max_n; n_t++) { +		in_t = freq_in / (k + 2); +		pll_out = freq_out / (n_t + 2); +		if (in_t < 0) +			continue; +		if (in_t == pll_out) { +			bypass = true; +			n = n_t; +			goto code_find; +		} +		red = abs(in_t - pll_out); +		if (red < red_t) { +			bypass = true; +			n = n_t; +			m = m_t; +			if (red == 0) +				goto code_find; +			red_t = red; +		} +		for (m_t = 0; m_t <= max_m; m_t++) { +			out_t = in_t / (m_t + 2); +			red = abs(out_t - pll_out); +			if (red < red_t) { +				bypass = false; +				n = n_t; +				m = m_t; +				if (red == 0) +					goto code_find; +				red_t = red; +			} +		} +	} +	pr_debug("Only get approximation about PLL\n"); + +code_find: + +	pll_code->m_bp = bypass; +	pll_code->m_code = m; +	pll_code->n_code = n; +	pll_code->k_code = k; +	return 0; +} +EXPORT_SYMBOL_GPL(rl6231_pll_calc); + +int rl6231_get_clk_info(int sclk, int rate) +{ +	int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + +	if (sclk <= 0 || rate <= 0) +		return -EINVAL; + +	rate = rate << 8; +	for (i = 0; i < ARRAY_SIZE(pd); i++) +		if (sclk == rate * pd[i]) +			return i; + +	return -EINVAL; +} +EXPORT_SYMBOL_GPL(rl6231_get_clk_info); + +MODULE_DESCRIPTION("RL6231 class device shared support"); +MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rl6231.h b/sound/soc/codecs/rl6231.h new file mode 100644 index 00000000000..0f7b057ed73 --- /dev/null +++ b/sound/soc/codecs/rl6231.h @@ -0,0 +1,34 @@ +/* + * rl6231.h - RL6231 class device shared support + * + * Copyright 2014 Realtek Semiconductor Corp. + * + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RL6231_H__ +#define __RL6231_H__ + +#define RL6231_PLL_INP_MAX	40000000 +#define RL6231_PLL_INP_MIN	256000 +#define RL6231_PLL_N_MAX	0x1ff +#define RL6231_PLL_K_MAX	0x1f +#define RL6231_PLL_M_MAX	0xf + +struct rl6231_pll_code { +	bool m_bp; /* Indicates bypass m code or not. */ +	int m_code; +	int n_code; +	int k_code; +}; + +int rl6231_calc_dmic_clk(int rate); +int rl6231_pll_calc(const unsigned int freq_in, +	const unsigned int freq_out, struct rl6231_pll_code *pll_code); +int rl6231_get_clk_info(int sclk, int rate); + +#endif /* __RL6231_H__ */ diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 912c9cbc272..30e23470857 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -188,7 +188,7 @@ static unsigned int mic_bst_tlv[] = {  static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,  		struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = rt5631->dmic_used_flag; @@ -199,7 +199,7 @@ static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,  static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,  		struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);  	rt5631->dmic_used_flag = ucontrol->value.integer.value[0]; @@ -210,26 +210,22 @@ static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,  static const char *rt5631_input_mode[] = {  	"Single ended", "Differential"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, -	RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); +static SOC_ENUM_SINGLE_DECL(rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, +			    RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); -static const SOC_ENUM_SINGLE_DECL( -	rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, -	RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); +static SOC_ENUM_SINGLE_DECL(rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, +			    RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode);  /* MONO Input Type */ -static const SOC_ENUM_SINGLE_DECL( -	rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, -	RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); +static SOC_ENUM_SINGLE_DECL(rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, +			    RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode);  /* SPK Ratio Gain Control */  static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x",  			"1.56x", "1.68x", "1.99x", "2.34x"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, -	RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); +static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, +			    RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio);  static const struct snd_kcontrol_new rt5631_snd_controls[] = {  	/* MIC */ @@ -759,9 +755,8 @@ static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = {  /* Left SPK Volume Input */  static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, -	RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, +			    RT5631_L_EN_SHIFT, rt5631_spkvoll_sel);  static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =  	SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum); @@ -769,9 +764,8 @@ static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =  /* Left HP Volume Input */  static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, -	RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, +			    RT5631_L_EN_SHIFT, rt5631_hpvoll_sel);  static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =  	SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum); @@ -779,9 +773,8 @@ static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =  /* Left Out Volume Input */  static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, -	RT5631_L_EN_SHIFT, rt5631_outvoll_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, +			    RT5631_L_EN_SHIFT, rt5631_outvoll_sel);  static const struct snd_kcontrol_new rt5631_outvoll_mux_control =  	SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum); @@ -789,9 +782,8 @@ static const struct snd_kcontrol_new rt5631_outvoll_mux_control =  /* Right Out Volume Input */  static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, -	RT5631_R_EN_SHIFT, rt5631_outvolr_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, +			    RT5631_R_EN_SHIFT, rt5631_outvolr_sel);  static const struct snd_kcontrol_new rt5631_outvolr_mux_control =  	SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum); @@ -799,9 +791,8 @@ static const struct snd_kcontrol_new rt5631_outvolr_mux_control =  /* Right HP Volume Input */  static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, -	RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, +			    RT5631_R_EN_SHIFT, rt5631_hpvolr_sel);  static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =  	SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum); @@ -809,9 +800,8 @@ static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =  /* Right SPK Volume Input */  static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, -	RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, +			    RT5631_R_EN_SHIFT, rt5631_spkvolr_sel);  static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =  	SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum); @@ -820,9 +810,8 @@ static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =  static const char *rt5631_spol_src_sel[] = {  	"SPOLMIX", "MONOIN_RX", "VDAC", "DACL"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, -	RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, +			    RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel);  static const struct snd_kcontrol_new rt5631_spol_mux_control =  	SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum); @@ -831,9 +820,8 @@ static const struct snd_kcontrol_new rt5631_spol_mux_control =  static const char *rt5631_spor_src_sel[] = {  	"SPORMIX", "MONOIN_RX", "VDAC", "DACR"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, -	RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, +			    RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel);  static const struct snd_kcontrol_new rt5631_spor_mux_control =  	SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum); @@ -841,9 +829,8 @@ static const struct snd_kcontrol_new rt5631_spor_mux_control =  /* MONO Input */  static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, -	RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, +			    RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel);  static const struct snd_kcontrol_new rt5631_mono_mux_control =  	SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum); @@ -851,9 +838,8 @@ static const struct snd_kcontrol_new rt5631_mono_mux_control =  /* Left HPO Input */  static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, -	RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, +			    RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel);  static const struct snd_kcontrol_new rt5631_hpl_mux_control =  	SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum); @@ -861,9 +847,8 @@ static const struct snd_kcontrol_new rt5631_hpl_mux_control =  /* Right HPO Input */  static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, -	RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, +			    RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel);  static const struct snd_kcontrol_new rt5631_hpr_mux_control =  	SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum); @@ -1585,15 +1570,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)  {  	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);  	unsigned int val; -	int ret; - -	codec->control_data = rt5631->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	val = rt5631_read_index(codec, RT5631_ADDA_MIXER_INTL_REG3);  	if (val & 0x0002) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index c26a8f814b1..de80e89b5fd 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1,5 +1,5 @@  /* - * rt5640.c  --  RT5640 ALSA SoC audio codec driver + * rt5640.c  --  RT5640/RT5639 ALSA SoC audio codec driver   *   * Copyright 2011 Realtek Semiconductor Corp.   * Author: Johnny Hsu <johnnyhsu@realtek.com> @@ -18,9 +18,11 @@  #include <linux/gpio.h>  #include <linux/i2c.h>  #include <linux/regmap.h> +#include <linux/of.h>  #include <linux/of_gpio.h>  #include <linux/platform_device.h>  #include <linux/spi/spi.h> +#include <linux/acpi.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -29,6 +31,7 @@  #include <sound/initval.h>  #include <sound/tlv.h> +#include "rl6231.h"  #include "rt5640.h"  #define RT5640_DEVICE_ID 0x6231 @@ -58,7 +61,7 @@ static struct reg_default init_list[] = {  };  #define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list) -static const struct reg_default rt5640_reg[RT5640_VENDOR_ID2 + 1] = { +static const struct reg_default rt5640_reg[] = {  	{ 0x00, 0x000e },  	{ 0x01, 0xc8c8 },  	{ 0x02, 0xc8c8 }, @@ -360,25 +363,24 @@ static unsigned int bst_tlv[] = {  static const char * const rt5640_data_select[] = {  	"Normal", "left copy to right", "right copy to left", "Swap"}; -static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, -				RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, -				RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, -				RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, -				RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF2_ADC_SEL_SFT, rt5640_data_select);  /* Class D speaker gain ratio */  static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x",  	"2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, -	RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); +static SOC_ENUM_SINGLE_DECL(rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, +			    RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);  static const struct snd_kcontrol_new rt5640_snd_controls[] = {  	/* Speaker Output Volume */ @@ -398,18 +400,13 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {  		RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),  	SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT,  		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv), -	/* MONO Output Control */ -	SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, -				RT5640_L_MUTE_SFT, 1, 1), +  	/* DAC Digital Volume */  	SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,  		RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),  	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,  			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,  			175, 0, dac_vol_tlv), -	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL, -			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, -			175, 0, dac_vol_tlv),  	/* IN1/IN2 Control */  	SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,  		RT5640_BST_SFT1, 8, 0, bst_tlv), @@ -441,6 +438,15 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {  	SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum),  }; +static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = { +	/* MONO Output Control */ +	SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT, +		1, 1), + +	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL, +		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv), +}; +  /**   * set_dmic_clk - Set parameter of dmic.   * @@ -448,30 +454,16 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {   * @kcontrol: The kcontrol of this widget.   * @event: Event id.   * - * Choose dmic clock between 1MHz and 3MHz. - * It is better for clock to approximate 3MHz.   */  static int set_dmic_clk(struct snd_soc_dapm_widget *w,  	struct snd_kcontrol *kcontrol, int event)  {  	struct snd_soc_codec *codec = w->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	int div[] = {2, 3, 4, 6, 8, 12}; -	int idx = -EINVAL, i; -	int rate, red, bound, temp; - -	rate = rt5640->sysclk; -	red = 3000000 * 12; -	for (i = 0; i < ARRAY_SIZE(div); i++) { -		bound = div[i] * 3000000; -		if (rate > bound) -			continue; -		temp = bound - rate; -		if (temp < red) { -			red = temp; -			idx = i; -		} -	} +	int idx = -EINVAL; + +	idx = rl6231_calc_dmic_clk(rt5640->sysclk); +  	if (idx < 0)  		dev_err(codec->dev, "Failed to set DMIC clock\n");  	else @@ -480,14 +472,14 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,  	return idx;  } -static int check_sysclk1_source(struct snd_soc_dapm_widget *source, +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,  			 struct snd_soc_dapm_widget *sink)  {  	unsigned int val;  	val = snd_soc_read(source->codec, RT5640_GLB_CLK);  	val &= RT5640_SCLK_SRC_MASK; -	if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T) +	if (val == RT5640_SCLK_SRC_PLL1)  		return 1;  	else  		return 0; @@ -554,6 +546,20 @@ static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = {  			RT5640_M_ANC_DAC_R_SFT, 1, 1),  }; +static const struct snd_kcontrol_new rt5639_sto_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5639_sto_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_R2_SFT, 1, 1), +}; +  static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = {  	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER,  			RT5640_M_DAC_L1_MONO_L_SFT, 1, 1), @@ -676,6 +682,30 @@ static const struct snd_kcontrol_new rt5640_out_r_mix[] = {  			RT5640_M_DAC_R1_OM_R_SFT, 1, 1),  }; +static const struct snd_kcontrol_new rt5639_out_l_mix[] = { +	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_BST1_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_IN_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_RM_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5639_out_r_mix[] = { +	SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_BST4_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_BST1_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_IN_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_RM_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_DAC_R1_OM_R_SFT, 1, 1), +}; +  static const struct snd_kcontrol_new rt5640_spo_l_mix[] = {  	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER,  			RT5640_M_DAC_R1_SPM_L_SFT, 1, 1), @@ -707,6 +737,13 @@ static const struct snd_kcontrol_new rt5640_hpo_mix[] = {  			RT5640_M_HPVOL_HM_SFT, 1, 1),  }; +static const struct snd_kcontrol_new rt5639_hpo_mix[] = { +	SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER, +			RT5640_M_DAC1_HM_SFT, 1, 1), +	SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER, +			RT5640_M_HPVOL_HM_SFT, 1, 1), +}; +  static const struct snd_kcontrol_new rt5640_lout_mix[] = {  	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER,  			RT5640_M_DAC_L1_LM_SFT, 1, 1), @@ -752,9 +789,8 @@ static const char * const rt5640_stereo_adc1_src[] = {  	"DIG MIX", "ADC"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, -	RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, +			    RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src);  static const struct snd_kcontrol_new rt5640_sto_adc_1_mux =  	SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum); @@ -763,9 +799,8 @@ static const char * const rt5640_stereo_adc2_src[] = {  	"DMIC1", "DMIC2", "DIG MIX"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, -	RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, +			    RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src);  static const struct snd_kcontrol_new rt5640_sto_adc_2_mux =  	SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum); @@ -775,9 +810,8 @@ static const char * const rt5640_mono_adc_l1_src[] = {  	"Mono DAC MIXL", "ADCL"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src);  static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux =  	SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum); @@ -786,9 +820,8 @@ static const char * const rt5640_mono_adc_l2_src[] = {  	"DMIC L1", "DMIC L2", "Mono DAC MIXL"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src);  static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux =  	SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum); @@ -797,9 +830,8 @@ static const char * const rt5640_mono_adc_r1_src[] = {  	"Mono DAC MIXR", "ADCR"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src);  static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux =  	SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum); @@ -808,9 +840,8 @@ static const char * const rt5640_mono_adc_r2_src[] = {  	"DMIC R1", "DMIC R2", "Mono DAC MIXR"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src);  static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux =  	SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum); @@ -825,12 +856,12 @@ static int rt5640_dac_l2_values[] = {  	3,  }; -static const SOC_VALUE_ENUM_SINGLE_DECL( -	rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, -	0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum, +				  RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, +				  0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);  static const struct snd_kcontrol_new rt5640_dac_l2_mux = -	SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); +	SOC_DAPM_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);  static const char * const rt5640_dac_r2_src[] = {  	"IF2", @@ -840,9 +871,9 @@ static int rt5640_dac_r2_values[] = {  	0,  }; -static const SOC_VALUE_ENUM_SINGLE_DECL( -	rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, -	0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_r2_enum, +				  RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, +				  0x3, rt5640_dac_r2_src, rt5640_dac_r2_values);  static const struct snd_kcontrol_new rt5640_dac_r2_mux =  	SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum); @@ -859,74 +890,26 @@ static int rt5640_dai_iis_map_values[] = {  	7,  }; -static const SOC_VALUE_ENUM_SINGLE_DECL( -	rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, -	0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum, +				  RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, +				  0x7, rt5640_dai_iis_map, +				  rt5640_dai_iis_map_values);  static const struct snd_kcontrol_new rt5640_dai_mux = -	SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); +	SOC_DAPM_ENUM("DAI select", rt5640_dai_iis_map_enum);  /* SDI select */  static const char * const rt5640_sdi_sel[] = {  	"IF1", "IF2"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_sdi_sel_enum, RT5640_I2S2_SDP, -	RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); +static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP, +			    RT5640_I2S2_SDI_SFT, rt5640_sdi_sel);  static const struct snd_kcontrol_new rt5640_sdi_mux =  	SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); -static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w, -	struct snd_kcontrol *kcontrol, int event) -{ -	struct snd_soc_codec *codec = w->codec; - -	switch (event) { -	case SND_SOC_DAPM_PRE_PMU: -		snd_soc_update_bits(codec, RT5640_GPIO_CTRL1, -			RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK, -			RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA); -		snd_soc_update_bits(codec, RT5640_DMIC, -			RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK | -			RT5640_DMIC_1_DP_MASK, -			RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING | -			RT5640_DMIC_1_DP_IN1P); -		break; - -	default: -		return 0; -	} - -	return 0; -} - -static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w, -	struct snd_kcontrol *kcontrol, int event) -{ -	struct snd_soc_codec *codec = w->codec; - -	switch (event) { -	case SND_SOC_DAPM_PRE_PMU: -		snd_soc_update_bits(codec, RT5640_GPIO_CTRL1, -			RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK, -			RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA); -		snd_soc_update_bits(codec, RT5640_DMIC, -			RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK | -			RT5640_DMIC_2_DP_MASK, -			RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING | -			RT5640_DMIC_2_DP_IN1N); -		break; - -	default: -		return 0; -	} - -	return 0; -} - -void hp_amp_power_on(struct snd_soc_codec *codec) +static void hp_amp_power_on(struct snd_soc_codec *codec)  {  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); @@ -1060,12 +1043,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,  		set_dmic_clk, SND_SOC_DAPM_PRE_PMU), -	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, -		RT5640_DMIC_1_EN_SFT, 0, rt5640_set_dmic1_event, -		SND_SOC_DAPM_PRE_PMU), -	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, -		RT5640_DMIC_2_EN_SFT, 0, rt5640_set_dmic2_event, -		SND_SOC_DAPM_PRE_PMU), +	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, RT5640_DMIC_1_EN_SFT, 0, +		NULL, 0), +	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, RT5640_DMIC_2_EN_SFT, 0, +		NULL, 0),  	/* Boost */  	SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2,  		RT5640_PWR_BST1_BIT, 0, NULL, 0), @@ -1152,26 +1133,15 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), -	/* Audio DSP */ -	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), -	/* ANC */ -	SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0), +  	/* Output Side */  	/* DAC mixer before sound effect  */  	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,  		rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)),  	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,  		rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)), -	/* DAC2 channel Mux */ -	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, -				&rt5640_dac_l2_mux), -	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, -				&rt5640_dac_r2_mux), +  	/* DAC Mixer */ -	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, -		rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)), -	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, -		rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),  	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,  		rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)),  	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, @@ -1183,21 +1153,14 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	/* DACs */  	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1,  			RT5640_PWR_DAC_L1_BIT, 0), -	SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, -			RT5640_PWR_DAC_L2_BIT, 0),  	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1,  			RT5640_PWR_DAC_R1_BIT, 0), -	SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, -			RT5640_PWR_DAC_R2_BIT, 0), +  	/* SPK/OUT Mixer */  	SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,  		0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),  	SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,  		0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)), -	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, -		0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)), -	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, -		0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),  	/* Ouput Volume */  	SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,  		RT5640_PWR_SV_L_BIT, 0, NULL, 0), @@ -1216,16 +1179,8 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  		0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),  	SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,  		0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)), -	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, -		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), -	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, -		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),  	SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0,  		rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)), -	SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0, -		rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), -	SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, -		RT5640_PWR_MA_BIT, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,  		0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),  	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, @@ -1257,10 +1212,69 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("HPOR"),  	SND_SOC_DAPM_OUTPUT("LOUTL"),  	SND_SOC_DAPM_OUTPUT("LOUTR"), +}; + +static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = { +	/* Audio DSP */ +	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), +	/* ANC */ +	SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* DAC2 channel Mux */ +	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_l2_mux), +	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_r2_mux), + +	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)), + +	SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_R2_BIT, +		0), +	SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_L2_BIT, +		0), + +	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, +		0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, +		0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)), + +	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, +		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), +	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, +		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), + +	SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0, +		rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), +	SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, +		RT5640_PWR_MA_BIT, 0, NULL, 0), +  	SND_SOC_DAPM_OUTPUT("MONOP"),  	SND_SOC_DAPM_OUTPUT("MONON"),  }; +static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = { +	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5639_sto_dac_l_mix, ARRAY_SIZE(rt5639_sto_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5639_sto_dac_r_mix, ARRAY_SIZE(rt5639_sto_dac_r_mix)), + +	SND_SOC_DAPM_SUPPLY("DAC L2 Filter", RT5640_PWR_DIG1, +		RT5640_PWR_DAC_L2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC R2 Filter", RT5640_PWR_DIG1, +		RT5640_PWR_DAC_R2_BIT, 0, NULL, 0), + +	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, +		0, rt5639_out_l_mix, ARRAY_SIZE(rt5639_out_l_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, +		0, rt5639_out_r_mix, ARRAY_SIZE(rt5639_out_r_mix)), + +	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, +		rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)), +	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, +		rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)), +}; +  static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"IN1P", NULL, "LDO2"},  	{"IN2P", NULL, "LDO2"}, @@ -1329,22 +1343,22 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},  	{"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},  	{"Stereo ADC MIXL", NULL, "Stereo Filter"}, -	{"Stereo Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},  	{"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},  	{"Stereo ADC MIXR", NULL, "Stereo Filter"}, -	{"Stereo Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},  	{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},  	{"Mono ADC MIXL", NULL, "Mono Left Filter"}, -	{"Mono Left Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},  	{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},  	{"Mono ADC MIXR", NULL, "Mono Right Filter"}, -	{"Mono Right Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"IF2 ADC L", NULL, "Mono ADC MIXL"},  	{"IF2 ADC R", NULL, "Mono ADC MIXR"}, @@ -1402,71 +1416,38 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"},  	{"DAC MIXR", "INF1 Switch", "IF1 DAC R"}, -	{"ANC", NULL, "Stereo ADC MIXL"}, -	{"ANC", NULL, "Stereo ADC MIXR"}, - -	{"Audio DSP", NULL, "DAC MIXL"}, -	{"Audio DSP", NULL, "DAC MIXR"}, - -	{"DAC L2 Mux", "IF2", "IF2 DAC L"}, -	{"DAC L2 Mux", "Base L/R", "Audio DSP"}, - -	{"DAC R2 Mux", "IF2", "IF2 DAC R"}, -  	{"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"}, -	{"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, -	{"Stereo DAC MIXL", "ANC Switch", "ANC"},  	{"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"}, -	{"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, -	{"Stereo DAC MIXR", "ANC Switch", "ANC"},  	{"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"}, -	{"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, -	{"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},  	{"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"}, -	{"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, -	{"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},  	{"DIG MIXL", "DAC L1 Switch", "DAC MIXL"}, -	{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},  	{"DIG MIXR", "DAC R1 Switch", "DAC MIXR"}, -	{"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},  	{"DAC L1", NULL, "Stereo DAC MIXL"}, -	{"DAC L1", NULL, "PLL1", check_sysclk1_source}, +	{"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},  	{"DAC R1", NULL, "Stereo DAC MIXR"}, -	{"DAC R1", NULL, "PLL1", check_sysclk1_source}, -	{"DAC L2", NULL, "Mono DAC MIXL"}, -	{"DAC L2", NULL, "PLL1", check_sysclk1_source}, -	{"DAC R2", NULL, "Mono DAC MIXR"}, -	{"DAC R2", NULL, "PLL1", check_sysclk1_source}, +	{"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},  	{"SPK MIXL", "REC MIXL Switch", "RECMIXL"},  	{"SPK MIXL", "INL Switch", "INL VOL"},  	{"SPK MIXL", "DAC L1 Switch", "DAC L1"}, -	{"SPK MIXL", "DAC L2 Switch", "DAC L2"},  	{"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"},  	{"SPK MIXR", "REC MIXR Switch", "RECMIXR"},  	{"SPK MIXR", "INR Switch", "INR VOL"},  	{"SPK MIXR", "DAC R1 Switch", "DAC R1"}, -	{"SPK MIXR", "DAC R2 Switch", "DAC R2"},  	{"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"}, -	{"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},  	{"OUT MIXL", "BST1 Switch", "BST1"},  	{"OUT MIXL", "INL Switch", "INL VOL"},  	{"OUT MIXL", "REC MIXL Switch", "RECMIXL"}, -	{"OUT MIXL", "DAC R2 Switch", "DAC R2"}, -	{"OUT MIXL", "DAC L2 Switch", "DAC L2"},  	{"OUT MIXL", "DAC L1 Switch", "DAC L1"}, -	{"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},  	{"OUT MIXR", "BST2 Switch", "BST2"},  	{"OUT MIXR", "BST1 Switch", "BST1"},  	{"OUT MIXR", "INR Switch", "INR VOL"},  	{"OUT MIXR", "REC MIXR Switch", "RECMIXR"}, -	{"OUT MIXR", "DAC L2 Switch", "DAC L2"}, -	{"OUT MIXR", "DAC R2 Switch", "DAC R2"},  	{"OUT MIXR", "DAC R1 Switch", "DAC R1"},  	{"SPKVOL L", NULL, "SPK MIXL"}, @@ -1485,11 +1466,9 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"},  	{"SPOR MIX", "BST1 Switch", "BST1"}, -	{"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},  	{"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},  	{"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},  	{"HPO MIX L", NULL, "HP L Amp"}, -	{"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},  	{"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},  	{"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},  	{"HPO MIX R", NULL, "HP R Amp"}, @@ -1499,12 +1478,6 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},  	{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"}, -	{"Mono MIX", "DAC R2 Switch", "DAC R2"}, -	{"Mono MIX", "DAC L2 Switch", "DAC L2"}, -	{"Mono MIX", "OUTVOL R Switch", "OUTVOL R"}, -	{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, -	{"Mono MIX", "BST1 Switch", "BST1"}, -  	{"HP Amp", NULL, "HPO MIX L"},  	{"HP Amp", NULL, "HPO MIX R"}, @@ -1529,11 +1502,82 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"HPOR", NULL, "HP R Playback"},  	{"LOUTL", NULL, "LOUT MIX"},  	{"LOUTR", NULL, "LOUT MIX"}, +}; + +static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { +	{"ANC", NULL, "Stereo ADC MIXL"}, +	{"ANC", NULL, "Stereo ADC MIXR"}, + +	{"Audio DSP", NULL, "DAC MIXL"}, +	{"Audio DSP", NULL, "DAC MIXR"}, + +	{"DAC L2 Mux", "IF2", "IF2 DAC L"}, +	{"DAC L2 Mux", "Base L/R", "Audio DSP"}, + +	{"DAC R2 Mux", "IF2", "IF2 DAC R"}, + +	{"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Stereo DAC MIXL", "ANC Switch", "ANC"}, +	{"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, +	{"Stereo DAC MIXR", "ANC Switch", "ANC"}, + +	{"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + +	{"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, +	{"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, + +	{"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"}, +	{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + +	{"DAC L2", NULL, "Mono DAC MIXL"}, +	{"DAC L2", NULL, "PLL1", is_sys_clk_from_pll}, +	{"DAC R2", NULL, "Mono DAC MIXR"}, +	{"DAC R2", NULL, "PLL1", is_sys_clk_from_pll}, + +	{"SPK MIXL", "DAC L2 Switch", "DAC L2"}, +	{"SPK MIXR", "DAC R2 Switch", "DAC R2"}, + +	{"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"}, +	{"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"}, + +	{"OUT MIXL", "DAC R2 Switch", "DAC R2"}, +	{"OUT MIXL", "DAC L2 Switch", "DAC L2"}, + +	{"OUT MIXR", "DAC L2 Switch", "DAC L2"}, +	{"OUT MIXR", "DAC R2 Switch", "DAC R2"}, + +	{"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"}, +	{"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"}, + +	{"Mono MIX", "DAC R2 Switch", "DAC R2"}, +	{"Mono MIX", "DAC L2 Switch", "DAC L2"}, +	{"Mono MIX", "OUTVOL R Switch", "OUTVOL R"}, +	{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, +	{"Mono MIX", "BST1 Switch", "BST1"}, +  	{"MONOP", NULL, "Mono MIX"},  	{"MONON", NULL, "Mono MIX"},  	{"MONOP", NULL, "Improve MONO Amp Drv"},  }; +static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = { +	{"Stereo DAC MIXL", "DAC L2 Switch", "IF2 DAC L"}, +	{"Stereo DAC MIXR", "DAC R2 Switch", "IF2 DAC R"}, + +	{"Mono DAC MIXL", "DAC L2 Switch", "IF2 DAC L"}, +	{"Mono DAC MIXL", "DAC R2 Switch", "IF2 DAC R"}, + +	{"Mono DAC MIXR", "DAC R2 Switch", "IF2 DAC R"}, +	{"Mono DAC MIXR", "DAC L2 Switch", "IF2 DAC L"}, + +	{"DIG MIXL", "DAC L2 Switch", "IF2 DAC L"}, +	{"DIG MIXR", "DAC R2 Switch", "IF2 DAC R"}, + +	{"IF2 DAC L", NULL, "DAC L2 Filter"}, +	{"IF2 DAC R", NULL, "DAC R2 Filter"}, +}; +  static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)  {  	int ret = 0, val; @@ -1582,34 +1626,19 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)  	return ret;  } -static int get_clk_info(int sclk, int rate) -{ -	int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; - -	if (sclk <= 0 || rate <= 0) -		return -EINVAL; - -	rate = rate << 8; -	for (i = 0; i < ARRAY_SIZE(pd); i++) -		if (sclk == rate * pd[i]) -			return i; - -	return -EINVAL; -} -  static int rt5640_hw_params(struct snd_pcm_substream *substream,  	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	unsigned int val_len = 0, val_clk, mask_clk, dai_sel; -	int pre_div, bclk_ms, frame_size; +	unsigned int val_len = 0, val_clk, mask_clk; +	int dai_sel, pre_div, bclk_ms, frame_size;  	rt5640->lrck[dai->id] = params_rate(params); -	pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]); +	pre_div = rl6231_get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);  	if (pre_div < 0) { -		dev_err(codec->dev, "Unsupported clock setting\n"); +		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", +			rt5640->lrck[dai->id], dai->id);  		return -EINVAL;  	}  	frame_size = snd_soc_params_to_frame_size(params); @@ -1628,16 +1657,16 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,  	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",  				bclk_ms, pre_div, dai->id); -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		val_len |= RT5640_I2S_DL_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		val_len |= RT5640_I2S_DL_24;  		break; -	case SNDRV_PCM_FORMAT_S8: +	case 8:  		val_len |= RT5640_I2S_DL_8;  		break;  	default: @@ -1673,7 +1702,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  {  	struct snd_soc_codec *codec = dai->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	unsigned int reg_val = 0, dai_sel; +	unsigned int reg_val = 0; +	int dai_sel;  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {  	case SND_SOC_DAIFMT_CBM_CFM: @@ -1749,12 +1779,6 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,  	case RT5640_SCLK_S_PLL1:  		reg_val |= RT5640_SCLK_SRC_PLL1;  		break; -	case RT5640_SCLK_S_PLL1_TK: -		reg_val |= RT5640_SCLK_SRC_PLL1T; -		break; -	case RT5640_SCLK_S_RCCLK: -		reg_val |= RT5640_SCLK_SRC_RCCLK; -		break;  	default:  		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);  		return -EINVAL; @@ -1768,65 +1792,12 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,  	return 0;  } -/** - * rt5640_pll_calc - Calculate PLL M/N/K code. - * @freq_in: external clock provided to codec. - * @freq_out: target clock which codec works on. - * @pll_code: Pointer to structure with M, N, K and bypass flag. - * - * Calculate M/N/K code to configure PLL for codec. And K is assigned to 2 - * which make calculation more efficiently. - * - * Returns 0 for success or negative error code. - */ -static int rt5640_pll_calc(const unsigned int freq_in, -	const unsigned int freq_out, struct rt5640_pll_code *pll_code) -{ -	int max_n = RT5640_PLL_N_MAX, max_m = RT5640_PLL_M_MAX; -	int n = 0, m = 0, red, n_t, m_t, in_t, out_t; -	int red_t = abs(freq_out - freq_in); -	bool bypass = false; - -	if (RT5640_PLL_INP_MAX < freq_in || RT5640_PLL_INP_MIN > freq_in) -		return -EINVAL; - -	for (n_t = 0; n_t <= max_n; n_t++) { -		in_t = (freq_in >> 1) + (freq_in >> 2) * n_t; -		if (in_t < 0) -			continue; -		if (in_t == freq_out) { -			bypass = true; -			n = n_t; -			goto code_find; -		} -		for (m_t = 0; m_t <= max_m; m_t++) { -			out_t = in_t / (m_t + 2); -			red = abs(out_t - freq_out); -			if (red < red_t) { -				n = n_t; -				m = m_t; -				if (red == 0) -					goto code_find; -				red_t = red; -			} -		} -	} -	pr_debug("Only get approximation about PLL\n"); - -code_find: -	pll_code->m_bp = bypass; -	pll_code->m_code = m; -	pll_code->n_code = n; -	pll_code->k_code = 2; -	return 0; -} -  static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  			unsigned int freq_in, unsigned int freq_out)  {  	struct snd_soc_codec *codec = dai->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	struct rt5640_pll_code *pll_code = &rt5640->pll_code; +	struct rl6231_pll_code pll_code;  	int ret, dai_sel;  	if (source == rt5640->pll_src && freq_in == rt5640->pll_in && @@ -1870,20 +1841,21 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  		return -EINVAL;  	} -	ret = rt5640_pll_calc(freq_in, freq_out, pll_code); +	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);  	if (ret < 0) {  		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);  		return ret;  	} -	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp, -		(pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code); +	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", +		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), +		pll_code.n_code, pll_code.k_code);  	snd_soc_write(codec, RT5640_PLL_CTRL1, -		pll_code->n_code << RT5640_PLL_N_SFT | pll_code->k_code); +		pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);  	snd_soc_write(codec, RT5640_PLL_CTRL2, -		(pll_code->m_bp ? 0 : pll_code->m_code) << RT5640_PLL_M_SFT | -		pll_code->m_bp << RT5640_PLL_M_BP_SFT); +		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT | +		pll_code.m_bp << RT5640_PLL_M_BP_SFT);  	rt5640->pll_in = freq_in;  	rt5640->pll_out = freq_out; @@ -1895,11 +1867,9 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  static int rt5640_set_bias_level(struct snd_soc_codec *codec,  			enum snd_soc_bias_level level)  { -	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);  	switch (level) {  	case SND_SOC_BIAS_STANDBY:  		if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { -			regcache_cache_only(rt5640->regmap, false);  			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,  				RT5640_PWR_VREF1 | RT5640_PWR_MB |  				RT5640_PWR_BG | RT5640_PWR_VREF2, @@ -1909,7 +1879,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,  			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,  				RT5640_PWR_FV1 | RT5640_PWR_FV2,  				RT5640_PWR_FV1 | RT5640_PWR_FV2); -			regcache_sync(rt5640->regmap);  			snd_soc_update_bits(codec, RT5640_DUMMY1,  						0x0301, 0x0301);  			snd_soc_update_bits(codec, RT5640_MICBIAS, @@ -1940,24 +1909,42 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,  static int rt5640_probe(struct snd_soc_codec *codec)  {  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	int ret;  	rt5640->codec = codec; -	codec->control_data = rt5640->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	codec->dapm.idle_bias_off = 1;  	rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);  	snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);  	snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);  	snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00); +	switch (snd_soc_read(codec, RT5640_RESET) & RT5640_ID_MASK) { +	case RT5640_ID_5640: +	case RT5640_ID_5642: +		snd_soc_add_codec_controls(codec, +			rt5640_specific_snd_controls, +			ARRAY_SIZE(rt5640_specific_snd_controls)); +		snd_soc_dapm_new_controls(&codec->dapm, +			rt5640_specific_dapm_widgets, +			ARRAY_SIZE(rt5640_specific_dapm_widgets)); +		snd_soc_dapm_add_routes(&codec->dapm, +			rt5640_specific_dapm_routes, +			ARRAY_SIZE(rt5640_specific_dapm_routes)); +		break; +	case RT5640_ID_5639: +		snd_soc_dapm_new_controls(&codec->dapm, +			rt5639_specific_dapm_widgets, +			ARRAY_SIZE(rt5639_specific_dapm_widgets)); +		snd_soc_dapm_add_routes(&codec->dapm, +			rt5639_specific_dapm_routes, +			ARRAY_SIZE(rt5639_specific_dapm_routes)); +		break; +	default: +		dev_err(codec->dev, +			"The driver is for RT5639 RT5640 or RT5642 only\n"); +		return -ENODEV; +	} +  	return 0;  } @@ -1977,13 +1964,23 @@ static int rt5640_suspend(struct snd_soc_codec *codec)  	rt5640_reset(codec);  	regcache_cache_only(rt5640->regmap, true);  	regcache_mark_dirty(rt5640->regmap); +	if (gpio_is_valid(rt5640->pdata.ldo1_en)) +		gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0);  	return 0;  }  static int rt5640_resume(struct snd_soc_codec *codec)  { -	rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + +	if (gpio_is_valid(rt5640->pdata.ldo1_en)) { +		gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1); +		msleep(400); +	} + +	regcache_cache_only(rt5640->regmap, false); +	regcache_sync(rt5640->regmap);  	return 0;  } @@ -2050,6 +2047,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {  	.suspend = rt5640_suspend,  	.resume = rt5640_resume,  	.set_bias_level = rt5640_set_bias_level, +	.idle_bias_off = true,  	.controls = rt5640_snd_controls,  	.num_controls = ARRAY_SIZE(rt5640_snd_controls),  	.dapm_widgets = rt5640_dapm_widgets, @@ -2076,10 +2074,30 @@ static const struct regmap_config rt5640_regmap = {  static const struct i2c_device_id rt5640_i2c_id[] = {  	{ "rt5640", 0 }, +	{ "rt5639", 0 }, +	{ "rt5642", 0 },  	{ }  };  MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); +#if defined(CONFIG_OF) +static const struct of_device_id rt5640_of_match[] = { +	{ .compatible = "realtek,rt5639", }, +	{ .compatible = "realtek,rt5640", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, rt5640_of_match); +#endif + +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5640_acpi_match[] = { +	{ "INT33CA", 0 }, +	{ "10EC5640", 0 }, +	{ }, +}; +MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); +#endif +  static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)  {  	rt5640->pdata.in1_diff = of_property_read_bool(np, @@ -2155,7 +2173,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,  	}  	regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); -	if ((val != RT5640_DEVICE_ID)) { +	if (val != RT5640_DEVICE_ID) {  		dev_err(&i2c->dev,  			"Device with ID register %x is not rt5640/39\n", val);  		return -ENODEV; @@ -2176,6 +2194,25 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,  		regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,  					RT5640_IN_DF2, RT5640_IN_DF2); +	if (rt5640->pdata.dmic_en) { +		regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, +			RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); + +		if (rt5640->pdata.dmic1_data_pin) { +			regmap_update_bits(rt5640->regmap, RT5640_DMIC, +				RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); +			regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, +				RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); +		} + +		if (rt5640->pdata.dmic2_data_pin) { +			regmap_update_bits(rt5640->regmap, RT5640_DMIC, +				RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); +			regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, +				RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); +		} +	} +  	rt5640->hp_mute = 1;  	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, @@ -2199,6 +2236,8 @@ static struct i2c_driver rt5640_i2c_driver = {  	.driver = {  		.name = "rt5640",  		.owner = THIS_MODULE, +		.acpi_match_table = ACPI_PTR(rt5640_acpi_match), +		.of_match_table = of_match_ptr(rt5640_of_match),  	},  	.probe = rt5640_i2c_probe,  	.remove   = rt5640_i2c_remove, @@ -2206,6 +2245,6 @@ static struct i2c_driver rt5640_i2c_driver = {  };  module_i2c_driver(rt5640_i2c_driver); -MODULE_DESCRIPTION("ASoC RT5640 driver"); +MODULE_DESCRIPTION("ASoC RT5640/RT5639 driver");  MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");  MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 5e8df25a13f..58ebe96b86d 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -192,6 +192,13 @@  #define RT5640_R_VOL_MASK			(0x3f)  #define RT5640_R_VOL_SFT			0 +/* SW Reset & Device ID (0x00) */ +#define RT5640_ID_MASK				(0x3 << 1) +#define RT5640_ID_5639				(0x0 << 1) +#define RT5640_ID_5640				(0x2 << 1) +#define RT5640_ID_5642				(0x3 << 1) + +  /* IN1 and IN2 Control (0x0d) */  /* IN3 and IN4 Control (0x0e) */  #define RT5640_BST_SFT1				12 @@ -976,8 +983,6 @@  #define RT5640_SCLK_SRC_SFT			14  #define RT5640_SCLK_SRC_MCLK			(0x0 << 14)  #define RT5640_SCLK_SRC_PLL1			(0x1 << 14) -#define RT5640_SCLK_SRC_PLL1T			(0x2 << 14) -#define RT5640_SCLK_SRC_RCCLK			(0x3 << 14) /* 15MHz */  #define RT5640_PLL1_SRC_MASK			(0x3 << 12)  #define RT5640_PLL1_SRC_SFT			12  #define RT5640_PLL1_SRC_MCLK			(0x0 << 12) @@ -2074,13 +2079,6 @@ enum {  	RT5640_DMIC2,  }; -struct rt5640_pll_code { -	bool m_bp; /* Indicates bypass m code or not. */ -	int m_code; -	int n_code; -	int k_code; -}; -  struct rt5640_priv {  	struct snd_soc_codec *codec;  	struct rt5640_platform_data pdata; @@ -2092,12 +2090,10 @@ struct rt5640_priv {  	int bclk[RT5640_AIFS];  	int master[RT5640_AIFS]; -	struct rt5640_pll_code pll_code;  	int pll_src;  	int pll_in;  	int pll_out; -	int dmic_en;  	bool hp_mute;  }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c new file mode 100644 index 00000000000..02147be2b30 --- /dev/null +++ b/sound/soc/codecs/rt5645.c @@ -0,0 +1,2378 @@ +/* + * rt5645.c  --  RT5645 ALSA SoC audio codec driver + * + * Copyright 2013 Realtek Semiconductor Corp. + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rl6231.h" +#include "rt5645.h" + +#define RT5645_DEVICE_ID 0x6308 + +#define RT5645_PR_RANGE_BASE (0xff + 1) +#define RT5645_PR_SPACING 0x100 + +#define RT5645_PR_BASE (RT5645_PR_RANGE_BASE + (0 * RT5645_PR_SPACING)) + +static const struct regmap_range_cfg rt5645_ranges[] = { +	{ +		.name = "PR", +		.range_min = RT5645_PR_BASE, +		.range_max = RT5645_PR_BASE + 0xf8, +		.selector_reg = RT5645_PRIV_INDEX, +		.selector_mask = 0xff, +		.selector_shift = 0x0, +		.window_start = RT5645_PRIV_DATA, +		.window_len = 0x1, +	}, +}; + +static const struct reg_default init_list[] = { +	{RT5645_PR_BASE + 0x3d,	0x3600}, +	{RT5645_PR_BASE + 0x1c,	0xfd20}, +	{RT5645_PR_BASE + 0x20,	0x611f}, +	{RT5645_PR_BASE + 0x21,	0x4040}, +	{RT5645_PR_BASE + 0x23,	0x0004}, +}; +#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt5645_reg[] = { +	{ 0x00, 0x0000 }, +	{ 0x01, 0xc8c8 }, +	{ 0x02, 0xc8c8 }, +	{ 0x03, 0xc8c8 }, +	{ 0x0a, 0x0002 }, +	{ 0x0b, 0x2827 }, +	{ 0x0c, 0xe000 }, +	{ 0x0d, 0x0000 }, +	{ 0x0e, 0x0000 }, +	{ 0x0f, 0x0808 }, +	{ 0x14, 0x3333 }, +	{ 0x16, 0x4b00 }, +	{ 0x18, 0x018b }, +	{ 0x19, 0xafaf }, +	{ 0x1a, 0xafaf }, +	{ 0x1b, 0x0001 }, +	{ 0x1c, 0x2f2f }, +	{ 0x1d, 0x2f2f }, +	{ 0x1e, 0x0000 }, +	{ 0x20, 0x0000 }, +	{ 0x27, 0x7060 }, +	{ 0x28, 0x7070 }, +	{ 0x29, 0x8080 }, +	{ 0x2a, 0x5656 }, +	{ 0x2b, 0x5454 }, +	{ 0x2c, 0xaaa0 }, +	{ 0x2f, 0x1002 }, +	{ 0x31, 0x5000 }, +	{ 0x32, 0x0000 }, +	{ 0x33, 0x0000 }, +	{ 0x34, 0x0000 }, +	{ 0x35, 0x0000 }, +	{ 0x3b, 0x0000 }, +	{ 0x3c, 0x007f }, +	{ 0x3d, 0x0000 }, +	{ 0x3e, 0x007f }, +	{ 0x3f, 0x0000 }, +	{ 0x40, 0x001f }, +	{ 0x41, 0x0000 }, +	{ 0x42, 0x001f }, +	{ 0x45, 0x6000 }, +	{ 0x46, 0x003e }, +	{ 0x47, 0x003e }, +	{ 0x48, 0xf807 }, +	{ 0x4a, 0x0004 }, +	{ 0x4d, 0x0000 }, +	{ 0x4e, 0x0000 }, +	{ 0x4f, 0x01ff }, +	{ 0x50, 0x0000 }, +	{ 0x51, 0x0000 }, +	{ 0x52, 0x01ff }, +	{ 0x53, 0xf000 }, +	{ 0x56, 0x0111 }, +	{ 0x57, 0x0064 }, +	{ 0x58, 0xef0e }, +	{ 0x59, 0xf0f0 }, +	{ 0x5a, 0xef0e }, +	{ 0x5b, 0xf0f0 }, +	{ 0x5c, 0xef0e }, +	{ 0x5d, 0xf0f0 }, +	{ 0x5e, 0xf000 }, +	{ 0x5f, 0x0000 }, +	{ 0x61, 0x0300 }, +	{ 0x62, 0x0000 }, +	{ 0x63, 0x00c2 }, +	{ 0x64, 0x0000 }, +	{ 0x65, 0x0000 }, +	{ 0x66, 0x0000 }, +	{ 0x6a, 0x0000 }, +	{ 0x6c, 0x0aaa }, +	{ 0x70, 0x8000 }, +	{ 0x71, 0x8000 }, +	{ 0x72, 0x8000 }, +	{ 0x73, 0x7770 }, +	{ 0x74, 0x3e00 }, +	{ 0x75, 0x2409 }, +	{ 0x76, 0x000a }, +	{ 0x77, 0x0c00 }, +	{ 0x78, 0x0000 }, +	{ 0x80, 0x0000 }, +	{ 0x81, 0x0000 }, +	{ 0x82, 0x0000 }, +	{ 0x83, 0x0000 }, +	{ 0x84, 0x0000 }, +	{ 0x85, 0x0000 }, +	{ 0x8a, 0x0000 }, +	{ 0x8e, 0x0004 }, +	{ 0x8f, 0x1100 }, +	{ 0x90, 0x0646 }, +	{ 0x91, 0x0c06 }, +	{ 0x93, 0x0000 }, +	{ 0x94, 0x0200 }, +	{ 0x95, 0x0000 }, +	{ 0x9a, 0x2184 }, +	{ 0x9b, 0x010a }, +	{ 0x9c, 0x0aea }, +	{ 0x9d, 0x000c }, +	{ 0x9e, 0x0400 }, +	{ 0xa0, 0xa0a8 }, +	{ 0xa1, 0x0059 }, +	{ 0xa2, 0x0001 }, +	{ 0xae, 0x6000 }, +	{ 0xaf, 0x0000 }, +	{ 0xb0, 0x6000 }, +	{ 0xb1, 0x0000 }, +	{ 0xb2, 0x0000 }, +	{ 0xb3, 0x001f }, +	{ 0xb4, 0x020c }, +	{ 0xb5, 0x1f00 }, +	{ 0xb6, 0x0000 }, +	{ 0xbb, 0x0000 }, +	{ 0xbc, 0x0000 }, +	{ 0xbd, 0x0000 }, +	{ 0xbe, 0x0000 }, +	{ 0xbf, 0x3100 }, +	{ 0xc0, 0x0000 }, +	{ 0xc1, 0x0000 }, +	{ 0xc2, 0x0000 }, +	{ 0xc3, 0x2000 }, +	{ 0xcd, 0x0000 }, +	{ 0xce, 0x0000 }, +	{ 0xcf, 0x1813 }, +	{ 0xd0, 0x0690 }, +	{ 0xd1, 0x1c17 }, +	{ 0xd3, 0xb320 }, +	{ 0xd4, 0x0000 }, +	{ 0xd6, 0x0400 }, +	{ 0xd9, 0x0809 }, +	{ 0xda, 0x0000 }, +	{ 0xdb, 0x0003 }, +	{ 0xdc, 0x0049 }, +	{ 0xdd, 0x001b }, +	{ 0xe6, 0x8000 }, +	{ 0xe7, 0x0200 }, +	{ 0xec, 0xb300 }, +	{ 0xed, 0x0000 }, +	{ 0xf0, 0x001f }, +	{ 0xf1, 0x020c }, +	{ 0xf2, 0x1f00 }, +	{ 0xf3, 0x0000 }, +	{ 0xf4, 0x4000 }, +	{ 0xf8, 0x0000 }, +	{ 0xf9, 0x0000 }, +	{ 0xfa, 0x2060 }, +	{ 0xfb, 0x4040 }, +	{ 0xfc, 0x0000 }, +	{ 0xfd, 0x0002 }, +	{ 0xfe, 0x10ec }, +	{ 0xff, 0x6308 }, +}; + +static int rt5645_reset(struct snd_soc_codec *codec) +{ +	return snd_soc_write(codec, RT5645_RESET, 0); +} + +static bool rt5645_volatile_register(struct device *dev, unsigned int reg) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) { +		if (reg >= rt5645_ranges[i].range_min && +			reg <= rt5645_ranges[i].range_max) { +			return true; +		} +	} + +	switch (reg) { +	case RT5645_RESET: +	case RT5645_PRIV_DATA: +	case RT5645_IN1_CTRL1: +	case RT5645_IN1_CTRL2: +	case RT5645_IN1_CTRL3: +	case RT5645_A_JD_CTRL1: +	case RT5645_ADC_EQ_CTRL1: +	case RT5645_EQ_CTRL1: +	case RT5645_ALC_CTRL_1: +	case RT5645_IRQ_CTRL2: +	case RT5645_IRQ_CTRL3: +	case RT5645_INT_IRQ_ST: +	case RT5645_IL_CMD: +	case RT5645_VENDOR_ID: +	case RT5645_VENDOR_ID1: +	case RT5645_VENDOR_ID2: +		return true; +	default: +		return false; +	} +} + +static bool rt5645_readable_register(struct device *dev, unsigned int reg) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) { +		if (reg >= rt5645_ranges[i].range_min && +			reg <= rt5645_ranges[i].range_max) { +			return true; +		} +	} + +	switch (reg) { +	case RT5645_RESET: +	case RT5645_SPK_VOL: +	case RT5645_HP_VOL: +	case RT5645_LOUT1: +	case RT5645_IN1_CTRL1: +	case RT5645_IN1_CTRL2: +	case RT5645_IN1_CTRL3: +	case RT5645_IN2_CTRL: +	case RT5645_INL1_INR1_VOL: +	case RT5645_SPK_FUNC_LIM: +	case RT5645_ADJ_HPF_CTRL: +	case RT5645_DAC1_DIG_VOL: +	case RT5645_DAC2_DIG_VOL: +	case RT5645_DAC_CTRL: +	case RT5645_STO1_ADC_DIG_VOL: +	case RT5645_MONO_ADC_DIG_VOL: +	case RT5645_ADC_BST_VOL1: +	case RT5645_ADC_BST_VOL2: +	case RT5645_STO1_ADC_MIXER: +	case RT5645_MONO_ADC_MIXER: +	case RT5645_AD_DA_MIXER: +	case RT5645_STO_DAC_MIXER: +	case RT5645_MONO_DAC_MIXER: +	case RT5645_DIG_MIXER: +	case RT5645_DIG_INF1_DATA: +	case RT5645_PDM_OUT_CTRL: +	case RT5645_REC_L1_MIXER: +	case RT5645_REC_L2_MIXER: +	case RT5645_REC_R1_MIXER: +	case RT5645_REC_R2_MIXER: +	case RT5645_HPMIXL_CTRL: +	case RT5645_HPOMIXL_CTRL: +	case RT5645_HPMIXR_CTRL: +	case RT5645_HPOMIXR_CTRL: +	case RT5645_HPO_MIXER: +	case RT5645_SPK_L_MIXER: +	case RT5645_SPK_R_MIXER: +	case RT5645_SPO_MIXER: +	case RT5645_SPO_CLSD_RATIO: +	case RT5645_OUT_L1_MIXER: +	case RT5645_OUT_R1_MIXER: +	case RT5645_OUT_L_GAIN1: +	case RT5645_OUT_L_GAIN2: +	case RT5645_OUT_R_GAIN1: +	case RT5645_OUT_R_GAIN2: +	case RT5645_LOUT_MIXER: +	case RT5645_HAPTIC_CTRL1: +	case RT5645_HAPTIC_CTRL2: +	case RT5645_HAPTIC_CTRL3: +	case RT5645_HAPTIC_CTRL4: +	case RT5645_HAPTIC_CTRL5: +	case RT5645_HAPTIC_CTRL6: +	case RT5645_HAPTIC_CTRL7: +	case RT5645_HAPTIC_CTRL8: +	case RT5645_HAPTIC_CTRL9: +	case RT5645_HAPTIC_CTRL10: +	case RT5645_PWR_DIG1: +	case RT5645_PWR_DIG2: +	case RT5645_PWR_ANLG1: +	case RT5645_PWR_ANLG2: +	case RT5645_PWR_MIXER: +	case RT5645_PWR_VOL: +	case RT5645_PRIV_INDEX: +	case RT5645_PRIV_DATA: +	case RT5645_I2S1_SDP: +	case RT5645_I2S2_SDP: +	case RT5645_ADDA_CLK1: +	case RT5645_ADDA_CLK2: +	case RT5645_DMIC_CTRL1: +	case RT5645_DMIC_CTRL2: +	case RT5645_TDM_CTRL_1: +	case RT5645_TDM_CTRL_2: +	case RT5645_GLB_CLK: +	case RT5645_PLL_CTRL1: +	case RT5645_PLL_CTRL2: +	case RT5645_ASRC_1: +	case RT5645_ASRC_2: +	case RT5645_ASRC_3: +	case RT5645_ASRC_4: +	case RT5645_DEPOP_M1: +	case RT5645_DEPOP_M2: +	case RT5645_DEPOP_M3: +	case RT5645_MICBIAS: +	case RT5645_A_JD_CTRL1: +	case RT5645_VAD_CTRL4: +	case RT5645_CLSD_OUT_CTRL: +	case RT5645_ADC_EQ_CTRL1: +	case RT5645_ADC_EQ_CTRL2: +	case RT5645_EQ_CTRL1: +	case RT5645_EQ_CTRL2: +	case RT5645_ALC_CTRL_1: +	case RT5645_ALC_CTRL_2: +	case RT5645_ALC_CTRL_3: +	case RT5645_ALC_CTRL_4: +	case RT5645_ALC_CTRL_5: +	case RT5645_JD_CTRL: +	case RT5645_IRQ_CTRL1: +	case RT5645_IRQ_CTRL2: +	case RT5645_IRQ_CTRL3: +	case RT5645_INT_IRQ_ST: +	case RT5645_GPIO_CTRL1: +	case RT5645_GPIO_CTRL2: +	case RT5645_GPIO_CTRL3: +	case RT5645_BASS_BACK: +	case RT5645_MP3_PLUS1: +	case RT5645_MP3_PLUS2: +	case RT5645_ADJ_HPF1: +	case RT5645_ADJ_HPF2: +	case RT5645_HP_CALIB_AMP_DET: +	case RT5645_SV_ZCD1: +	case RT5645_SV_ZCD2: +	case RT5645_IL_CMD: +	case RT5645_IL_CMD2: +	case RT5645_IL_CMD3: +	case RT5645_DRC1_HL_CTRL1: +	case RT5645_DRC2_HL_CTRL1: +	case RT5645_ADC_MONO_HP_CTRL1: +	case RT5645_ADC_MONO_HP_CTRL2: +	case RT5645_DRC2_CTRL1: +	case RT5645_DRC2_CTRL2: +	case RT5645_DRC2_CTRL3: +	case RT5645_DRC2_CTRL4: +	case RT5645_DRC2_CTRL5: +	case RT5645_JD_CTRL3: +	case RT5645_JD_CTRL4: +	case RT5645_GEN_CTRL1: +	case RT5645_GEN_CTRL2: +	case RT5645_GEN_CTRL3: +	case RT5645_VENDOR_ID: +	case RT5645_VENDOR_ID1: +	case RT5645_VENDOR_ID2: +		return true; +	default: +		return false; +	} +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { +	TLV_DB_RANGE_HEAD(7), +	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), +	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), +	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), +	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), +	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), +	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), +	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +static const char * const rt5645_tdm_data_swap_select[] = { +	"L/R", "R/L", "L/L", "R/R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum, +	RT5645_TDM_CTRL_1, 6, rt5645_tdm_data_swap_select); + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum, +	RT5645_TDM_CTRL_1, 4, rt5645_tdm_data_swap_select); + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum, +	RT5645_TDM_CTRL_1, 2, rt5645_tdm_data_swap_select); + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot6_7_enum, +	RT5645_TDM_CTRL_1, 0, rt5645_tdm_data_swap_select); + +static const char * const rt5645_tdm_adc_data_select[] = { +	"1/2/R", "2/1/R", "R/1/2", "R/2/1" +}; + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum, +				RT5645_TDM_CTRL_1, 8, +				rt5645_tdm_adc_data_select); + +static const struct snd_kcontrol_new rt5645_snd_controls[] = { +	/* Speaker Output Volume */ +	SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, +		RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), +	SOC_DOUBLE_TLV("Speaker Playback Volume", RT5645_SPK_VOL, +		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), + +	/* Headphone Output Volume */ +	SOC_DOUBLE("HP Channel Switch", RT5645_HP_VOL, +		RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), +	SOC_DOUBLE_TLV("HP Playback Volume", RT5645_HP_VOL, +		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), + +	/* OUTPUT Control */ +	SOC_DOUBLE("OUT Playback Switch", RT5645_LOUT1, +		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE("OUT Channel Switch", RT5645_LOUT1, +		RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), +	SOC_DOUBLE_TLV("OUT Playback Volume", RT5645_LOUT1, +		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), + +	/* DAC Digital Volume */ +	SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL, +		RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1), +	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL, +		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv), +	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL, +		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv), + +	/* IN1/IN2 Control */ +	SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1, +		RT5645_BST_SFT1, 8, 0, bst_tlv), +	SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL, +		RT5645_BST_SFT2, 8, 0, bst_tlv), + +	/* INL/INR Volume Control */ +	SOC_DOUBLE_TLV("IN Capture Volume", RT5645_INL1_INR1_VOL, +		RT5645_INL_VOL_SFT, RT5645_INR_VOL_SFT, 31, 1, in_vol_tlv), + +	/* ADC Digital Volume Control */ +	SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL, +		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL, +		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv), +	SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL, +		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL, +		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv), + +	/* ADC Boost Volume Control */ +	SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1, +		RT5645_STO1_ADC_L_BST_SFT, RT5645_STO1_ADC_R_BST_SFT, 3, 0, +		adc_bst_tlv), +	SOC_DOUBLE_TLV("STO2 ADC Boost Gain", RT5645_ADC_BST_VOL1, +		RT5645_STO2_ADC_L_BST_SFT, RT5645_STO2_ADC_R_BST_SFT, 3, 0, +		adc_bst_tlv), + +	/* I2S2 function select */ +	SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT, +		1, 1), + +	/* TDM */ +	SOC_ENUM("TDM Adc Slot0 1 Data", rt5645_tdm_adc_slot0_1_enum), +	SOC_ENUM("TDM Adc Slot2 3 Data", rt5645_tdm_adc_slot2_3_enum), +	SOC_ENUM("TDM Adc Slot4 5 Data", rt5645_tdm_adc_slot4_5_enum), +	SOC_ENUM("TDM Adc Slot6 7 Data", rt5645_tdm_adc_slot6_7_enum), +	SOC_ENUM("TDM IF1 ADC DATA Sel", rt5645_tdm_adc_sel_enum), +	SOC_SINGLE("TDM IF1_DAC1_L Sel", RT5645_TDM_CTRL_3, 12, 7, 0), +	SOC_SINGLE("TDM IF1_DAC1_R Sel", RT5645_TDM_CTRL_3, 8, 7, 0), +	SOC_SINGLE("TDM IF1_DAC2_L Sel", RT5645_TDM_CTRL_3, 4, 7, 0), +	SOC_SINGLE("TDM IF1_DAC2_R Sel", RT5645_TDM_CTRL_3, 0, 7, 0), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); +	int idx = -EINVAL; + +	idx = rl6231_calc_dmic_clk(rt5645->sysclk); + +	if (idx < 0) +		dev_err(codec->dev, "Failed to set DMIC clock\n"); +	else +		snd_soc_update_bits(codec, RT5645_DMIC_CTRL1, +			RT5645_DMIC_CLK_MASK, idx << RT5645_DMIC_CLK_SFT); +	return idx; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, +			 struct snd_soc_dapm_widget *sink) +{ +	unsigned int val; + +	val = snd_soc_read(source->codec, RT5645_GLB_CLK); +	val &= RT5645_SCLK_SRC_MASK; +	if (val == RT5645_SCLK_SRC_PLL1) +		return 1; +	else +		return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, +			RT5645_M_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER, +			RT5645_M_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_sto1_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, +			RT5645_M_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER, +			RT5645_M_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER, +			RT5645_M_MONO_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER, +			RT5645_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER, +			RT5645_M_MONO_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER, +			RT5645_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dac_l_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER, +			RT5645_M_ADCMIX_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_AD_DA_MIXER, +			RT5645_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dac_r_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER, +			RT5645_M_ADCMIX_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_AD_DA_MIXER, +			RT5645_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_sto_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER, +			RT5645_M_DAC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_STO_DAC_MIXER, +			RT5645_M_DAC_L2_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER, +			RT5645_M_DAC_R1_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_sto_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER, +			RT5645_M_DAC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_STO_DAC_MIXER, +			RT5645_M_DAC_R2_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER, +			RT5645_M_DAC_L1_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_MONO_DAC_MIXER, +			RT5645_M_DAC_L1_MONO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER, +			RT5645_M_DAC_L2_MONO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER, +			RT5645_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_MONO_DAC_MIXER, +			RT5645_M_DAC_R1_MONO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER, +			RT5645_M_DAC_R2_MONO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER, +			RT5645_M_DAC_L2_MONO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dig_l_mix[] = { +	SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5645_DIG_MIXER, +			RT5645_M_STO_L_DAC_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER, +			RT5645_M_DAC_L2_DAC_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER, +			RT5645_M_DAC_R2_DAC_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dig_r_mix[] = { +	SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5645_DIG_MIXER, +			RT5645_M_STO_R_DAC_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER, +			RT5645_M_DAC_R2_DAC_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER, +			RT5645_M_DAC_L2_DAC_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5645_rec_l_mix[] = { +	SOC_DAPM_SINGLE("HPOL Switch", RT5645_REC_L2_MIXER, +			RT5645_M_HP_L_RM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5645_REC_L2_MIXER, +			RT5645_M_IN_L_RM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_L2_MIXER, +			RT5645_M_BST2_RM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_L2_MIXER, +			RT5645_M_BST1_RM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUT MIXL Switch", RT5645_REC_L2_MIXER, +			RT5645_M_OM_L_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_rec_r_mix[] = { +	SOC_DAPM_SINGLE("HPOR Switch", RT5645_REC_R2_MIXER, +			RT5645_M_HP_R_RM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5645_REC_R2_MIXER, +			RT5645_M_IN_R_RM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_R2_MIXER, +			RT5645_M_BST2_RM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_R2_MIXER, +			RT5645_M_BST1_RM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUT MIXR Switch", RT5645_REC_R2_MIXER, +			RT5645_M_OM_R_RM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spk_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPK_L_MIXER, +			RT5645_M_DAC_L1_SM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_SPK_L_MIXER, +			RT5645_M_DAC_L2_SM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5645_SPK_L_MIXER, +			RT5645_M_IN_L_SM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5645_SPK_L_MIXER, +			RT5645_M_BST1_L_SM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spk_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPK_R_MIXER, +			RT5645_M_DAC_R1_SM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_SPK_R_MIXER, +			RT5645_M_DAC_R2_SM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5645_SPK_R_MIXER, +			RT5645_M_IN_R_SM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5645_SPK_R_MIXER, +			RT5645_M_BST2_R_SM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_out_l_mix[] = { +	SOC_DAPM_SINGLE("BST1 Switch", RT5645_OUT_L1_MIXER, +			RT5645_M_BST1_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5645_OUT_L1_MIXER, +			RT5645_M_IN_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_OUT_L1_MIXER, +			RT5645_M_DAC_L2_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_OUT_L1_MIXER, +			RT5645_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_out_r_mix[] = { +	SOC_DAPM_SINGLE("BST2 Switch", RT5645_OUT_R1_MIXER, +			RT5645_M_BST2_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5645_OUT_R1_MIXER, +			RT5645_M_IN_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_OUT_R1_MIXER, +			RT5645_M_DAC_R2_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_OUT_R1_MIXER, +			RT5645_M_DAC_R1_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spo_l_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER, +			RT5645_M_DAC_R1_SPM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPO_MIXER, +			RT5645_M_DAC_L1_SPM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER, +			RT5645_M_SV_R_SPM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("SPKVOL L Switch", RT5645_SPO_MIXER, +			RT5645_M_SV_L_SPM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spo_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER, +			RT5645_M_DAC_R1_SPM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER, +			RT5645_M_SV_R_SPM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_hpo_mix[] = { +	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPO_MIXER, +			RT5645_M_DAC1_HM_SFT, 1, 1), +	SOC_DAPM_SINGLE("HPVOL Switch", RT5645_HPO_MIXER, +			RT5645_M_HPVOL_HM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_hpvoll_mix[] = { +	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXL_CTRL, +			RT5645_M_DAC1_HV_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXL_CTRL, +			RT5645_M_DAC2_HV_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5645_HPOMIXL_CTRL, +			RT5645_M_IN_HV_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5645_HPOMIXL_CTRL, +			RT5645_M_BST1_HV_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_hpvolr_mix[] = { +	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXR_CTRL, +			RT5645_M_DAC1_HV_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXR_CTRL, +			RT5645_M_DAC2_HV_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5645_HPOMIXR_CTRL, +			RT5645_M_IN_HV_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5645_HPOMIXR_CTRL, +			RT5645_M_BST2_HV_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_lout_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_LOUT_MIXER, +			RT5645_M_DAC_L1_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_LOUT_MIXER, +			RT5645_M_DAC_R1_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUTMIX L Switch", RT5645_LOUT_MIXER, +			RT5645_M_OV_L_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUTMIX R Switch", RT5645_LOUT_MIXER, +			RT5645_M_OV_R_LM_SFT, 1, 1), +}; + +/*DAC1 L/R source*/ /* MX-29 [9:8] [11:10] */ +static const char * const rt5645_dac1_src[] = { +	"IF1 DAC", "IF2 DAC", "IF3 DAC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_dac1l_enum, RT5645_AD_DA_MIXER, +	RT5645_DAC1_L_SEL_SFT, rt5645_dac1_src); + +static const struct snd_kcontrol_new rt5645_dac1l_mux = +	SOC_DAPM_ENUM("DAC1 L source", rt5645_dac1l_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5645_dac1r_enum, RT5645_AD_DA_MIXER, +	RT5645_DAC1_R_SEL_SFT, rt5645_dac1_src); + +static const struct snd_kcontrol_new rt5645_dac1r_mux = +	SOC_DAPM_ENUM("DAC1 R source", rt5645_dac1r_enum); + +/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */ +static const char * const rt5645_dac12_src[] = { +	"IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_dac2l_enum, RT5645_DAC_CTRL, +	RT5645_DAC2_L_SEL_SFT, rt5645_dac12_src); + +static const struct snd_kcontrol_new rt5645_dac_l2_mux = +	SOC_DAPM_ENUM("DAC2 L source", rt5645_dac2l_enum); + +static const char * const rt5645_dacr2_src[] = { +	"IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "Haptic" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_dac2r_enum, RT5645_DAC_CTRL, +	RT5645_DAC2_R_SEL_SFT, rt5645_dacr2_src); + +static const struct snd_kcontrol_new rt5645_dac_r2_mux = +	SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum); + + +/* INL/R source */ +static const char * const rt5645_inl_src[] = { +	"IN2P", "MonoP" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_inl_enum, RT5645_INL1_INR1_VOL, +	RT5645_INL_SEL_SFT, rt5645_inl_src); + +static const struct snd_kcontrol_new rt5645_inl_mux = +	SOC_DAPM_ENUM("INL source", rt5645_inl_enum); + +static const char * const rt5645_inr_src[] = { +	"IN2N", "MonoN" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_inr_enum, RT5645_INL1_INR1_VOL, +	RT5645_INR_SEL_SFT, rt5645_inr_src); + +static const struct snd_kcontrol_new rt5645_inr_mux = +	SOC_DAPM_ENUM("INR source", rt5645_inr_enum); + +/* Stereo1 ADC source */ +/* MX-27 [12] */ +static const char * const rt5645_stereo_adc1_src[] = { +	"DAC MIX", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_stereo1_adc1_enum, RT5645_STO1_ADC_MIXER, +	RT5645_ADC_1_SRC_SFT, rt5645_stereo_adc1_src); + +static const struct snd_kcontrol_new rt5645_sto_adc1_mux = +	SOC_DAPM_ENUM("Stereo1 ADC1 Mux", rt5645_stereo1_adc1_enum); + +/* MX-27 [11] */ +static const char * const rt5645_stereo_adc2_src[] = { +	"DAC MIX", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_stereo1_adc2_enum, RT5645_STO1_ADC_MIXER, +	RT5645_ADC_2_SRC_SFT, rt5645_stereo_adc2_src); + +static const struct snd_kcontrol_new rt5645_sto_adc2_mux = +	SOC_DAPM_ENUM("Stereo1 ADC2 Mux", rt5645_stereo1_adc2_enum); + +/* MX-27 [8] */ +static const char * const rt5645_stereo_dmic_src[] = { +	"DMIC1", "DMIC2" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_stereo1_dmic_enum, RT5645_STO1_ADC_MIXER, +	RT5645_DMIC_SRC_SFT, rt5645_stereo_dmic_src); + +static const struct snd_kcontrol_new rt5645_sto1_dmic_mux = +	SOC_DAPM_ENUM("Stereo1 DMIC source", rt5645_stereo1_dmic_enum); + +/* Mono ADC source */ +/* MX-28 [12] */ +static const char * const rt5645_mono_adc_l1_src[] = { +	"Mono DAC MIXL", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_mono_adc_l1_enum, RT5645_MONO_ADC_MIXER, +	RT5645_MONO_ADC_L1_SRC_SFT, rt5645_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_l1_mux = +	SOC_DAPM_ENUM("Mono ADC1 left source", rt5645_mono_adc_l1_enum); +/* MX-28 [11] */ +static const char * const rt5645_mono_adc_l2_src[] = { +	"Mono DAC MIXL", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_mono_adc_l2_enum, RT5645_MONO_ADC_MIXER, +	RT5645_MONO_ADC_L2_SRC_SFT, rt5645_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_l2_mux = +	SOC_DAPM_ENUM("Mono ADC2 left source", rt5645_mono_adc_l2_enum); + +/* MX-28 [8] */ +static const char * const rt5645_mono_dmic_src[] = { +	"DMIC1", "DMIC2" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_mono_dmic_l_enum, RT5645_MONO_ADC_MIXER, +	RT5645_MONO_DMIC_L_SRC_SFT, rt5645_mono_dmic_src); + +static const struct snd_kcontrol_new rt5645_mono_dmic_l_mux = +	SOC_DAPM_ENUM("Mono DMIC left source", rt5645_mono_dmic_l_enum); +/* MX-28 [1:0] */ +static SOC_ENUM_SINGLE_DECL( +	rt5645_mono_dmic_r_enum, RT5645_MONO_ADC_MIXER, +	RT5645_MONO_DMIC_R_SRC_SFT, rt5645_mono_dmic_src); + +static const struct snd_kcontrol_new rt5645_mono_dmic_r_mux = +	SOC_DAPM_ENUM("Mono DMIC Right source", rt5645_mono_dmic_r_enum); +/* MX-28 [4] */ +static const char * const rt5645_mono_adc_r1_src[] = { +	"Mono DAC MIXR", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_mono_adc_r1_enum, RT5645_MONO_ADC_MIXER, +	RT5645_MONO_ADC_R1_SRC_SFT, rt5645_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_r1_mux = +	SOC_DAPM_ENUM("Mono ADC1 right source", rt5645_mono_adc_r1_enum); +/* MX-28 [3] */ +static const char * const rt5645_mono_adc_r2_src[] = { +	"Mono DAC MIXR", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_mono_adc_r2_enum, RT5645_MONO_ADC_MIXER, +	RT5645_MONO_ADC_R2_SRC_SFT, rt5645_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux = +	SOC_DAPM_ENUM("Mono ADC2 right source", rt5645_mono_adc_r2_enum); + +/* MX-77 [9:8] */ +static const char * const rt5645_if1_adc_in_src[] = { +	"IF_ADC1", "IF_ADC2", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_if1_adc_in_enum, RT5645_TDM_CTRL_1, +	RT5645_IF1_ADC_IN_SFT, rt5645_if1_adc_in_src); + +static const struct snd_kcontrol_new rt5645_if1_adc_in_mux = +	SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum); + +/* MX-2F [13:12] */ +static const char * const rt5645_if2_adc_in_src[] = { +	"IF_ADC1", "IF_ADC2", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_if2_adc_in_enum, RT5645_DIG_INF1_DATA, +	RT5645_IF2_ADC_IN_SFT, rt5645_if2_adc_in_src); + +static const struct snd_kcontrol_new rt5645_if2_adc_in_mux = +	SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum); + +/* MX-2F [1:0] */ +static const char * const rt5645_if3_adc_in_src[] = { +	"IF_ADC1", "IF_ADC2", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA, +	RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src); + +static const struct snd_kcontrol_new rt5645_if3_adc_in_mux = +	SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum); + +/* MX-31 [15] [13] [11] [9] */ +static const char * const rt5645_pdm_src[] = { +	"Mono DAC", "Stereo DAC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_pdm1_l_enum, RT5645_PDM_OUT_CTRL, +	RT5645_PDM1_L_SFT, rt5645_pdm_src); + +static const struct snd_kcontrol_new rt5645_pdm1_l_mux = +	SOC_DAPM_ENUM("PDM1 L source", rt5645_pdm1_l_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5645_pdm1_r_enum, RT5645_PDM_OUT_CTRL, +	RT5645_PDM1_R_SFT, rt5645_pdm_src); + +static const struct snd_kcontrol_new rt5645_pdm1_r_mux = +	SOC_DAPM_ENUM("PDM1 R source", rt5645_pdm1_r_enum); + +/* MX-9D [9:8] */ +static const char * const rt5645_vad_adc_src[] = { +	"Sto1 ADC L", "Mono ADC L", "Mono ADC R" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5645_vad_adc_enum, RT5645_VAD_CTRL4, +	RT5645_VAD_SEL_SFT, rt5645_vad_adc_src); + +static const struct snd_kcontrol_new rt5645_vad_adc_mux = +	SOC_DAPM_ENUM("VAD ADC source", rt5645_vad_adc_enum); + +static const struct snd_kcontrol_new spk_l_vol_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL, +		RT5645_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new spk_r_vol_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL, +		RT5645_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hp_l_vol_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL, +		RT5645_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hp_r_vol_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL, +		RT5645_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm1_l_vol_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL, +		RT5645_M_PDM1_L, 1, 1); + +static const struct snd_kcontrol_new pdm1_r_vol_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL, +		RT5645_M_PDM1_R, 1, 1); + +static void hp_amp_power(struct snd_soc_codec *codec, int on) +{ +	static int hp_amp_power_count; +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + +	if (on) { +		if (hp_amp_power_count <= 0) { +			/* depop parameters */ +			snd_soc_update_bits(codec, RT5645_DEPOP_M2, +				RT5645_DEPOP_MASK, RT5645_DEPOP_MAN); +			snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d); +			regmap_write(rt5645->regmap, RT5645_PR_BASE + +				RT5645_HP_DCC_INT1, 0x9f01); +			mdelay(150); +			/* headphone amp power on */ +			snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +				RT5645_PWR_FV1 | RT5645_PWR_FV2 , 0); +			snd_soc_update_bits(codec, RT5645_PWR_VOL, +				RT5645_PWR_HV_L | RT5645_PWR_HV_R, +				RT5645_PWR_HV_L | RT5645_PWR_HV_R); +			snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +				RT5645_PWR_HP_L | RT5645_PWR_HP_R | +				RT5645_PWR_HA, +				RT5645_PWR_HP_L | RT5645_PWR_HP_R | +				RT5645_PWR_HA); +			mdelay(5); +			snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +				RT5645_PWR_FV1 | RT5645_PWR_FV2, +				RT5645_PWR_FV1 | RT5645_PWR_FV2); + +			snd_soc_update_bits(codec, RT5645_DEPOP_M1, +				RT5645_HP_CO_MASK | RT5645_HP_SG_MASK, +				RT5645_HP_CO_EN | RT5645_HP_SG_EN); +			regmap_write(rt5645->regmap, RT5645_PR_BASE + +				0x14, 0x1aaa); +			regmap_write(rt5645->regmap, RT5645_PR_BASE + +				0x24, 0x0430); +		} +		hp_amp_power_count++; +	} else { +		hp_amp_power_count--; +		if (hp_amp_power_count <= 0) { +			snd_soc_update_bits(codec, RT5645_DEPOP_M1, +				RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK | +				RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS | +				RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS); +			/* headphone amp power down */ +			snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000); +			snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +				RT5645_PWR_HP_L | RT5645_PWR_HP_R | +				RT5645_PWR_HA, 0); +		} +	} +} + +static int rt5645_hp_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		hp_amp_power(codec, 1); +		/* headphone unmute sequence */ +		snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK | +			RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK, +			(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | +			(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | +			(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); +		regmap_write(rt5645->regmap, +			RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); +		snd_soc_update_bits(codec, RT5645_DEPOP_M1, +			RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN); +		snd_soc_update_bits(codec, RT5645_DEPOP_M1, +			RT5645_RSTN_MASK, RT5645_RSTN_EN); +		snd_soc_update_bits(codec, RT5645_DEPOP_M1, +			RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK | +			RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS | +			RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); +		msleep(40); +		snd_soc_update_bits(codec, RT5645_DEPOP_M1, +			RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK | +			RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS | +			RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		/* headphone mute sequence */ +		snd_soc_update_bits(codec, RT5645_DEPOP_M3, +			RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | +			RT5645_CP_FQ3_MASK, +			(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | +			(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | +			(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); +		regmap_write(rt5645->regmap, +			RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); +		snd_soc_update_bits(codec, RT5645_DEPOP_M1, +			RT5645_HP_SG_MASK, RT5645_HP_SG_EN); +		snd_soc_update_bits(codec, RT5645_DEPOP_M1, +			RT5645_RSTP_MASK, RT5645_RSTP_EN); +		snd_soc_update_bits(codec, RT5645_DEPOP_M1, +			RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK | +			RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS | +			RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); +		msleep(30); +		hp_amp_power(codec, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5645_spk_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		snd_soc_update_bits(codec, RT5645_PWR_DIG1, +			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R | +			RT5645_PWR_CLS_D_L, +			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R | +			RT5645_PWR_CLS_D_L); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, RT5645_PWR_DIG1, +			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R | +			RT5645_PWR_CLS_D_L, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5645_lout_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		hp_amp_power(codec, 1); +		snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +			RT5645_PWR_LM, RT5645_PWR_LM); +		snd_soc_update_bits(codec, RT5645_LOUT1, +			RT5645_L_MUTE | RT5645_R_MUTE, 0); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, RT5645_LOUT1, +			RT5645_L_MUTE | RT5645_R_MUTE, +			RT5645_L_MUTE | RT5645_R_MUTE); +		snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +			RT5645_PWR_LM, 0); +		hp_amp_power(codec, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5645_bst2_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		snd_soc_update_bits(codec, RT5645_PWR_ANLG2, +			RT5645_PWR_BST2_P, RT5645_PWR_BST2_P); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, RT5645_PWR_ANLG2, +			RT5645_PWR_BST2_P, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER, +		RT5645_PWR_LDO2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("PLL1", RT5645_PWR_ANLG2, +		RT5645_PWR_PLL_BIT, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("JD Power", RT5645_PWR_ANLG2, +		RT5645_PWR_JD1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL, +		RT5645_PWR_MIC_DET_BIT, 0, NULL, 0), + +	/* Input Side */ +	/* micbias */ +	SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, +			RT5645_PWR_MB1_BIT, 0), +	SND_SOC_DAPM_MICBIAS("micbias2", RT5645_PWR_ANLG2, +			RT5645_PWR_MB2_BIT, 0), +	/* Input Lines */ +	SND_SOC_DAPM_INPUT("DMIC L1"), +	SND_SOC_DAPM_INPUT("DMIC R1"), +	SND_SOC_DAPM_INPUT("DMIC L2"), +	SND_SOC_DAPM_INPUT("DMIC R2"), + +	SND_SOC_DAPM_INPUT("IN1P"), +	SND_SOC_DAPM_INPUT("IN1N"), +	SND_SOC_DAPM_INPUT("IN2P"), +	SND_SOC_DAPM_INPUT("IN2N"), + +	SND_SOC_DAPM_INPUT("Haptic Generator"), + +	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, +		set_dmic_clk, SND_SOC_DAPM_PRE_PMU), +	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5645_DMIC_CTRL1, +		RT5645_DMIC_1_EN_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5645_DMIC_CTRL1, +		RT5645_DMIC_2_EN_SFT, 0, NULL, 0), +	/* Boost */ +	SND_SOC_DAPM_PGA("BST1", RT5645_PWR_ANLG2, +		RT5645_PWR_BST1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA_E("BST2", RT5645_PWR_ANLG2, +		RT5645_PWR_BST2_BIT, 0, NULL, 0, rt5645_bst2_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	/* Input Volume */ +	SND_SOC_DAPM_PGA("INL VOL", RT5645_PWR_VOL, +		RT5645_PWR_IN_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("INR VOL", RT5645_PWR_VOL, +		RT5645_PWR_IN_R_BIT, 0, NULL, 0), +	/* REC Mixer */ +	SND_SOC_DAPM_MIXER("RECMIXL", RT5645_PWR_MIXER, RT5645_PWR_RM_L_BIT, +			0, rt5645_rec_l_mix, ARRAY_SIZE(rt5645_rec_l_mix)), +	SND_SOC_DAPM_MIXER("RECMIXR", RT5645_PWR_MIXER, RT5645_PWR_RM_R_BIT, +			0, rt5645_rec_r_mix, ARRAY_SIZE(rt5645_rec_r_mix)), +	/* ADCs */ +	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_SUPPLY("ADC L power", RT5645_PWR_DIG1, +		RT5645_PWR_ADC_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC R power", RT5645_PWR_DIG1, +		RT5645_PWR_ADC_R_BIT, 0, NULL, 0), + +	/* ADC Mux */ +	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_sto1_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_sto_adc2_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_sto_adc2_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_sto_adc1_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_sto_adc1_mux), +	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_mono_dmic_l_mux), +	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_mono_dmic_r_mux), +	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_mono_adc_l2_mux), +	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_mono_adc_l1_mux), +	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_mono_adc_r1_mux), +	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5645_mono_adc_r2_mux), +	/* ADC Mixer */ + +	SND_SOC_DAPM_SUPPLY_S("adc stereo1 filter", 1, RT5645_PWR_DIG2, +		RT5645_PWR_ADC_S1F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("adc stereo2 filter", 1, RT5645_PWR_DIG2, +		RT5645_PWR_ADC_S2F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, +		rt5645_sto1_adc_l_mix, ARRAY_SIZE(rt5645_sto1_adc_l_mix), +		NULL, 0), +	SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0, +		rt5645_sto1_adc_r_mix, ARRAY_SIZE(rt5645_sto1_adc_r_mix), +		NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("adc mono left filter", 1, RT5645_PWR_DIG2, +		RT5645_PWR_ADC_MF_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER_E("Mono ADC MIXL", SND_SOC_NOPM, 0, 0, +		rt5645_mono_adc_l_mix, ARRAY_SIZE(rt5645_mono_adc_l_mix), +		NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("adc mono right filter", 1, RT5645_PWR_DIG2, +		RT5645_PWR_ADC_MF_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER_E("Mono ADC MIXR", SND_SOC_NOPM, 0, 0, +		rt5645_mono_adc_r_mix, ARRAY_SIZE(rt5645_mono_adc_r_mix), +		NULL, 0), + +	/* ADC PGA */ +	SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("VAD_ADC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* IF1 2 Mux */ +	SND_SOC_DAPM_MUX("IF1 ADC Mux", SND_SOC_NOPM, +		0, 0, &rt5645_if1_adc_in_mux), +	SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, +		0, 0, &rt5645_if2_adc_in_mux), + +	/* Digital Interface */ +	SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1, +		RT5645_PWR_I2S1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("I2S2", RT5645_PWR_DIG1, +		RT5645_PWR_I2S2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* Digital Interface Select */ +	SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, +		0, 0, &rt5645_vad_adc_mux), + +	/* Audio Interface */ +	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + +	/* Output Side */ +	/* DAC mixer before sound effect  */ +	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, +		rt5645_dac_l_mix, ARRAY_SIZE(rt5645_dac_l_mix)), +	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, +		rt5645_dac_r_mix, ARRAY_SIZE(rt5645_dac_r_mix)), + +	/* DAC2 channel Mux */ +	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_l2_mux), +	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_r2_mux), +	SND_SOC_DAPM_PGA("DAC L2 Volume", RT5645_PWR_DIG1, +		RT5645_PWR_DAC_L2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DAC R2 Volume", RT5645_PWR_DIG1, +		RT5645_PWR_DAC_R2_BIT, 0, NULL, 0), + +	SND_SOC_DAPM_MUX("DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1l_mux), +	SND_SOC_DAPM_MUX("DAC1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1r_mux), + +	/* DAC Mixer */ +	SND_SOC_DAPM_SUPPLY_S("dac stereo1 filter", 1, RT5645_PWR_DIG2, +		RT5645_PWR_DAC_S1F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("dac mono left filter", 1, RT5645_PWR_DIG2, +		RT5645_PWR_DAC_MF_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("dac mono right filter", 1, RT5645_PWR_DIG2, +		RT5645_PWR_DAC_MF_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5645_sto_dac_l_mix, ARRAY_SIZE(rt5645_sto_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5645_sto_dac_r_mix, ARRAY_SIZE(rt5645_sto_dac_r_mix)), +	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5645_mono_dac_l_mix, ARRAY_SIZE(rt5645_mono_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5645_mono_dac_r_mix, ARRAY_SIZE(rt5645_mono_dac_r_mix)), +	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5645_dig_l_mix, ARRAY_SIZE(rt5645_dig_l_mix)), +	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5645_dig_r_mix, ARRAY_SIZE(rt5645_dig_r_mix)), + +	/* DACs */ +	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L1_BIT, +		0), +	SND_SOC_DAPM_DAC("DAC L2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L2_BIT, +		0), +	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R1_BIT, +		0), +	SND_SOC_DAPM_DAC("DAC R2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R2_BIT, +		0), +	/* OUT Mixer */ +	SND_SOC_DAPM_MIXER("SPK MIXL", RT5645_PWR_MIXER, RT5645_PWR_SM_L_BIT, +		0, rt5645_spk_l_mix, ARRAY_SIZE(rt5645_spk_l_mix)), +	SND_SOC_DAPM_MIXER("SPK MIXR", RT5645_PWR_MIXER, RT5645_PWR_SM_R_BIT, +		0, rt5645_spk_r_mix, ARRAY_SIZE(rt5645_spk_r_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXL", RT5645_PWR_MIXER, RT5645_PWR_OM_L_BIT, +		0, rt5645_out_l_mix, ARRAY_SIZE(rt5645_out_l_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXR", RT5645_PWR_MIXER, RT5645_PWR_OM_R_BIT, +		0, rt5645_out_r_mix, ARRAY_SIZE(rt5645_out_r_mix)), +	/* Ouput Volume */ +	SND_SOC_DAPM_SWITCH("SPKVOL L", RT5645_PWR_VOL, RT5645_PWR_SV_L_BIT, 0, +		&spk_l_vol_control), +	SND_SOC_DAPM_SWITCH("SPKVOL R", RT5645_PWR_VOL, RT5645_PWR_SV_R_BIT, 0, +		&spk_r_vol_control), +	SND_SOC_DAPM_MIXER("HPOVOL MIXL", RT5645_PWR_VOL, RT5645_PWR_HV_L_BIT, +		0, rt5645_hpvoll_mix, ARRAY_SIZE(rt5645_hpvoll_mix)), +	SND_SOC_DAPM_MIXER("HPOVOL MIXR", RT5645_PWR_VOL, RT5645_PWR_HV_R_BIT, +		0, rt5645_hpvolr_mix, ARRAY_SIZE(rt5645_hpvolr_mix)), +	SND_SOC_DAPM_SUPPLY("HPOVOL MIXL Power", RT5645_PWR_MIXER, +		RT5645_PWR_HM_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("HPOVOL MIXR Power", RT5645_PWR_MIXER, +		RT5645_PWR_HM_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_SWITCH("HPOVOL L", SND_SOC_NOPM, 0, 0, &hp_l_vol_control), +	SND_SOC_DAPM_SWITCH("HPOVOL R", SND_SOC_NOPM, 0, 0, &hp_r_vol_control), + +	/* HPO/LOUT/Mono Mixer */ +	SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_l_mix, +		ARRAY_SIZE(rt5645_spo_l_mix)), +	SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_r_mix, +		ARRAY_SIZE(rt5645_spo_r_mix)), +	SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, rt5645_hpo_mix, +		ARRAY_SIZE(rt5645_hpo_mix)), +	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, rt5645_lout_mix, +		ARRAY_SIZE(rt5645_lout_mix)), + +	SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0, rt5645_hp_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, rt5645_lout_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_PGA_S("SPK amp", 2, SND_SOC_NOPM, 0, 0, rt5645_spk_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + +	/* PDM */ +	SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5645_PWR_DIG2, RT5645_PWR_PDM1_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_MUX("PDM1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_l_mux), +	SND_SOC_DAPM_MUX("PDM1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_r_mux), + +	SND_SOC_DAPM_SWITCH("PDM1 L", SND_SOC_NOPM, 0, 0, &pdm1_l_vol_control), +	SND_SOC_DAPM_SWITCH("PDM1 R", SND_SOC_NOPM, 0, 0, &pdm1_r_vol_control), + +	/* Output Lines */ +	SND_SOC_DAPM_OUTPUT("HPOL"), +	SND_SOC_DAPM_OUTPUT("HPOR"), +	SND_SOC_DAPM_OUTPUT("LOUTL"), +	SND_SOC_DAPM_OUTPUT("LOUTR"), +	SND_SOC_DAPM_OUTPUT("PDM1L"), +	SND_SOC_DAPM_OUTPUT("PDM1R"), +	SND_SOC_DAPM_OUTPUT("SPOL"), +	SND_SOC_DAPM_OUTPUT("SPOR"), +}; + +static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { +	{ "IN1P", NULL, "LDO2" }, +	{ "IN2P", NULL, "LDO2" }, + +	{ "DMIC1", NULL, "DMIC L1" }, +	{ "DMIC1", NULL, "DMIC R1" }, +	{ "DMIC2", NULL, "DMIC L2" }, +	{ "DMIC2", NULL, "DMIC R2" }, + +	{ "BST1", NULL, "IN1P" }, +	{ "BST1", NULL, "IN1N" }, +	{ "BST1", NULL, "JD Power" }, +	{ "BST1", NULL, "Mic Det Power" }, +	{ "BST2", NULL, "IN2P" }, +	{ "BST2", NULL, "IN2N" }, + +	{ "INL VOL", NULL, "IN2P" }, +	{ "INR VOL", NULL, "IN2N" }, + +	{ "RECMIXL", "HPOL Switch", "HPOL" }, +	{ "RECMIXL", "INL Switch", "INL VOL" }, +	{ "RECMIXL", "BST2 Switch", "BST2" }, +	{ "RECMIXL", "BST1 Switch", "BST1" }, +	{ "RECMIXL", "OUT MIXL Switch", "OUT MIXL" }, + +	{ "RECMIXR", "HPOR Switch", "HPOR" }, +	{ "RECMIXR", "INR Switch", "INR VOL" }, +	{ "RECMIXR", "BST2 Switch", "BST2" }, +	{ "RECMIXR", "BST1 Switch", "BST1" }, +	{ "RECMIXR", "OUT MIXR Switch", "OUT MIXR" }, + +	{ "ADC L", NULL, "RECMIXL" }, +	{ "ADC L", NULL, "ADC L power" }, +	{ "ADC R", NULL, "RECMIXR" }, +	{ "ADC R", NULL, "ADC R power" }, + +	{"DMIC L1", NULL, "DMIC CLK"}, +	{"DMIC L1", NULL, "DMIC1 Power"}, +	{"DMIC R1", NULL, "DMIC CLK"}, +	{"DMIC R1", NULL, "DMIC1 Power"}, +	{"DMIC L2", NULL, "DMIC CLK"}, +	{"DMIC L2", NULL, "DMIC2 Power"}, +	{"DMIC R2", NULL, "DMIC CLK"}, +	{"DMIC R2", NULL, "DMIC2 Power"}, + +	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, +	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, + +	{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, +	{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, + +	{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, +	{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, + +	{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, +	{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, +	{ "Stereo1 ADC L1 Mux", "ADC", "ADC L" }, +	{ "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" }, + +	{ "Stereo1 ADC R1 Mux", "ADC", "ADC R" }, +	{ "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" }, +	{ "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC Mux" }, +	{ "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" }, + +	{ "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" }, +	{ "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, +	{ "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, +	{ "Mono ADC L1 Mux", "ADC", "ADC L" }, + +	{ "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, +	{ "Mono ADC R1 Mux", "ADC", "ADC R" }, +	{ "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" }, +	{ "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + +	{ "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" }, +	{ "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" }, +	{ "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" }, +	{ "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" }, + +	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, +	{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" }, +	{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, +	{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" }, +	{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" }, +	{ "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" }, +	{ "Mono ADC MIXL", NULL, "adc mono left filter" }, +	{ "adc mono left filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" }, +	{ "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" }, +	{ "Mono ADC MIXR", NULL, "adc mono right filter" }, +	{ "adc mono right filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "VAD ADC Mux", "Sto1 ADC L", "Stereo1 ADC MIXL" }, +	{ "VAD ADC Mux", "Mono ADC L", "Mono ADC MIXL" }, +	{ "VAD ADC Mux", "Mono ADC R", "Mono ADC MIXR" }, + +	{ "IF_ADC1", NULL, "Stereo1 ADC MIXL" }, +	{ "IF_ADC1", NULL, "Stereo1 ADC MIXR" }, +	{ "IF_ADC2", NULL, "Mono ADC MIXL" }, +	{ "IF_ADC2", NULL, "Mono ADC MIXR" }, +	{ "VAD_ADC", NULL, "VAD ADC Mux" }, + +	{ "IF1 ADC Mux", "IF_ADC1", "IF_ADC1" }, +	{ "IF1 ADC Mux", "IF_ADC2", "IF_ADC2" }, +	{ "IF1 ADC Mux", "VAD_ADC", "VAD_ADC" }, + +	{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" }, +	{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" }, +	{ "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" }, + +	{ "IF1 ADC", NULL, "I2S1" }, +	{ "IF1 ADC", NULL, "IF1 ADC Mux" }, +	{ "IF2 ADC", NULL, "I2S2" }, +	{ "IF2 ADC", NULL, "IF2 ADC Mux" }, + +	{ "AIF1TX", NULL, "IF1 ADC" }, +	{ "AIF1TX", NULL, "IF2 ADC" }, +	{ "AIF2TX", NULL, "IF2 ADC" }, + +	{ "IF1 DAC1", NULL, "AIF1RX" }, +	{ "IF1 DAC2", NULL, "AIF1RX" }, +	{ "IF2 DAC", NULL, "AIF2RX" }, + +	{ "IF1 DAC1", NULL, "I2S1" }, +	{ "IF1 DAC2", NULL, "I2S1" }, +	{ "IF2 DAC", NULL, "I2S2" }, + +	{ "IF1 DAC2 L", NULL, "IF1 DAC2" }, +	{ "IF1 DAC2 R", NULL, "IF1 DAC2" }, +	{ "IF1 DAC1 L", NULL, "IF1 DAC1" }, +	{ "IF1 DAC1 R", NULL, "IF1 DAC1" }, +	{ "IF2 DAC L", NULL, "IF2 DAC" }, +	{ "IF2 DAC R", NULL, "IF2 DAC" }, + +	{ "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" }, +	{ "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" }, + +	{ "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" }, +	{ "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" }, + +	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" }, +	{ "DAC1 MIXL", "DAC1 Switch", "DAC1 L Mux" }, +	{ "DAC1 MIXL", NULL, "dac stereo1 filter" }, +	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" }, +	{ "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" }, +	{ "DAC1 MIXR", NULL, "dac stereo1 filter" }, + +	{ "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" }, +	{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" }, +	{ "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" }, +	{ "DAC L2 Mux", "VAD_ADC", "VAD_ADC" }, +	{ "DAC L2 Volume", NULL, "DAC L2 Mux" }, +	{ "DAC L2 Volume", NULL, "dac mono left filter" }, + +	{ "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" }, +	{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" }, +	{ "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" }, +	{ "DAC R2 Mux", "Haptic", "Haptic Generator" }, +	{ "DAC R2 Volume", NULL, "DAC R2 Mux" }, +	{ "DAC R2 Volume", NULL, "dac mono right filter" }, + +	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, +	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, +	{ "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, +	{ "Stereo DAC MIXL", NULL, "dac stereo1 filter" }, +	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, +	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, +	{ "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, +	{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" }, + +	{ "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, +	{ "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, +	{ "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" }, +	{ "Mono DAC MIXL", NULL, "dac mono left filter" }, +	{ "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, +	{ "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, +	{ "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, +	{ "Mono DAC MIXR", NULL, "dac mono right filter" }, + +	{ "DAC MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, +	{ "DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, +	{ "DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" }, +	{ "DAC MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, +	{ "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, +	{ "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, + +	{ "DAC L1", NULL, "Stereo DAC MIXL" }, +	{ "DAC L1", NULL, "PLL1", is_sys_clk_from_pll }, +	{ "DAC R1", NULL, "Stereo DAC MIXR" }, +	{ "DAC R1", NULL, "PLL1", is_sys_clk_from_pll }, +	{ "DAC L2", NULL, "Mono DAC MIXL" }, +	{ "DAC L2", NULL, "PLL1", is_sys_clk_from_pll }, +	{ "DAC R2", NULL, "Mono DAC MIXR" }, +	{ "DAC R2", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "SPK MIXL", "BST1 Switch", "BST1" }, +	{ "SPK MIXL", "INL Switch", "INL VOL" }, +	{ "SPK MIXL", "DAC L1 Switch", "DAC L1" }, +	{ "SPK MIXL", "DAC L2 Switch", "DAC L2" }, +	{ "SPK MIXR", "BST2 Switch", "BST2" }, +	{ "SPK MIXR", "INR Switch", "INR VOL" }, +	{ "SPK MIXR", "DAC R1 Switch", "DAC R1" }, +	{ "SPK MIXR", "DAC R2 Switch", "DAC R2" }, + +	{ "OUT MIXL", "BST1 Switch", "BST1" }, +	{ "OUT MIXL", "INL Switch", "INL VOL" }, +	{ "OUT MIXL", "DAC L2 Switch", "DAC L2" }, +	{ "OUT MIXL", "DAC L1 Switch", "DAC L1" }, + +	{ "OUT MIXR", "BST2 Switch", "BST2" }, +	{ "OUT MIXR", "INR Switch", "INR VOL" }, +	{ "OUT MIXR", "DAC R2 Switch", "DAC R2" }, +	{ "OUT MIXR", "DAC R1 Switch", "DAC R1" }, + +	{ "HPOVOL MIXL", "DAC1 Switch", "DAC L1" }, +	{ "HPOVOL MIXL", "DAC2 Switch", "DAC L2" }, +	{ "HPOVOL MIXL", "INL Switch", "INL VOL" }, +	{ "HPOVOL MIXL", "BST1 Switch", "BST1" }, +	{ "HPOVOL MIXL", NULL, "HPOVOL MIXL Power" }, +	{ "HPOVOL MIXR", "DAC1 Switch", "DAC R1" }, +	{ "HPOVOL MIXR", "DAC2 Switch", "DAC R2" }, +	{ "HPOVOL MIXR", "INR Switch", "INR VOL" }, +	{ "HPOVOL MIXR", "BST2 Switch", "BST2" }, +	{ "HPOVOL MIXR", NULL, "HPOVOL MIXR Power" }, + +	{ "DAC 2", NULL, "DAC L2" }, +	{ "DAC 2", NULL, "DAC R2" }, +	{ "DAC 1", NULL, "DAC L1" }, +	{ "DAC 1", NULL, "DAC R1" }, +	{ "HPOVOL L", "Switch", "HPOVOL MIXL" }, +	{ "HPOVOL R", "Switch", "HPOVOL MIXR" }, +	{ "HPOVOL", NULL, "HPOVOL L" }, +	{ "HPOVOL", NULL, "HPOVOL R" }, +	{ "HPO MIX", "DAC1 Switch", "DAC 1" }, +	{ "HPO MIX", "HPVOL Switch", "HPOVOL" }, + +	{ "SPKVOL L", "Switch", "SPK MIXL" }, +	{ "SPKVOL R", "Switch", "SPK MIXR" }, + +	{ "SPOL MIX", "DAC R1 Switch", "DAC R1" }, +	{ "SPOL MIX", "DAC L1 Switch", "DAC L1" }, +	{ "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" }, +	{ "SPOL MIX", "SPKVOL L Switch", "SPKVOL L" }, +	{ "SPOR MIX", "DAC R1 Switch", "DAC R1" }, +	{ "SPOR MIX", "SPKVOL R Switch", "SPKVOL R" }, + +	{ "LOUT MIX", "DAC L1 Switch", "DAC L1" }, +	{ "LOUT MIX", "DAC R1 Switch", "DAC R1" }, +	{ "LOUT MIX", "OUTMIX L Switch", "OUT MIXL" }, +	{ "LOUT MIX", "OUTMIX R Switch", "OUT MIXR" }, + +	{ "PDM1 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, +	{ "PDM1 L Mux", "Mono DAC", "Mono DAC MIXL" }, +	{ "PDM1 L Mux", NULL, "PDM1 Power" }, +	{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, +	{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, +	{ "PDM1 R Mux", NULL, "PDM1 Power" }, + +	{ "HP amp", NULL, "HPO MIX" }, +	{ "HP amp", NULL, "JD Power" }, +	{ "HP amp", NULL, "Mic Det Power" }, +	{ "HP amp", NULL, "LDO2" }, +	{ "HPOL", NULL, "HP amp" }, +	{ "HPOR", NULL, "HP amp" }, + +	{ "LOUT amp", NULL, "LOUT MIX" }, +	{ "LOUTL", NULL, "LOUT amp" }, +	{ "LOUTR", NULL, "LOUT amp" }, + +	{ "PDM1 L", "Switch", "PDM1 L Mux" }, +	{ "PDM1 R", "Switch", "PDM1 R Mux" }, + +	{ "PDM1L", NULL, "PDM1 L" }, +	{ "PDM1R", NULL, "PDM1 R" }, + +	{ "SPK amp", NULL, "SPOL MIX" }, +	{ "SPK amp", NULL, "SPOR MIX" }, +	{ "SPOL", NULL, "SPK amp" }, +	{ "SPOR", NULL, "SPK amp" }, +}; + +static int rt5645_hw_params(struct snd_pcm_substream *substream, +	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); +	unsigned int val_len = 0, val_clk, mask_clk; +	int pre_div, bclk_ms, frame_size; + +	rt5645->lrck[dai->id] = params_rate(params); +	pre_div = rl6231_get_clk_info(rt5645->sysclk, rt5645->lrck[dai->id]); +	if (pre_div < 0) { +		dev_err(codec->dev, "Unsupported clock setting\n"); +		return -EINVAL; +	} +	frame_size = snd_soc_params_to_frame_size(params); +	if (frame_size < 0) { +		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); +		return -EINVAL; +	} +	bclk_ms = frame_size > 32; +	rt5645->bclk[dai->id] = rt5645->lrck[dai->id] * (32 << bclk_ms); + +	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", +		rt5645->bclk[dai->id], rt5645->lrck[dai->id]); +	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", +				bclk_ms, pre_div, dai->id); + +	switch (params_width(params)) { +	case 16: +		break; +	case 20: +		val_len |= RT5645_I2S_DL_20; +		break; +	case 24: +		val_len |= RT5645_I2S_DL_24; +		break; +	case 8: +		val_len |= RT5645_I2S_DL_8; +		break; +	default: +		return -EINVAL; +	} + +	switch (dai->id) { +	case RT5645_AIF1: +		mask_clk = RT5645_I2S_BCLK_MS1_MASK | RT5645_I2S_PD1_MASK; +		val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT | +			pre_div << RT5645_I2S_PD1_SFT; +		snd_soc_update_bits(codec, RT5645_I2S1_SDP, +			RT5645_I2S_DL_MASK, val_len); +		snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk); +		break; +	case  RT5645_AIF2: +		mask_clk = RT5645_I2S_BCLK_MS2_MASK | RT5645_I2S_PD2_MASK; +		val_clk = bclk_ms << RT5645_I2S_BCLK_MS2_SFT | +			pre_div << RT5645_I2S_PD2_SFT; +		snd_soc_update_bits(codec, RT5645_I2S2_SDP, +			RT5645_I2S_DL_MASK, val_len); +		snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk); +		break; +	default: +		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); +		return -EINVAL; +	} + +	return 0; +} + +static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		rt5645->master[dai->id] = 1; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		reg_val |= RT5645_I2S_MS_S; +		rt5645->master[dai->id] = 0; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		break; +	case SND_SOC_DAIFMT_IB_NF: +		reg_val |= RT5645_I2S_BP_INV; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		reg_val |= RT5645_I2S_DF_LEFT; +		break; +	case SND_SOC_DAIFMT_DSP_A: +		reg_val |= RT5645_I2S_DF_PCM_A; +		break; +	case SND_SOC_DAIFMT_DSP_B: +		reg_val |= RT5645_I2S_DF_PCM_B; +		break; +	default: +		return -EINVAL; +	} +	switch (dai->id) { +	case RT5645_AIF1: +		snd_soc_update_bits(codec, RT5645_I2S1_SDP, +			RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK | +			RT5645_I2S_DF_MASK, reg_val); +		break; +	case RT5645_AIF2: +		snd_soc_update_bits(codec, RT5645_I2S2_SDP, +			RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK | +			RT5645_I2S_DF_MASK, reg_val); +		break; +	default: +		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); +		return -EINVAL; +	} +	return 0; +} + +static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai, +		int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	if (freq == rt5645->sysclk && clk_id == rt5645->sysclk_src) +		return 0; + +	switch (clk_id) { +	case RT5645_SCLK_S_MCLK: +		reg_val |= RT5645_SCLK_SRC_MCLK; +		break; +	case RT5645_SCLK_S_PLL1: +		reg_val |= RT5645_SCLK_SRC_PLL1; +		break; +	case RT5645_SCLK_S_RCCLK: +		reg_val |= RT5645_SCLK_SRC_RCCLK; +		break; +	default: +		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); +		return -EINVAL; +	} +	snd_soc_update_bits(codec, RT5645_GLB_CLK, +		RT5645_SCLK_SRC_MASK, reg_val); +	rt5645->sysclk = freq; +	rt5645->sysclk_src = clk_id; + +	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + +	return 0; +} + +static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, +			unsigned int freq_in, unsigned int freq_out) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); +	struct rl6231_pll_code pll_code; +	int ret; + +	if (source == rt5645->pll_src && freq_in == rt5645->pll_in && +	    freq_out == rt5645->pll_out) +		return 0; + +	if (!freq_in || !freq_out) { +		dev_dbg(codec->dev, "PLL disabled\n"); + +		rt5645->pll_in = 0; +		rt5645->pll_out = 0; +		snd_soc_update_bits(codec, RT5645_GLB_CLK, +			RT5645_SCLK_SRC_MASK, RT5645_SCLK_SRC_MCLK); +		return 0; +	} + +	switch (source) { +	case RT5645_PLL1_S_MCLK: +		snd_soc_update_bits(codec, RT5645_GLB_CLK, +			RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_MCLK); +		break; +	case RT5645_PLL1_S_BCLK1: +	case RT5645_PLL1_S_BCLK2: +		switch (dai->id) { +		case RT5645_AIF1: +			snd_soc_update_bits(codec, RT5645_GLB_CLK, +				RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK1); +			break; +		case  RT5645_AIF2: +			snd_soc_update_bits(codec, RT5645_GLB_CLK, +				RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK2); +			break; +		default: +			dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); +			return -EINVAL; +		} +		break; +	default: +		dev_err(codec->dev, "Unknown PLL source %d\n", source); +		return -EINVAL; +	} + +	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); +	if (ret < 0) { +		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); +		return ret; +	} + +	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", +		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), +		pll_code.n_code, pll_code.k_code); + +	snd_soc_write(codec, RT5645_PLL_CTRL1, +		pll_code.n_code << RT5645_PLL_N_SFT | pll_code.k_code); +	snd_soc_write(codec, RT5645_PLL_CTRL2, +		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT | +		pll_code.m_bp << RT5645_PLL_M_BP_SFT); + +	rt5645->pll_in = freq_in; +	rt5645->pll_out = freq_out; +	rt5645->pll_src = source; + +	return 0; +} + +static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, +			unsigned int rx_mask, int slots, int slot_width) +{ +	struct snd_soc_codec *codec = dai->codec; +	unsigned int val = 0; + +	if (rx_mask || tx_mask) +		val |= (1 << 14); + +	switch (slots) { +	case 4: +		val |= (1 << 12); +		break; +	case 6: +		val |= (2 << 12); +		break; +	case 8: +		val |= (3 << 12); +		break; +	case 2: +	default: +		break; +	} + +	switch (slot_width) { +	case 20: +		val |= (1 << 10); +		break; +	case 24: +		val |= (2 << 10); +		break; +	case 32: +		val |= (3 << 10); +		break; +	case 16: +	default: +		break; +	} + +	snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, 0x7c00, val); + +	return 0; +} + +static int rt5645_set_bias_level(struct snd_soc_codec *codec, +			enum snd_soc_bias_level level) +{ +	switch (level) { +	case SND_SOC_BIAS_STANDBY: +		if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { +			snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +				RT5645_PWR_VREF1 | RT5645_PWR_MB | +				RT5645_PWR_BG | RT5645_PWR_VREF2, +				RT5645_PWR_VREF1 | RT5645_PWR_MB | +				RT5645_PWR_BG | RT5645_PWR_VREF2); +			mdelay(10); +			snd_soc_update_bits(codec, RT5645_PWR_ANLG1, +				RT5645_PWR_FV1 | RT5645_PWR_FV2, +				RT5645_PWR_FV1 | RT5645_PWR_FV2); +			snd_soc_update_bits(codec, RT5645_GEN_CTRL1, +				RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL); +		} +		break; + +	case SND_SOC_BIAS_OFF: +		snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); +		snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128); +		snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000); +		snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000); +		snd_soc_write(codec, RT5645_PWR_VOL, 0x0000); +		snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000); +		snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000); +		snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000); +		break; + +	default: +		break; +	} +	codec->dapm.bias_level = level; + +	return 0; +} + +static int rt5645_probe(struct snd_soc_codec *codec) +{ +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + +	rt5645->codec = codec; + +	rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF); + +	snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); + +	return 0; +} + +static int rt5645_remove(struct snd_soc_codec *codec) +{ +	rt5645_reset(codec); +	return 0; +} + +#ifdef CONFIG_PM +static int rt5645_suspend(struct snd_soc_codec *codec) +{ +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5645->regmap, true); +	regcache_mark_dirty(rt5645->regmap); + +	return 0; +} + +static int rt5645_resume(struct snd_soc_codec *codec) +{ +	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5645->regmap, false); +	regcache_sync(rt5645->regmap); + +	return 0; +} +#else +#define rt5645_suspend NULL +#define rt5645_resume NULL +#endif + +#define RT5645_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5645_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt5645_aif_dai_ops = { +	.hw_params = rt5645_hw_params, +	.set_fmt = rt5645_set_dai_fmt, +	.set_sysclk = rt5645_set_dai_sysclk, +	.set_tdm_slot = rt5645_set_tdm_slot, +	.set_pll = rt5645_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5645_dai[] = { +	{ +		.name = "rt5645-aif1", +		.id = RT5645_AIF1, +		.playback = { +			.stream_name = "AIF1 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5645_STEREO_RATES, +			.formats = RT5645_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF1 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5645_STEREO_RATES, +			.formats = RT5645_FORMATS, +		}, +		.ops = &rt5645_aif_dai_ops, +	}, +	{ +		.name = "rt5645-aif2", +		.id = RT5645_AIF2, +		.playback = { +			.stream_name = "AIF2 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5645_STEREO_RATES, +			.formats = RT5645_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF2 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5645_STEREO_RATES, +			.formats = RT5645_FORMATS, +		}, +		.ops = &rt5645_aif_dai_ops, +	}, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5645 = { +	.probe = rt5645_probe, +	.remove = rt5645_remove, +	.suspend = rt5645_suspend, +	.resume = rt5645_resume, +	.set_bias_level = rt5645_set_bias_level, +	.idle_bias_off = true, +	.controls = rt5645_snd_controls, +	.num_controls = ARRAY_SIZE(rt5645_snd_controls), +	.dapm_widgets = rt5645_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets), +	.dapm_routes = rt5645_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), +}; + +static const struct regmap_config rt5645_regmap = { +	.reg_bits = 8, +	.val_bits = 16, + +	.max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) * +					       RT5645_PR_SPACING), +	.volatile_reg = rt5645_volatile_register, +	.readable_reg = rt5645_readable_register, + +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults = rt5645_reg, +	.num_reg_defaults = ARRAY_SIZE(rt5645_reg), +	.ranges = rt5645_ranges, +	.num_ranges = ARRAY_SIZE(rt5645_ranges), +}; + +static const struct i2c_device_id rt5645_i2c_id[] = { +	{ "rt5645", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); + +static int rt5645_i2c_probe(struct i2c_client *i2c, +		    const struct i2c_device_id *id) +{ +	struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev); +	struct rt5645_priv *rt5645; +	int ret; +	unsigned int val; + +	rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv), +				GFP_KERNEL); +	if (rt5645 == NULL) +		return -ENOMEM; + +	i2c_set_clientdata(i2c, rt5645); + +	if (pdata) +		rt5645->pdata = *pdata; + +	rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); +	if (IS_ERR(rt5645->regmap)) { +		ret = PTR_ERR(rt5645->regmap); +		dev_err(&i2c->dev, "Failed to allocate register map: %d\n", +			ret); +		return ret; +	} + +	regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); +	if (val != RT5645_DEVICE_ID) { +		dev_err(&i2c->dev, +			"Device with ID register %x is not rt5645\n", val); +		return -ENODEV; +	} + +	regmap_write(rt5645->regmap, RT5645_RESET, 0); + +	ret = regmap_register_patch(rt5645->regmap, init_list, +				    ARRAY_SIZE(init_list)); +	if (ret != 0) +		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + +	if (rt5645->pdata.in2_diff) +		regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, +					RT5645_IN_DF2, RT5645_IN_DF2); + +	if (rt5645->pdata.dmic_en) { +		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, +			RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL); + +		switch (rt5645->pdata.dmic1_data_pin) { +		case RT5645_DMIC_DATA_IN2N: +			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, +				RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N); +			break; + +		case RT5645_DMIC_DATA_GPIO5: +			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, +				RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5); +			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, +				RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA); +			break; + +		case RT5645_DMIC_DATA_GPIO11: +			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, +				RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11); +			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, +				RT5645_GP11_PIN_MASK, +				RT5645_GP11_PIN_DMIC1_SDA); +			break; + +		default: +			break; +		} + +		switch (rt5645->pdata.dmic2_data_pin) { +		case RT5645_DMIC_DATA_IN2P: +			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, +				RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P); +			break; + +		case RT5645_DMIC_DATA_GPIO6: +			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, +				RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6); +			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, +				RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA); +			break; + +		case RT5645_DMIC_DATA_GPIO10: +			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, +				RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10); +			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, +				RT5645_GP10_PIN_MASK, +				RT5645_GP10_PIN_DMIC2_SDA); +			break; + +		case RT5645_DMIC_DATA_GPIO12: +			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, +				RT5645_DMIC_1_DP_MASK, RT5645_DMIC_2_DP_GPIO12); +			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, +				RT5645_GP12_PIN_MASK, +				RT5645_GP12_PIN_DMIC2_SDA); +			break; + +		default: +			break; +		} + +	} + +	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, +			rt5645_dai, ARRAY_SIZE(rt5645_dai)); +	if (ret < 0) +		goto err; + +	return 0; +err: +	return ret; +} + +static int rt5645_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); + +	return 0; +} + +static struct i2c_driver rt5645_i2c_driver = { +	.driver = { +		.name = "rt5645", +		.owner = THIS_MODULE, +	}, +	.probe = rt5645_i2c_probe, +	.remove   = rt5645_i2c_remove, +	.id_table = rt5645_i2c_id, +}; +module_i2c_driver(rt5645_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5645 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h new file mode 100644 index 00000000000..355b7e9eefa --- /dev/null +++ b/sound/soc/codecs/rt5645.h @@ -0,0 +1,2181 @@ +/* + * rt5645.h  --  RT5645 ALSA SoC audio driver + * + * Copyright 2013 Realtek Microelectronics + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5645_H__ +#define __RT5645_H__ + +#include <sound/rt5645.h> + +/* Info */ +#define RT5645_RESET				0x00 +#define RT5645_VENDOR_ID			0xfd +#define RT5645_VENDOR_ID1			0xfe +#define RT5645_VENDOR_ID2			0xff +/*  I/O - Output */ +#define RT5645_SPK_VOL				0x01 +#define RT5645_HP_VOL				0x02 +#define RT5645_LOUT1				0x03 +#define RT5645_LOUT_CTRL			0x05 +/* I/O - Input */ +#define RT5645_IN1_CTRL1			0x0a +#define RT5645_IN1_CTRL2			0x0b +#define RT5645_IN1_CTRL3			0x0c +#define RT5645_IN2_CTRL				0x0d +#define RT5645_INL1_INR1_VOL			0x0f +#define RT5645_SPK_FUNC_LIM			0x14 +#define RT5645_ADJ_HPF_CTRL			0x16 +/* I/O - ADC/DAC/DMIC */ +#define RT5645_DAC1_DIG_VOL			0x19 +#define RT5645_DAC2_DIG_VOL			0x1a +#define RT5645_DAC_CTRL				0x1b +#define RT5645_STO1_ADC_DIG_VOL			0x1c +#define RT5645_MONO_ADC_DIG_VOL			0x1d +#define RT5645_ADC_BST_VOL1			0x1e +/* Mixer - D-D */ +#define RT5645_ADC_BST_VOL2			0x20 +#define RT5645_STO1_ADC_MIXER			0x27 +#define RT5645_MONO_ADC_MIXER			0x28 +#define RT5645_AD_DA_MIXER			0x29 +#define RT5645_STO_DAC_MIXER			0x2a +#define RT5645_MONO_DAC_MIXER			0x2b +#define RT5645_DIG_MIXER			0x2c +#define RT5645_DIG_INF1_DATA			0x2f +/* Mixer - PDM */ +#define RT5645_PDM_OUT_CTRL			0x31 +/* Mixer - ADC */ +#define RT5645_REC_L1_MIXER			0x3b +#define RT5645_REC_L2_MIXER			0x3c +#define RT5645_REC_R1_MIXER			0x3d +#define RT5645_REC_R2_MIXER			0x3e +/* Mixer - DAC */ +#define RT5645_HPMIXL_CTRL			0x3f +#define RT5645_HPOMIXL_CTRL			0x40 +#define RT5645_HPMIXR_CTRL			0x41 +#define RT5645_HPOMIXR_CTRL			0x42 +#define RT5645_HPO_MIXER			0x45 +#define RT5645_SPK_L_MIXER			0x46 +#define RT5645_SPK_R_MIXER			0x47 +#define RT5645_SPO_MIXER			0x48 +#define RT5645_SPO_CLSD_RATIO			0x4a +#define RT5645_OUT_L_GAIN1			0x4d +#define RT5645_OUT_L_GAIN2			0x4e +#define RT5645_OUT_L1_MIXER			0x4f +#define RT5645_OUT_R_GAIN1			0x50 +#define RT5645_OUT_R_GAIN2			0x51 +#define RT5645_OUT_R1_MIXER			0x52 +#define RT5645_LOUT_MIXER			0x53 +/* Haptic */ +#define RT5645_HAPTIC_CTRL1			0x56 +#define RT5645_HAPTIC_CTRL2			0x57 +#define RT5645_HAPTIC_CTRL3			0x58 +#define RT5645_HAPTIC_CTRL4			0x59 +#define RT5645_HAPTIC_CTRL5			0x5a +#define RT5645_HAPTIC_CTRL6			0x5b +#define RT5645_HAPTIC_CTRL7			0x5c +#define RT5645_HAPTIC_CTRL8			0x5d +#define RT5645_HAPTIC_CTRL9			0x5e +#define RT5645_HAPTIC_CTRL10			0x5f +/* Power */ +#define RT5645_PWR_DIG1				0x61 +#define RT5645_PWR_DIG2				0x62 +#define RT5645_PWR_ANLG1			0x63 +#define RT5645_PWR_ANLG2			0x64 +#define RT5645_PWR_MIXER			0x65 +#define RT5645_PWR_VOL				0x66 +/* Private Register Control */ +#define RT5645_PRIV_INDEX			0x6a +#define RT5645_PRIV_DATA			0x6c +/* Format - ADC/DAC */ +#define RT5645_I2S1_SDP				0x70 +#define RT5645_I2S2_SDP				0x71 +#define RT5645_ADDA_CLK1			0x73 +#define RT5645_ADDA_CLK2			0x74 +#define RT5645_DMIC_CTRL1			0x75 +#define RT5645_DMIC_CTRL2			0x76 +/* Format - TDM Control */ +#define RT5645_TDM_CTRL_1			0x77 +#define RT5645_TDM_CTRL_2			0x78 +#define RT5645_TDM_CTRL_3			0x79 + +/* Function - Analog */ +#define RT5645_GLB_CLK				0x80 +#define RT5645_PLL_CTRL1			0x81 +#define RT5645_PLL_CTRL2			0x82 +#define RT5645_ASRC_1				0x83 +#define RT5645_ASRC_2				0x84 +#define RT5645_ASRC_3				0x85 +#define RT5645_ASRC_4				0x8a +#define RT5645_DEPOP_M1				0x8e +#define RT5645_DEPOP_M2				0x8f +#define RT5645_DEPOP_M3				0x90 +#define RT5645_CHARGE_PUMP			0x91 +#define RT5645_MICBIAS				0x93 +#define RT5645_A_JD_CTRL1			0x94 +#define RT5645_VAD_CTRL4			0x9d +#define RT5645_CLSD_OUT_CTRL			0xa0 +/* Function - Digital */ +#define RT5645_ADC_EQ_CTRL1			0xae +#define RT5645_ADC_EQ_CTRL2			0xaf +#define RT5645_EQ_CTRL1				0xb0 +#define RT5645_EQ_CTRL2				0xb1 +#define RT5645_ALC_CTRL_1			0xb3 +#define RT5645_ALC_CTRL_2			0xb4 +#define RT5645_ALC_CTRL_3			0xb5 +#define RT5645_ALC_CTRL_4			0xb6 +#define RT5645_ALC_CTRL_5			0xb7 +#define RT5645_JD_CTRL				0xbb +#define RT5645_IRQ_CTRL1			0xbc +#define RT5645_IRQ_CTRL2			0xbd +#define RT5645_IRQ_CTRL3			0xbe +#define RT5645_INT_IRQ_ST			0xbf +#define RT5645_GPIO_CTRL1			0xc0 +#define RT5645_GPIO_CTRL2			0xc1 +#define RT5645_GPIO_CTRL3			0xc2 +#define RT5645_BASS_BACK			0xcf +#define RT5645_MP3_PLUS1			0xd0 +#define RT5645_MP3_PLUS2			0xd1 +#define RT5645_ADJ_HPF1				0xd3 +#define RT5645_ADJ_HPF2				0xd4 +#define RT5645_HP_CALIB_AMP_DET			0xd6 +#define RT5645_SV_ZCD1				0xd9 +#define RT5645_SV_ZCD2				0xda +#define RT5645_IL_CMD				0xdb +#define RT5645_IL_CMD2				0xdc +#define RT5645_IL_CMD3				0xdd +#define RT5645_DRC1_HL_CTRL1			0xe7 +#define RT5645_DRC2_HL_CTRL1			0xe9 +#define RT5645_MUTI_DRC_CTRL1			0xea +#define RT5645_ADC_MONO_HP_CTRL1		0xec +#define RT5645_ADC_MONO_HP_CTRL2		0xed +#define RT5645_DRC2_CTRL1			0xf0 +#define RT5645_DRC2_CTRL2			0xf1 +#define RT5645_DRC2_CTRL3			0xf2 +#define RT5645_DRC2_CTRL4			0xf3 +#define RT5645_DRC2_CTRL5			0xf4 +#define RT5645_JD_CTRL3				0xf8 +#define RT5645_JD_CTRL4				0xf9 +/* General Control */ +#define RT5645_GEN_CTRL1			0xfa +#define RT5645_GEN_CTRL2			0xfb +#define RT5645_GEN_CTRL3			0xfc + + +/* Index of Codec Private Register definition */ +#define RT5645_DIG_VOL				0x00 +#define RT5645_PR_ALC_CTRL_1			0x01 +#define RT5645_PR_ALC_CTRL_2			0x02 +#define RT5645_PR_ALC_CTRL_3			0x03 +#define RT5645_PR_ALC_CTRL_4			0x04 +#define RT5645_PR_ALC_CTRL_5			0x05 +#define RT5645_PR_ALC_CTRL_6			0x06 +#define RT5645_BIAS_CUR1			0x12 +#define RT5645_BIAS_CUR3			0x14 +#define RT5645_CLSD_INT_REG1			0x1c +#define RT5645_MAMP_INT_REG2			0x37 +#define RT5645_CHOP_DAC_ADC			0x3d +#define RT5645_MIXER_INT_REG			0x3f +#define RT5645_3D_SPK				0x63 +#define RT5645_WND_1				0x6c +#define RT5645_WND_2				0x6d +#define RT5645_WND_3				0x6e +#define RT5645_WND_4				0x6f +#define RT5645_WND_5				0x70 +#define RT5645_WND_8				0x73 +#define RT5645_DIP_SPK_INF			0x75 +#define RT5645_HP_DCC_INT1			0x77 +#define RT5645_EQ_BW_LOP			0xa0 +#define RT5645_EQ_GN_LOP			0xa1 +#define RT5645_EQ_FC_BP1			0xa2 +#define RT5645_EQ_BW_BP1			0xa3 +#define RT5645_EQ_GN_BP1			0xa4 +#define RT5645_EQ_FC_BP2			0xa5 +#define RT5645_EQ_BW_BP2			0xa6 +#define RT5645_EQ_GN_BP2			0xa7 +#define RT5645_EQ_FC_BP3			0xa8 +#define RT5645_EQ_BW_BP3			0xa9 +#define RT5645_EQ_GN_BP3			0xaa +#define RT5645_EQ_FC_BP4			0xab +#define RT5645_EQ_BW_BP4			0xac +#define RT5645_EQ_GN_BP4			0xad +#define RT5645_EQ_FC_HIP1			0xae +#define RT5645_EQ_GN_HIP1			0xaf +#define RT5645_EQ_FC_HIP2			0xb0 +#define RT5645_EQ_BW_HIP2			0xb1 +#define RT5645_EQ_GN_HIP2			0xb2 +#define RT5645_EQ_PRE_VOL			0xb3 +#define RT5645_EQ_PST_VOL			0xb4 + + +/* global definition */ +#define RT5645_L_MUTE				(0x1 << 15) +#define RT5645_L_MUTE_SFT			15 +#define RT5645_VOL_L_MUTE			(0x1 << 14) +#define RT5645_VOL_L_SFT			14 +#define RT5645_R_MUTE				(0x1 << 7) +#define RT5645_R_MUTE_SFT			7 +#define RT5645_VOL_R_MUTE			(0x1 << 6) +#define RT5645_VOL_R_SFT			6 +#define RT5645_L_VOL_MASK			(0x3f << 8) +#define RT5645_L_VOL_SFT			8 +#define RT5645_R_VOL_MASK			(0x3f) +#define RT5645_R_VOL_SFT			0 + +/* IN1 Control 1 (0x0a) */ +#define RT5645_CBJ_BST1_MASK			(0xf << 12) +#define RT5645_CBJ_BST1_SFT			(12) +#define RT5645_CBJ_JD_HP_EN			(0x1 << 9) +#define RT5645_CBJ_JD_MIC_EN			(0x1 << 8) +#define RT5645_CBJ_JD_MIC_SW_EN			(0x1 << 7) +#define RT5645_CBJ_MIC_SEL_R			(0x1 << 6) +#define RT5645_CBJ_MIC_SEL_L			(0x1 << 5) +#define RT5645_CBJ_MIC_SW			(0x1 << 4) +#define RT5645_CBJ_BST1_EN			(0x1 << 2) + +/* IN1 Control 2 (0x0b) */ +#define RT5645_CBJ_MN_JD			(0x1 << 12) +#define RT5645_CAPLESS_EN			(0x1 << 11) +#define RT5645_CBJ_DET_MODE			(0x1 << 7) + +/* IN1 Control 3 (0x0c) */ +#define RT5645_CBJ_TIE_G_L			(0x1 << 15) +#define RT5645_CBJ_TIE_G_R			(0x1 << 14) + +/* IN2 Control (0x0d) */ +#define RT5645_BST_MASK1			(0xf<<12) +#define RT5645_BST_SFT1				12 +#define RT5645_BST_MASK2			(0xf<<8) +#define RT5645_BST_SFT2				8 +#define RT5645_IN_DF2				(0x1 << 6) +#define RT5645_IN_SFT2				6 + +/* INL and INR Volume Control (0x0f) */ +#define RT5645_INL_SEL_MASK			(0x1 << 15) +#define RT5645_INL_SEL_SFT			15 +#define RT5645_INL_SEL_IN4P			(0x0 << 15) +#define RT5645_INL_SEL_MONOP			(0x1 << 15) +#define RT5645_INL_VOL_MASK			(0x1f << 8) +#define RT5645_INL_VOL_SFT			8 +#define RT5645_INR_SEL_MASK			(0x1 << 7) +#define RT5645_INR_SEL_SFT			7 +#define RT5645_INR_SEL_IN4N			(0x0 << 7) +#define RT5645_INR_SEL_MONON			(0x1 << 7) +#define RT5645_INR_VOL_MASK			(0x1f) +#define RT5645_INR_VOL_SFT			0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5645_DAC_L1_VOL_MASK			(0xff << 8) +#define RT5645_DAC_L1_VOL_SFT			8 +#define RT5645_DAC_R1_VOL_MASK			(0xff) +#define RT5645_DAC_R1_VOL_SFT			0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5645_DAC_L2_VOL_MASK			(0xff << 8) +#define RT5645_DAC_L2_VOL_SFT			8 +#define RT5645_DAC_R2_VOL_MASK			(0xff) +#define RT5645_DAC_R2_VOL_SFT			0 + +/* DAC2 Control (0x1b) */ +#define RT5645_M_DAC_L2_VOL			(0x1 << 13) +#define RT5645_M_DAC_L2_VOL_SFT			13 +#define RT5645_M_DAC_R2_VOL			(0x1 << 12) +#define RT5645_M_DAC_R2_VOL_SFT			12 +#define RT5645_DAC2_L_SEL_MASK			(0x7 << 4) +#define RT5645_DAC2_L_SEL_SFT			4 +#define RT5645_DAC2_R_SEL_MASK			(0x7 << 0) +#define RT5645_DAC2_R_SEL_SFT			0 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5645_ADC_L_VOL_MASK			(0x7f << 8) +#define RT5645_ADC_L_VOL_SFT			8 +#define RT5645_ADC_R_VOL_MASK			(0x7f) +#define RT5645_ADC_R_VOL_SFT			0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5645_MONO_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5645_MONO_ADC_L_VOL_SFT		8 +#define RT5645_MONO_ADC_R_VOL_MASK		(0x7f) +#define RT5645_MONO_ADC_R_VOL_SFT		0 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5645_STO1_ADC_L_BST_MASK		(0x3 << 14) +#define RT5645_STO1_ADC_L_BST_SFT		14 +#define RT5645_STO1_ADC_R_BST_MASK		(0x3 << 12) +#define RT5645_STO1_ADC_R_BST_SFT		12 +#define RT5645_STO1_ADC_COMP_MASK		(0x3 << 10) +#define RT5645_STO1_ADC_COMP_SFT		10 +#define RT5645_STO2_ADC_L_BST_MASK		(0x3 << 8) +#define RT5645_STO2_ADC_L_BST_SFT		8 +#define RT5645_STO2_ADC_R_BST_MASK		(0x3 << 6) +#define RT5645_STO2_ADC_R_BST_SFT		6 +#define RT5645_STO2_ADC_COMP_MASK		(0x3 << 4) +#define RT5645_STO2_ADC_COMP_SFT		4 + +/* Stereo2 ADC Mixer Control (0x26) */ +#define RT5645_STO2_ADC_SRC_MASK		(0x1 << 15) +#define RT5645_STO2_ADC_SRC_SFT			15 + +/* Stereo ADC Mixer Control (0x27) */ +#define RT5645_M_ADC_L1				(0x1 << 14) +#define RT5645_M_ADC_L1_SFT			14 +#define RT5645_M_ADC_L2				(0x1 << 13) +#define RT5645_M_ADC_L2_SFT			13 +#define RT5645_ADC_1_SRC_MASK			(0x1 << 12) +#define RT5645_ADC_1_SRC_SFT			12 +#define RT5645_ADC_1_SRC_ADC			(0x1 << 12) +#define RT5645_ADC_1_SRC_DACMIX			(0x0 << 12) +#define RT5645_ADC_2_SRC_MASK			(0x1 << 11) +#define RT5645_ADC_2_SRC_SFT			11 +#define RT5645_DMIC_SRC_MASK			(0x1 << 8) +#define RT5645_DMIC_SRC_SFT			8 +#define RT5645_M_ADC_R1				(0x1 << 6) +#define RT5645_M_ADC_R1_SFT			6 +#define RT5645_M_ADC_R2				(0x1 << 5) +#define RT5645_M_ADC_R2_SFT			5 +#define RT5645_DMIC3_SRC_MASK			(0x1 << 1) +#define RT5645_DMIC3_SRC_SFT			0 + +/* Mono ADC Mixer Control (0x28) */ +#define RT5645_M_MONO_ADC_L1			(0x1 << 14) +#define RT5645_M_MONO_ADC_L1_SFT		14 +#define RT5645_M_MONO_ADC_L2			(0x1 << 13) +#define RT5645_M_MONO_ADC_L2_SFT		13 +#define RT5645_MONO_ADC_L1_SRC_MASK		(0x1 << 12) +#define RT5645_MONO_ADC_L1_SRC_SFT		12 +#define RT5645_MONO_ADC_L1_SRC_DACMIXL		(0x0 << 12) +#define RT5645_MONO_ADC_L1_SRC_ADCL		(0x1 << 12) +#define RT5645_MONO_ADC_L2_SRC_MASK		(0x1 << 11) +#define RT5645_MONO_ADC_L2_SRC_SFT		11 +#define RT5645_MONO_DMIC_L_SRC_MASK		(0x1 << 8) +#define RT5645_MONO_DMIC_L_SRC_SFT		8 +#define RT5645_M_MONO_ADC_R1			(0x1 << 6) +#define RT5645_M_MONO_ADC_R1_SFT		6 +#define RT5645_M_MONO_ADC_R2			(0x1 << 5) +#define RT5645_M_MONO_ADC_R2_SFT		5 +#define RT5645_MONO_ADC_R1_SRC_MASK		(0x1 << 4) +#define RT5645_MONO_ADC_R1_SRC_SFT		4 +#define RT5645_MONO_ADC_R1_SRC_ADCR		(0x1 << 4) +#define RT5645_MONO_ADC_R1_SRC_DACMIXR		(0x0 << 4) +#define RT5645_MONO_ADC_R2_SRC_MASK		(0x1 << 3) +#define RT5645_MONO_ADC_R2_SRC_SFT		3 +#define RT5645_MONO_DMIC_R_SRC_MASK		(0x3) +#define RT5645_MONO_DMIC_R_SRC_SFT		0 + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5645_M_ADCMIX_L			(0x1 << 15) +#define RT5645_M_ADCMIX_L_SFT			15 +#define RT5645_M_DAC1_L				(0x1 << 14) +#define RT5645_M_DAC1_L_SFT			14 +#define RT5645_DAC1_R_SEL_MASK			(0x3 << 10) +#define RT5645_DAC1_R_SEL_SFT			10 +#define RT5645_DAC1_R_SEL_IF1			(0x0 << 10) +#define RT5645_DAC1_R_SEL_IF2			(0x1 << 10) +#define RT5645_DAC1_R_SEL_IF3			(0x2 << 10) +#define RT5645_DAC1_R_SEL_IF4			(0x3 << 10) +#define RT5645_DAC1_L_SEL_MASK			(0x3 << 8) +#define RT5645_DAC1_L_SEL_SFT			8 +#define RT5645_DAC1_L_SEL_IF1			(0x0 << 8) +#define RT5645_DAC1_L_SEL_IF2			(0x1 << 8) +#define RT5645_DAC1_L_SEL_IF3			(0x2 << 8) +#define RT5645_DAC1_L_SEL_IF4			(0x3 << 8) +#define RT5645_M_ADCMIX_R			(0x1 << 7) +#define RT5645_M_ADCMIX_R_SFT			7 +#define RT5645_M_DAC1_R				(0x1 << 6) +#define RT5645_M_DAC1_R_SFT			6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5645_M_DAC_L1				(0x1 << 14) +#define RT5645_M_DAC_L1_SFT			14 +#define RT5645_DAC_L1_STO_L_VOL_MASK		(0x1 << 13) +#define RT5645_DAC_L1_STO_L_VOL_SFT		13 +#define RT5645_M_DAC_L2				(0x1 << 12) +#define RT5645_M_DAC_L2_SFT			12 +#define RT5645_DAC_L2_STO_L_VOL_MASK		(0x1 << 11) +#define RT5645_DAC_L2_STO_L_VOL_SFT		11 +#define RT5645_M_ANC_DAC_L			(0x1 << 10) +#define RT5645_M_ANC_DAC_L_SFT			10 +#define RT5645_M_DAC_R1_STO_L			(0x1 << 9) +#define RT5645_M_DAC_R1_STO_L_SFT			9 +#define RT5645_DAC_R1_STO_L_VOL_MASK		(0x1 << 8) +#define RT5645_DAC_R1_STO_L_VOL_SFT		8 +#define RT5645_M_DAC_R1				(0x1 << 6) +#define RT5645_M_DAC_R1_SFT			6 +#define RT5645_DAC_R1_STO_R_VOL_MASK		(0x1 << 5) +#define RT5645_DAC_R1_STO_R_VOL_SFT		5 +#define RT5645_M_DAC_R2				(0x1 << 4) +#define RT5645_M_DAC_R2_SFT			4 +#define RT5645_DAC_R2_STO_R_VOL_MASK		(0x1 << 3) +#define RT5645_DAC_R2_STO_R_VOL_SFT		3 +#define RT5645_M_ANC_DAC_R			(0x1 << 2) +#define RT5645_M_ANC_DAC_R_SFT			2 +#define RT5645_M_DAC_L1_STO_R			(0x1 << 1) +#define RT5645_M_DAC_L1_STO_R_SFT			1 +#define RT5645_DAC_L1_STO_R_VOL_MASK		(0x1) +#define RT5645_DAC_L1_STO_R_VOL_SFT		0 + +/* Mono DAC Mixer Control (0x2b) */ +#define RT5645_M_DAC_L1_MONO_L			(0x1 << 14) +#define RT5645_M_DAC_L1_MONO_L_SFT		14 +#define RT5645_DAC_L1_MONO_L_VOL_MASK		(0x1 << 13) +#define RT5645_DAC_L1_MONO_L_VOL_SFT		13 +#define RT5645_M_DAC_L2_MONO_L			(0x1 << 12) +#define RT5645_M_DAC_L2_MONO_L_SFT		12 +#define RT5645_DAC_L2_MONO_L_VOL_MASK		(0x1 << 11) +#define RT5645_DAC_L2_MONO_L_VOL_SFT		11 +#define RT5645_M_DAC_R2_MONO_L			(0x1 << 10) +#define RT5645_M_DAC_R2_MONO_L_SFT		10 +#define RT5645_DAC_R2_MONO_L_VOL_MASK		(0x1 << 9) +#define RT5645_DAC_R2_MONO_L_VOL_SFT		9 +#define RT5645_M_DAC_R1_MONO_R			(0x1 << 6) +#define RT5645_M_DAC_R1_MONO_R_SFT		6 +#define RT5645_DAC_R1_MONO_R_VOL_MASK		(0x1 << 5) +#define RT5645_DAC_R1_MONO_R_VOL_SFT		5 +#define RT5645_M_DAC_R2_MONO_R			(0x1 << 4) +#define RT5645_M_DAC_R2_MONO_R_SFT		4 +#define RT5645_DAC_R2_MONO_R_VOL_MASK		(0x1 << 3) +#define RT5645_DAC_R2_MONO_R_VOL_SFT		3 +#define RT5645_M_DAC_L2_MONO_R			(0x1 << 2) +#define RT5645_M_DAC_L2_MONO_R_SFT		2 +#define RT5645_DAC_L2_MONO_R_VOL_MASK		(0x1 << 1) +#define RT5645_DAC_L2_MONO_R_VOL_SFT		1 + +/* Digital Mixer Control (0x2c) */ +#define RT5645_M_STO_L_DAC_L			(0x1 << 15) +#define RT5645_M_STO_L_DAC_L_SFT		15 +#define RT5645_STO_L_DAC_L_VOL_MASK		(0x1 << 14) +#define RT5645_STO_L_DAC_L_VOL_SFT		14 +#define RT5645_M_DAC_L2_DAC_L			(0x1 << 13) +#define RT5645_M_DAC_L2_DAC_L_SFT		13 +#define RT5645_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12) +#define RT5645_DAC_L2_DAC_L_VOL_SFT		12 +#define RT5645_M_STO_R_DAC_R			(0x1 << 11) +#define RT5645_M_STO_R_DAC_R_SFT		11 +#define RT5645_STO_R_DAC_R_VOL_MASK		(0x1 << 10) +#define RT5645_STO_R_DAC_R_VOL_SFT		10 +#define RT5645_M_DAC_R2_DAC_R			(0x1 << 9) +#define RT5645_M_DAC_R2_DAC_R_SFT		9 +#define RT5645_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8) +#define RT5645_DAC_R2_DAC_R_VOL_SFT		8 +#define RT5645_M_DAC_R2_DAC_L			(0x1 << 7) +#define RT5645_M_DAC_R2_DAC_L_SFT		7 +#define RT5645_DAC_R2_DAC_L_VOL_MASK		(0x1 << 6) +#define RT5645_DAC_R2_DAC_L_VOL_SFT		6 +#define RT5645_M_DAC_L2_DAC_R			(0x1 << 5) +#define RT5645_M_DAC_L2_DAC_R_SFT		5 +#define RT5645_DAC_L2_DAC_R_VOL_MASK		(0x1 << 4) +#define RT5645_DAC_L2_DAC_R_VOL_SFT		4 + +/* Digital Interface Data Control (0x2f) */ +#define RT5645_IF1_ADC2_IN_SEL			(0x1 << 15) +#define RT5645_IF1_ADC2_IN_SFT			15 +#define RT5645_IF2_ADC_IN_MASK			(0x7 << 12) +#define RT5645_IF2_ADC_IN_SFT			12 +#define RT5645_IF2_DAC_SEL_MASK			(0x3 << 10) +#define RT5645_IF2_DAC_SEL_SFT			10 +#define RT5645_IF2_ADC_SEL_MASK			(0x3 << 8) +#define RT5645_IF2_ADC_SEL_SFT			8 +#define RT5645_IF3_DAC_SEL_MASK			(0x3 << 6) +#define RT5645_IF3_DAC_SEL_SFT			6 +#define RT5645_IF3_ADC_SEL_MASK			(0x3 << 4) +#define RT5645_IF3_ADC_SEL_SFT			4 +#define RT5645_IF3_ADC_IN_MASK			(0x7) +#define RT5645_IF3_ADC_IN_SFT			0 + +/* PDM Output Control (0x31) */ +#define RT5645_PDM1_L_MASK			(0x1 << 15) +#define RT5645_PDM1_L_SFT			15 +#define RT5645_M_PDM1_L				(0x1 << 14) +#define RT5645_M_PDM1_L_SFT			14 +#define RT5645_PDM1_R_MASK			(0x1 << 13) +#define RT5645_PDM1_R_SFT			13 +#define RT5645_M_PDM1_R				(0x1 << 12) +#define RT5645_M_PDM1_R_SFT			12 +#define RT5645_PDM2_L_MASK			(0x1 << 11) +#define RT5645_PDM2_L_SFT			11 +#define RT5645_M_PDM2_L				(0x1 << 10) +#define RT5645_M_PDM2_L_SFT			10 +#define RT5645_PDM2_R_MASK			(0x1 << 9) +#define RT5645_PDM2_R_SFT			9 +#define RT5645_M_PDM2_R				(0x1 << 8) +#define RT5645_M_PDM2_R_SFT			8 +#define RT5645_PDM2_BUSY			(0x1 << 7) +#define RT5645_PDM1_BUSY			(0x1 << 6) +#define RT5645_PDM_PATTERN			(0x1 << 5) +#define RT5645_PDM_GAIN				(0x1 << 4) +#define RT5645_PDM_DIV_MASK			(0x3) + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5645_G_HP_L_RM_L_MASK			(0x7 << 13) +#define RT5645_G_HP_L_RM_L_SFT			13 +#define RT5645_G_IN_L_RM_L_MASK			(0x7 << 10) +#define RT5645_G_IN_L_RM_L_SFT			10 +#define RT5645_G_BST4_RM_L_MASK			(0x7 << 7) +#define RT5645_G_BST4_RM_L_SFT			7 +#define RT5645_G_BST3_RM_L_MASK			(0x7 << 4) +#define RT5645_G_BST3_RM_L_SFT			4 +#define RT5645_G_BST2_RM_L_MASK			(0x7 << 1) +#define RT5645_G_BST2_RM_L_SFT			1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5645_G_BST1_RM_L_MASK			(0x7 << 13) +#define RT5645_G_BST1_RM_L_SFT			13 +#define RT5645_G_OM_L_RM_L_MASK			(0x7 << 10) +#define RT5645_G_OM_L_RM_L_SFT			10 +#define RT5645_M_MM_L_RM_L			(0x1 << 6) +#define RT5645_M_MM_L_RM_L_SFT			6 +#define RT5645_M_IN_L_RM_L			(0x1 << 5) +#define RT5645_M_IN_L_RM_L_SFT			5 +#define RT5645_M_HP_L_RM_L			(0x1 << 4) +#define RT5645_M_HP_L_RM_L_SFT			4 +#define RT5645_M_BST3_RM_L			(0x1 << 3) +#define RT5645_M_BST3_RM_L_SFT			3 +#define RT5645_M_BST2_RM_L			(0x1 << 2) +#define RT5645_M_BST2_RM_L_SFT			2 +#define RT5645_M_BST1_RM_L			(0x1 << 1) +#define RT5645_M_BST1_RM_L_SFT			1 +#define RT5645_M_OM_L_RM_L			(0x1) +#define RT5645_M_OM_L_RM_L_SFT			0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5645_G_HP_R_RM_R_MASK			(0x7 << 13) +#define RT5645_G_HP_R_RM_R_SFT			13 +#define RT5645_G_IN_R_RM_R_MASK			(0x7 << 10) +#define RT5645_G_IN_R_RM_R_SFT			10 +#define RT5645_G_BST4_RM_R_MASK			(0x7 << 7) +#define RT5645_G_BST4_RM_R_SFT			7 +#define RT5645_G_BST3_RM_R_MASK			(0x7 << 4) +#define RT5645_G_BST3_RM_R_SFT			4 +#define RT5645_G_BST2_RM_R_MASK			(0x7 << 1) +#define RT5645_G_BST2_RM_R_SFT			1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5645_G_BST1_RM_R_MASK			(0x7 << 13) +#define RT5645_G_BST1_RM_R_SFT			13 +#define RT5645_G_OM_R_RM_R_MASK			(0x7 << 10) +#define RT5645_G_OM_R_RM_R_SFT			10 +#define RT5645_M_MM_R_RM_R			(0x1 << 6) +#define RT5645_M_MM_R_RM_R_SFT			6 +#define RT5645_M_IN_R_RM_R			(0x1 << 5) +#define RT5645_M_IN_R_RM_R_SFT			5 +#define RT5645_M_HP_R_RM_R			(0x1 << 4) +#define RT5645_M_HP_R_RM_R_SFT			4 +#define RT5645_M_BST3_RM_R			(0x1 << 3) +#define RT5645_M_BST3_RM_R_SFT			3 +#define RT5645_M_BST2_RM_R			(0x1 << 2) +#define RT5645_M_BST2_RM_R_SFT			2 +#define RT5645_M_BST1_RM_R			(0x1 << 1) +#define RT5645_M_BST1_RM_R_SFT			1 +#define RT5645_M_OM_R_RM_R			(0x1) +#define RT5645_M_OM_R_RM_R_SFT			0 + +/* HPOMIX Control (0x40) (0x42) */ +#define RT5645_M_BST1_HV			(0x1 << 4) +#define RT5645_M_BST1_HV_SFT			4 +#define RT5645_M_BST2_HV			(0x1 << 4) +#define RT5645_M_BST2_HV_SFT			4 +#define RT5645_M_BST3_HV			(0x1 << 3) +#define RT5645_M_BST3_HV_SFT			3 +#define RT5645_M_IN_HV				(0x1 << 2) +#define RT5645_M_IN_HV_SFT			2 +#define RT5645_M_DAC2_HV			(0x1 << 1) +#define RT5645_M_DAC2_HV_SFT			1 +#define RT5645_M_DAC1_HV			(0x1 << 0) +#define RT5645_M_DAC1_HV_SFT			0 + +/* HPMIX Control (0x45) */ +#define RT5645_M_DAC1_HM			(0x1 << 14) +#define RT5645_M_DAC1_HM_SFT			14 +#define RT5645_M_HPVOL_HM			(0x1 << 13) +#define RT5645_M_HPVOL_HM_SFT			13 + +/* SPK Left Mixer Control (0x46) */ +#define RT5645_G_RM_L_SM_L_MASK			(0x3 << 14) +#define RT5645_G_RM_L_SM_L_SFT			14 +#define RT5645_G_IN_L_SM_L_MASK			(0x3 << 12) +#define RT5645_G_IN_L_SM_L_SFT			12 +#define RT5645_G_DAC_L1_SM_L_MASK		(0x3 << 10) +#define RT5645_G_DAC_L1_SM_L_SFT		10 +#define RT5645_G_DAC_L2_SM_L_MASK		(0x3 << 8) +#define RT5645_G_DAC_L2_SM_L_SFT		8 +#define RT5645_G_OM_L_SM_L_MASK			(0x3 << 6) +#define RT5645_G_OM_L_SM_L_SFT			6 +#define RT5645_M_BST1_L_SM_L			(0x1 << 5) +#define RT5645_M_BST1_L_SM_L_SFT		5 +#define RT5645_M_IN_L_SM_L			(0x1 << 3) +#define RT5645_M_IN_L_SM_L_SFT			3 +#define RT5645_M_DAC_L1_SM_L			(0x1 << 1) +#define RT5645_M_DAC_L1_SM_L_SFT		1 +#define RT5645_M_DAC_L2_SM_L			(0x1 << 2) +#define RT5645_M_DAC_L2_SM_L_SFT		2 +#define RT5645_M_BST3_L_SM_L			(0x1 << 4) +#define RT5645_M_BST3_L_SM_L_SFT		4 + +/* SPK Right Mixer Control (0x47) */ +#define RT5645_G_RM_R_SM_R_MASK			(0x3 << 14) +#define RT5645_G_RM_R_SM_R_SFT			14 +#define RT5645_G_IN_R_SM_R_MASK			(0x3 << 12) +#define RT5645_G_IN_R_SM_R_SFT			12 +#define RT5645_G_DAC_R1_SM_R_MASK		(0x3 << 10) +#define RT5645_G_DAC_R1_SM_R_SFT		10 +#define RT5645_G_DAC_R2_SM_R_MASK		(0x3 << 8) +#define RT5645_G_DAC_R2_SM_R_SFT		8 +#define RT5645_G_OM_R_SM_R_MASK			(0x3 << 6) +#define RT5645_G_OM_R_SM_R_SFT			6 +#define RT5645_M_BST2_R_SM_R			(0x1 << 5) +#define RT5645_M_BST2_R_SM_R_SFT		5 +#define RT5645_M_IN_R_SM_R			(0x1 << 3) +#define RT5645_M_IN_R_SM_R_SFT			3 +#define RT5645_M_DAC_R1_SM_R			(0x1 << 1) +#define RT5645_M_DAC_R1_SM_R_SFT		1 +#define RT5645_M_DAC_R2_SM_R			(0x1 << 2) +#define RT5645_M_DAC_R2_SM_R_SFT		2 +#define RT5645_M_BST3_R_SM_R			(0x1 << 4) +#define RT5645_M_BST3_R_SM_R_SFT		4 + +/* SPOLMIX Control (0x48) */ +#define RT5645_M_DAC_L1_SPM_L			(0x1 << 15) +#define RT5645_M_DAC_L1_SPM_L_SFT		15 +#define RT5645_M_DAC_R1_SPM_L			(0x1 << 14) +#define RT5645_M_DAC_R1_SPM_L_SFT		14 +#define RT5645_M_SV_L_SPM_L			(0x1 << 13) +#define RT5645_M_SV_L_SPM_L_SFT			13 +#define RT5645_M_SV_R_SPM_L			(0x1 << 12) +#define RT5645_M_SV_R_SPM_L_SFT			12 +#define RT5645_M_BST3_SPM_L			(0x1 << 11) +#define RT5645_M_BST3_SPM_L_SFT			11 +#define RT5645_M_DAC_R1_SPM_R			(0x1 << 2) +#define RT5645_M_DAC_R1_SPM_R_SFT		2 +#define RT5645_M_BST3_SPM_R			(0x1 << 1) +#define RT5645_M_BST3_SPM_R_SFT			1 +#define RT5645_M_SV_R_SPM_R			(0x1 << 0) +#define RT5645_M_SV_R_SPM_R_SFT			0 + +/* Mono Output Mixer Control (0x4c) */ +#define RT5645_M_OV_L_MM			(0x1 << 9) +#define RT5645_M_OV_L_MM_SFT			9 +#define RT5645_M_DAC_L2_MA			(0x1 << 8) +#define RT5645_M_DAC_L2_MA_SFT			8 +#define RT5645_G_MONOMIX_MASK			(0x1 << 10) +#define RT5645_G_MONOMIX_SFT			10 +#define RT5645_M_BST2_MM			(0x1 << 4) +#define RT5645_M_BST2_MM_SFT			4 +#define RT5645_M_DAC_R1_MM			(0x1 << 3) +#define RT5645_M_DAC_R1_MM_SFT			3 +#define RT5645_M_DAC_R2_MM			(0x1 << 2) +#define RT5645_M_DAC_R2_MM_SFT			2 +#define RT5645_M_DAC_L2_MM			(0x1 << 1) +#define RT5645_M_DAC_L2_MM_SFT			1 +#define RT5645_M_BST3_MM			(0x1 << 0) +#define RT5645_M_BST3_MM_SFT			0 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5645_G_BST3_OM_L_MASK			(0x7 << 13) +#define RT5645_G_BST3_OM_L_SFT			13 +#define RT5645_G_BST2_OM_L_MASK			(0x7 << 10) +#define RT5645_G_BST2_OM_L_SFT			10 +#define RT5645_G_BST1_OM_L_MASK			(0x7 << 7) +#define RT5645_G_BST1_OM_L_SFT			7 +#define RT5645_G_IN_L_OM_L_MASK			(0x7 << 4) +#define RT5645_G_IN_L_OM_L_SFT			4 +#define RT5645_G_RM_L_OM_L_MASK			(0x7 << 1) +#define RT5645_G_RM_L_OM_L_SFT			1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5645_G_DAC_R2_OM_L_MASK		(0x7 << 13) +#define RT5645_G_DAC_R2_OM_L_SFT		13 +#define RT5645_G_DAC_L2_OM_L_MASK		(0x7 << 10) +#define RT5645_G_DAC_L2_OM_L_SFT		10 +#define RT5645_G_DAC_L1_OM_L_MASK		(0x7 << 7) +#define RT5645_G_DAC_L1_OM_L_SFT		7 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5645_M_BST3_OM_L			(0x1 << 4) +#define RT5645_M_BST3_OM_L_SFT			4 +#define RT5645_M_BST1_OM_L			(0x1 << 3) +#define RT5645_M_BST1_OM_L_SFT			3 +#define RT5645_M_IN_L_OM_L			(0x1 << 2) +#define RT5645_M_IN_L_OM_L_SFT			2 +#define RT5645_M_DAC_L2_OM_L			(0x1 << 1) +#define RT5645_M_DAC_L2_OM_L_SFT		1 +#define RT5645_M_DAC_L1_OM_L			(0x1) +#define RT5645_M_DAC_L1_OM_L_SFT		0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5645_G_BST4_OM_R_MASK			(0x7 << 13) +#define RT5645_G_BST4_OM_R_SFT			13 +#define RT5645_G_BST2_OM_R_MASK			(0x7 << 10) +#define RT5645_G_BST2_OM_R_SFT			10 +#define RT5645_G_BST1_OM_R_MASK			(0x7 << 7) +#define RT5645_G_BST1_OM_R_SFT			7 +#define RT5645_G_IN_R_OM_R_MASK			(0x7 << 4) +#define RT5645_G_IN_R_OM_R_SFT			4 +#define RT5645_G_RM_R_OM_R_MASK			(0x7 << 1) +#define RT5645_G_RM_R_OM_R_SFT			1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5645_G_DAC_L2_OM_R_MASK		(0x7 << 13) +#define RT5645_G_DAC_L2_OM_R_SFT		13 +#define RT5645_G_DAC_R2_OM_R_MASK		(0x7 << 10) +#define RT5645_G_DAC_R2_OM_R_SFT		10 +#define RT5645_G_DAC_R1_OM_R_MASK		(0x7 << 7) +#define RT5645_G_DAC_R1_OM_R_SFT		7 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5645_M_BST3_OM_R			(0x1 << 4) +#define RT5645_M_BST3_OM_R_SFT			4 +#define RT5645_M_BST2_OM_R			(0x1 << 3) +#define RT5645_M_BST2_OM_R_SFT			3 +#define RT5645_M_IN_R_OM_R			(0x1 << 2) +#define RT5645_M_IN_R_OM_R_SFT			2 +#define RT5645_M_DAC_R2_OM_R			(0x1 << 1) +#define RT5645_M_DAC_R2_OM_R_SFT		1 +#define RT5645_M_DAC_R1_OM_R			(0x1) +#define RT5645_M_DAC_R1_OM_R_SFT		0 + +/* LOUT Mixer Control (0x53) */ +#define RT5645_M_DAC_L1_LM			(0x1 << 15) +#define RT5645_M_DAC_L1_LM_SFT			15 +#define RT5645_M_DAC_R1_LM			(0x1 << 14) +#define RT5645_M_DAC_R1_LM_SFT			14 +#define RT5645_M_OV_L_LM			(0x1 << 13) +#define RT5645_M_OV_L_LM_SFT			13 +#define RT5645_M_OV_R_LM			(0x1 << 12) +#define RT5645_M_OV_R_LM_SFT			12 +#define RT5645_G_LOUTMIX_MASK			(0x1 << 11) +#define RT5645_G_LOUTMIX_SFT			11 + +/* Power Management for Digital 1 (0x61) */ +#define RT5645_PWR_I2S1				(0x1 << 15) +#define RT5645_PWR_I2S1_BIT			15 +#define RT5645_PWR_I2S2				(0x1 << 14) +#define RT5645_PWR_I2S2_BIT			14 +#define RT5645_PWR_I2S3				(0x1 << 13) +#define RT5645_PWR_I2S3_BIT			13 +#define RT5645_PWR_DAC_L1			(0x1 << 12) +#define RT5645_PWR_DAC_L1_BIT			12 +#define RT5645_PWR_DAC_R1			(0x1 << 11) +#define RT5645_PWR_DAC_R1_BIT			11 +#define RT5645_PWR_CLS_D_R			(0x1 << 9) +#define RT5645_PWR_CLS_D_R_BIT			9 +#define RT5645_PWR_CLS_D_L			(0x1 << 8) +#define RT5645_PWR_CLS_D_L_BIT			8 +#define RT5645_PWR_ADC_R			(0x1 << 1) +#define RT5645_PWR_ADC_R_BIT			1 +#define RT5645_PWR_DAC_L2			(0x1 << 7) +#define RT5645_PWR_DAC_L2_BIT			7 +#define RT5645_PWR_DAC_R2			(0x1 << 6) +#define RT5645_PWR_DAC_R2_BIT			6 +#define RT5645_PWR_ADC_L			(0x1 << 2) +#define RT5645_PWR_ADC_L_BIT			2 +#define RT5645_PWR_ADC_R			(0x1 << 1) +#define RT5645_PWR_ADC_R_BIT			1 +#define RT5645_PWR_CLS_D			(0x1) +#define RT5645_PWR_CLS_D_BIT			0 + +/* Power Management for Digital 2 (0x62) */ +#define RT5645_PWR_ADC_S1F			(0x1 << 15) +#define RT5645_PWR_ADC_S1F_BIT			15 +#define RT5645_PWR_ADC_MF_L			(0x1 << 14) +#define RT5645_PWR_ADC_MF_L_BIT			14 +#define RT5645_PWR_ADC_MF_R			(0x1 << 13) +#define RT5645_PWR_ADC_MF_R_BIT			13 +#define RT5645_PWR_I2S_DSP			(0x1 << 12) +#define RT5645_PWR_I2S_DSP_BIT			12 +#define RT5645_PWR_DAC_S1F			(0x1 << 11) +#define RT5645_PWR_DAC_S1F_BIT			11 +#define RT5645_PWR_DAC_MF_L			(0x1 << 10) +#define RT5645_PWR_DAC_MF_L_BIT			10 +#define RT5645_PWR_DAC_MF_R			(0x1 << 9) +#define RT5645_PWR_DAC_MF_R_BIT			9 +#define RT5645_PWR_ADC_S2F			(0x1 << 8) +#define RT5645_PWR_ADC_S2F_BIT			8 +#define RT5645_PWR_PDM1				(0x1 << 7) +#define RT5645_PWR_PDM1_BIT			7 +#define RT5645_PWR_PDM2				(0x1 << 6) +#define RT5645_PWR_PDM2_BIT			6 +#define RT5645_PWR_IPTV				(0x1 << 1) +#define RT5645_PWR_IPTV_BIT			1 +#define RT5645_PWR_PAD				(0x1) +#define RT5645_PWR_PAD_BIT			0 + +/* Power Management for Analog 1 (0x63) */ +#define RT5645_PWR_VREF1			(0x1 << 15) +#define RT5645_PWR_VREF1_BIT			15 +#define RT5645_PWR_FV1				(0x1 << 14) +#define RT5645_PWR_FV1_BIT			14 +#define RT5645_PWR_MB				(0x1 << 13) +#define RT5645_PWR_MB_BIT			13 +#define RT5645_PWR_LM				(0x1 << 12) +#define RT5645_PWR_LM_BIT			12 +#define RT5645_PWR_BG				(0x1 << 11) +#define RT5645_PWR_BG_BIT			11 +#define RT5645_PWR_MA				(0x1 << 10) +#define RT5645_PWR_MA_BIT			10 +#define RT5645_PWR_HP_L				(0x1 << 7) +#define RT5645_PWR_HP_L_BIT			7 +#define RT5645_PWR_HP_R				(0x1 << 6) +#define RT5645_PWR_HP_R_BIT			6 +#define RT5645_PWR_HA				(0x1 << 5) +#define RT5645_PWR_HA_BIT			5 +#define RT5645_PWR_VREF2			(0x1 << 4) +#define RT5645_PWR_VREF2_BIT			4 +#define RT5645_PWR_FV2				(0x1 << 3) +#define RT5645_PWR_FV2_BIT			3 +#define RT5645_LDO_SEL_MASK			(0x3) +#define RT5645_LDO_SEL_SFT			0 + +/* Power Management for Analog 2 (0x64) */ +#define RT5645_PWR_BST1				(0x1 << 15) +#define RT5645_PWR_BST1_BIT			15 +#define RT5645_PWR_BST2				(0x1 << 14) +#define RT5645_PWR_BST2_BIT			14 +#define RT5645_PWR_BST3				(0x1 << 13) +#define RT5645_PWR_BST3_BIT			13 +#define RT5645_PWR_BST4				(0x1 << 12) +#define RT5645_PWR_BST4_BIT			12 +#define RT5645_PWR_MB1				(0x1 << 11) +#define RT5645_PWR_MB1_BIT			11 +#define RT5645_PWR_MB2				(0x1 << 10) +#define RT5645_PWR_MB2_BIT			10 +#define RT5645_PWR_PLL				(0x1 << 9) +#define RT5645_PWR_PLL_BIT			9 +#define RT5645_PWR_BST2_P			(0x1 << 5) +#define RT5645_PWR_BST2_P_BIT			5 +#define RT5645_PWR_BST3_P			(0x1 << 4) +#define RT5645_PWR_BST3_P_BIT			4 +#define RT5645_PWR_BST4_P			(0x1 << 3) +#define RT5645_PWR_BST4_P_BIT			3 +#define RT5645_PWR_JD1				(0x1 << 2) +#define RT5645_PWR_JD1_BIT			2 +#define RT5645_PWR_JD				(0x1 << 1) +#define RT5645_PWR_JD_BIT			1 + +/* Power Management for Mixer (0x65) */ +#define RT5645_PWR_OM_L				(0x1 << 15) +#define RT5645_PWR_OM_L_BIT			15 +#define RT5645_PWR_OM_R				(0x1 << 14) +#define RT5645_PWR_OM_R_BIT			14 +#define RT5645_PWR_SM_L				(0x1 << 13) +#define RT5645_PWR_SM_L_BIT			13 +#define RT5645_PWR_SM_R				(0x1 << 12) +#define RT5645_PWR_SM_R_BIT			12 +#define RT5645_PWR_RM_L				(0x1 << 11) +#define RT5645_PWR_RM_L_BIT			11 +#define RT5645_PWR_RM_R				(0x1 << 10) +#define RT5645_PWR_RM_R_BIT			10 +#define RT5645_PWR_MM				(0x1 << 8) +#define RT5645_PWR_MM_BIT			8 +#define RT5645_PWR_HM_L				(0x1 << 7) +#define RT5645_PWR_HM_L_BIT			7 +#define RT5645_PWR_HM_R				(0x1 << 6) +#define RT5645_PWR_HM_R_BIT			6 +#define RT5645_PWR_LDO2				(0x1 << 1) +#define RT5645_PWR_LDO2_BIT			1 + +/* Power Management for Volume (0x66) */ +#define RT5645_PWR_SV_L				(0x1 << 15) +#define RT5645_PWR_SV_L_BIT			15 +#define RT5645_PWR_SV_R				(0x1 << 14) +#define RT5645_PWR_SV_R_BIT			14 +#define RT5645_PWR_HV_L				(0x1 << 11) +#define RT5645_PWR_HV_L_BIT			11 +#define RT5645_PWR_HV_R				(0x1 << 10) +#define RT5645_PWR_HV_R_BIT			10 +#define RT5645_PWR_IN_L				(0x1 << 9) +#define RT5645_PWR_IN_L_BIT			9 +#define RT5645_PWR_IN_R				(0x1 << 8) +#define RT5645_PWR_IN_R_BIT			8 +#define RT5645_PWR_MIC_DET			(0x1 << 5) +#define RT5645_PWR_MIC_DET_BIT			5 + +/* I2S1/2 Audio Serial Data Port Control (0x70 0x71) */ +#define RT5645_I2S_MS_MASK			(0x1 << 15) +#define RT5645_I2S_MS_SFT			15 +#define RT5645_I2S_MS_M				(0x0 << 15) +#define RT5645_I2S_MS_S				(0x1 << 15) +#define RT5645_I2S_O_CP_MASK			(0x3 << 10) +#define RT5645_I2S_O_CP_SFT			10 +#define RT5645_I2S_O_CP_OFF			(0x0 << 10) +#define RT5645_I2S_O_CP_U_LAW			(0x1 << 10) +#define RT5645_I2S_O_CP_A_LAW			(0x2 << 10) +#define RT5645_I2S_I_CP_MASK			(0x3 << 8) +#define RT5645_I2S_I_CP_SFT			8 +#define RT5645_I2S_I_CP_OFF			(0x0 << 8) +#define RT5645_I2S_I_CP_U_LAW			(0x1 << 8) +#define RT5645_I2S_I_CP_A_LAW			(0x2 << 8) +#define RT5645_I2S_BP_MASK			(0x1 << 7) +#define RT5645_I2S_BP_SFT			7 +#define RT5645_I2S_BP_NOR			(0x0 << 7) +#define RT5645_I2S_BP_INV			(0x1 << 7) +#define RT5645_I2S_DL_MASK			(0x3 << 2) +#define RT5645_I2S_DL_SFT			2 +#define RT5645_I2S_DL_16			(0x0 << 2) +#define RT5645_I2S_DL_20			(0x1 << 2) +#define RT5645_I2S_DL_24			(0x2 << 2) +#define RT5645_I2S_DL_8				(0x3 << 2) +#define RT5645_I2S_DF_MASK			(0x3) +#define RT5645_I2S_DF_SFT			0 +#define RT5645_I2S_DF_I2S			(0x0) +#define RT5645_I2S_DF_LEFT			(0x1) +#define RT5645_I2S_DF_PCM_A			(0x2) +#define RT5645_I2S_DF_PCM_B			(0x3) + +/* I2S2 Audio Serial Data Port Control (0x71) */ +#define RT5645_I2S2_SDI_MASK			(0x1 << 6) +#define RT5645_I2S2_SDI_SFT			6 +#define RT5645_I2S2_SDI_I2S1			(0x0 << 6) +#define RT5645_I2S2_SDI_I2S2			(0x1 << 6) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5645_I2S_BCLK_MS1_MASK		(0x1 << 15) +#define RT5645_I2S_BCLK_MS1_SFT			15 +#define RT5645_I2S_BCLK_MS1_32			(0x0 << 15) +#define RT5645_I2S_BCLK_MS1_64			(0x1 << 15) +#define RT5645_I2S_PD1_MASK			(0x7 << 12) +#define RT5645_I2S_PD1_SFT			12 +#define RT5645_I2S_PD1_1			(0x0 << 12) +#define RT5645_I2S_PD1_2			(0x1 << 12) +#define RT5645_I2S_PD1_3			(0x2 << 12) +#define RT5645_I2S_PD1_4			(0x3 << 12) +#define RT5645_I2S_PD1_6			(0x4 << 12) +#define RT5645_I2S_PD1_8			(0x5 << 12) +#define RT5645_I2S_PD1_12			(0x6 << 12) +#define RT5645_I2S_PD1_16			(0x7 << 12) +#define RT5645_I2S_BCLK_MS2_MASK		(0x1 << 11) +#define RT5645_I2S_BCLK_MS2_SFT			11 +#define RT5645_I2S_BCLK_MS2_32			(0x0 << 11) +#define RT5645_I2S_BCLK_MS2_64			(0x1 << 11) +#define RT5645_I2S_PD2_MASK			(0x7 << 8) +#define RT5645_I2S_PD2_SFT			8 +#define RT5645_I2S_PD2_1			(0x0 << 8) +#define RT5645_I2S_PD2_2			(0x1 << 8) +#define RT5645_I2S_PD2_3			(0x2 << 8) +#define RT5645_I2S_PD2_4			(0x3 << 8) +#define RT5645_I2S_PD2_6			(0x4 << 8) +#define RT5645_I2S_PD2_8			(0x5 << 8) +#define RT5645_I2S_PD2_12			(0x6 << 8) +#define RT5645_I2S_PD2_16			(0x7 << 8) +#define RT5645_I2S_BCLK_MS3_MASK		(0x1 << 7) +#define RT5645_I2S_BCLK_MS3_SFT			7 +#define RT5645_I2S_BCLK_MS3_32			(0x0 << 7) +#define RT5645_I2S_BCLK_MS3_64			(0x1 << 7) +#define RT5645_I2S_PD3_MASK			(0x7 << 4) +#define RT5645_I2S_PD3_SFT			4 +#define RT5645_I2S_PD3_1			(0x0 << 4) +#define RT5645_I2S_PD3_2			(0x1 << 4) +#define RT5645_I2S_PD3_3			(0x2 << 4) +#define RT5645_I2S_PD3_4			(0x3 << 4) +#define RT5645_I2S_PD3_6			(0x4 << 4) +#define RT5645_I2S_PD3_8			(0x5 << 4) +#define RT5645_I2S_PD3_12			(0x6 << 4) +#define RT5645_I2S_PD3_16			(0x7 << 4) +#define RT5645_DAC_OSR_MASK			(0x3 << 2) +#define RT5645_DAC_OSR_SFT			2 +#define RT5645_DAC_OSR_128			(0x0 << 2) +#define RT5645_DAC_OSR_64			(0x1 << 2) +#define RT5645_DAC_OSR_32			(0x2 << 2) +#define RT5645_DAC_OSR_16			(0x3 << 2) +#define RT5645_ADC_OSR_MASK			(0x3) +#define RT5645_ADC_OSR_SFT			0 +#define RT5645_ADC_OSR_128			(0x0) +#define RT5645_ADC_OSR_64			(0x1) +#define RT5645_ADC_OSR_32			(0x2) +#define RT5645_ADC_OSR_16			(0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5645_DAC_L_OSR_MASK			(0x3 << 14) +#define RT5645_DAC_L_OSR_SFT			14 +#define RT5645_DAC_L_OSR_128			(0x0 << 14) +#define RT5645_DAC_L_OSR_64			(0x1 << 14) +#define RT5645_DAC_L_OSR_32			(0x2 << 14) +#define RT5645_DAC_L_OSR_16			(0x3 << 14) +#define RT5645_ADC_R_OSR_MASK			(0x3 << 12) +#define RT5645_ADC_R_OSR_SFT			12 +#define RT5645_ADC_R_OSR_128			(0x0 << 12) +#define RT5645_ADC_R_OSR_64			(0x1 << 12) +#define RT5645_ADC_R_OSR_32			(0x2 << 12) +#define RT5645_ADC_R_OSR_16			(0x3 << 12) +#define RT5645_DAHPF_EN				(0x1 << 11) +#define RT5645_DAHPF_EN_SFT			11 +#define RT5645_ADHPF_EN				(0x1 << 10) +#define RT5645_ADHPF_EN_SFT			10 + +/* Digital Microphone Control (0x75) */ +#define RT5645_DMIC_1_EN_MASK			(0x1 << 15) +#define RT5645_DMIC_1_EN_SFT			15 +#define RT5645_DMIC_1_DIS			(0x0 << 15) +#define RT5645_DMIC_1_EN			(0x1 << 15) +#define RT5645_DMIC_2_EN_MASK			(0x1 << 14) +#define RT5645_DMIC_2_EN_SFT			14 +#define RT5645_DMIC_2_DIS			(0x0 << 14) +#define RT5645_DMIC_2_EN			(0x1 << 14) +#define RT5645_DMIC_1L_LH_MASK			(0x1 << 13) +#define RT5645_DMIC_1L_LH_SFT			13 +#define RT5645_DMIC_1L_LH_FALLING		(0x0 << 13) +#define RT5645_DMIC_1L_LH_RISING		(0x1 << 13) +#define RT5645_DMIC_1R_LH_MASK			(0x1 << 12) +#define RT5645_DMIC_1R_LH_SFT			12 +#define RT5645_DMIC_1R_LH_FALLING		(0x0 << 12) +#define RT5645_DMIC_1R_LH_RISING		(0x1 << 12) +#define RT5645_DMIC_2_DP_MASK			(0x3 << 10) +#define RT5645_DMIC_2_DP_SFT			10 +#define RT5645_DMIC_2_DP_GPIO6			(0x0 << 10) +#define RT5645_DMIC_2_DP_GPIO10			(0x1 << 10) +#define RT5645_DMIC_2_DP_GPIO12			(0x2 << 10) +#define RT5645_DMIC_2_DP_IN2P			(0x3 << 10) +#define RT5645_DMIC_2L_LH_MASK			(0x1 << 9) +#define RT5645_DMIC_2L_LH_SFT			9 +#define RT5645_DMIC_2L_LH_FALLING		(0x0 << 9) +#define RT5645_DMIC_2L_LH_RISING		(0x1 << 9) +#define RT5645_DMIC_2R_LH_MASK			(0x1 << 8) +#define RT5645_DMIC_2R_LH_SFT			8 +#define RT5645_DMIC_2R_LH_FALLING		(0x0 << 8) +#define RT5645_DMIC_2R_LH_RISING		(0x1 << 8) +#define RT5645_DMIC_CLK_MASK			(0x7 << 5) +#define RT5645_DMIC_CLK_SFT			5 +#define RT5645_DMIC_3_EN_MASK			(0x1 << 4) +#define RT5645_DMIC_3_EN_SFT			4 +#define RT5645_DMIC_3_DIS			(0x0 << 4) +#define RT5645_DMIC_3_EN			(0x1 << 4) +#define RT5645_DMIC_1_DP_MASK			(0x3 << 0) +#define RT5645_DMIC_1_DP_SFT			0 +#define RT5645_DMIC_1_DP_GPIO5			(0x0 << 0) +#define RT5645_DMIC_1_DP_IN2N			(0x1 << 0) +#define RT5645_DMIC_1_DP_GPIO11			(0x2 << 0) + +/* TDM Control 1 (0x77) */ +#define RT5645_IF1_ADC_IN_MASK			(0x3 << 8) +#define RT5645_IF1_ADC_IN_SFT			8 + +/* Global Clock Control (0x80) */ +#define RT5645_SCLK_SRC_MASK			(0x3 << 14) +#define RT5645_SCLK_SRC_SFT			14 +#define RT5645_SCLK_SRC_MCLK			(0x0 << 14) +#define RT5645_SCLK_SRC_PLL1			(0x1 << 14) +#define RT5645_SCLK_SRC_RCCLK			(0x2 << 14) /* 15MHz */ +#define RT5645_PLL1_SRC_MASK			(0x3 << 12) +#define RT5645_PLL1_SRC_SFT			12 +#define RT5645_PLL1_SRC_MCLK			(0x0 << 12) +#define RT5645_PLL1_SRC_BCLK1			(0x1 << 12) +#define RT5645_PLL1_SRC_BCLK2			(0x2 << 12) +#define RT5645_PLL1_SRC_BCLK3			(0x3 << 12) +#define RT5645_PLL1_PD_MASK			(0x1 << 3) +#define RT5645_PLL1_PD_SFT			3 +#define RT5645_PLL1_PD_1			(0x0 << 3) +#define RT5645_PLL1_PD_2			(0x1 << 3) + +#define RT5645_PLL_INP_MAX			40000000 +#define RT5645_PLL_INP_MIN			256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5645_PLL_N_MAX			0x1ff +#define RT5645_PLL_N_MASK			(RT5645_PLL_N_MAX << 7) +#define RT5645_PLL_N_SFT			7 +#define RT5645_PLL_K_MAX			0x1f +#define RT5645_PLL_K_MASK			(RT5645_PLL_K_MAX) +#define RT5645_PLL_K_SFT			0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5645_PLL_M_MAX			0xf +#define RT5645_PLL_M_MASK			(RT5645_PLL_M_MAX << 12) +#define RT5645_PLL_M_SFT			12 +#define RT5645_PLL_M_BP				(0x1 << 11) +#define RT5645_PLL_M_BP_SFT			11 + +/* ASRC Control 1 (0x83) */ +#define RT5645_STO_T_MASK			(0x1 << 15) +#define RT5645_STO_T_SFT			15 +#define RT5645_STO_T_SCLK			(0x0 << 15) +#define RT5645_STO_T_LRCK1			(0x1 << 15) +#define RT5645_M1_T_MASK			(0x1 << 14) +#define RT5645_M1_T_SFT				14 +#define RT5645_M1_T_I2S2			(0x0 << 14) +#define RT5645_M1_T_I2S2_D3			(0x1 << 14) +#define RT5645_I2S2_F_MASK			(0x1 << 12) +#define RT5645_I2S2_F_SFT			12 +#define RT5645_I2S2_F_I2S2_D2			(0x0 << 12) +#define RT5645_I2S2_F_I2S1_TCLK			(0x1 << 12) +#define RT5645_DMIC_1_M_MASK			(0x1 << 9) +#define RT5645_DMIC_1_M_SFT			9 +#define RT5645_DMIC_1_M_NOR			(0x0 << 9) +#define RT5645_DMIC_1_M_ASYN			(0x1 << 9) +#define RT5645_DMIC_2_M_MASK			(0x1 << 8) +#define RT5645_DMIC_2_M_SFT			8 +#define RT5645_DMIC_2_M_NOR			(0x0 << 8) +#define RT5645_DMIC_2_M_ASYN			(0x1 << 8) + +/* ASRC Control 2 (0x84) */ +#define RT5645_MDA_L_M_MASK			(0x1 << 15) +#define RT5645_MDA_L_M_SFT			15 +#define RT5645_MDA_L_M_NOR			(0x0 << 15) +#define RT5645_MDA_L_M_ASYN			(0x1 << 15) +#define RT5645_MDA_R_M_MASK			(0x1 << 14) +#define RT5645_MDA_R_M_SFT			14 +#define RT5645_MDA_R_M_NOR			(0x0 << 14) +#define RT5645_MDA_R_M_ASYN			(0x1 << 14) +#define RT5645_MAD_L_M_MASK			(0x1 << 13) +#define RT5645_MAD_L_M_SFT			13 +#define RT5645_MAD_L_M_NOR			(0x0 << 13) +#define RT5645_MAD_L_M_ASYN			(0x1 << 13) +#define RT5645_MAD_R_M_MASK			(0x1 << 12) +#define RT5645_MAD_R_M_SFT			12 +#define RT5645_MAD_R_M_NOR			(0x0 << 12) +#define RT5645_MAD_R_M_ASYN			(0x1 << 12) +#define RT5645_ADC_M_MASK			(0x1 << 11) +#define RT5645_ADC_M_SFT			11 +#define RT5645_ADC_M_NOR			(0x0 << 11) +#define RT5645_ADC_M_ASYN			(0x1 << 11) +#define RT5645_STO_DAC_M_MASK			(0x1 << 5) +#define RT5645_STO_DAC_M_SFT			5 +#define RT5645_STO_DAC_M_NOR			(0x0 << 5) +#define RT5645_STO_DAC_M_ASYN			(0x1 << 5) +#define RT5645_I2S1_R_D_MASK			(0x1 << 4) +#define RT5645_I2S1_R_D_SFT			4 +#define RT5645_I2S1_R_D_DIS			(0x0 << 4) +#define RT5645_I2S1_R_D_EN			(0x1 << 4) +#define RT5645_I2S2_R_D_MASK			(0x1 << 3) +#define RT5645_I2S2_R_D_SFT			3 +#define RT5645_I2S2_R_D_DIS			(0x0 << 3) +#define RT5645_I2S2_R_D_EN			(0x1 << 3) +#define RT5645_PRE_SCLK_MASK			(0x3) +#define RT5645_PRE_SCLK_SFT			0 +#define RT5645_PRE_SCLK_512			(0x0) +#define RT5645_PRE_SCLK_1024			(0x1) +#define RT5645_PRE_SCLK_2048			(0x2) + +/* ASRC Control 3 (0x85) */ +#define RT5645_I2S1_RATE_MASK			(0xf << 12) +#define RT5645_I2S1_RATE_SFT			12 +#define RT5645_I2S2_RATE_MASK			(0xf << 8) +#define RT5645_I2S2_RATE_SFT			8 + +/* ASRC Control 4 (0x89) */ +#define RT5645_I2S1_PD_MASK			(0x7 << 12) +#define RT5645_I2S1_PD_SFT			12 +#define RT5645_I2S2_PD_MASK			(0x7 << 8) +#define RT5645_I2S2_PD_SFT			8 + +/* HPOUT Over Current Detection (0x8b) */ +#define RT5645_HP_OVCD_MASK			(0x1 << 10) +#define RT5645_HP_OVCD_SFT			10 +#define RT5645_HP_OVCD_DIS			(0x0 << 10) +#define RT5645_HP_OVCD_EN			(0x1 << 10) +#define RT5645_HP_OC_TH_MASK			(0x3 << 8) +#define RT5645_HP_OC_TH_SFT			8 +#define RT5645_HP_OC_TH_90			(0x0 << 8) +#define RT5645_HP_OC_TH_105			(0x1 << 8) +#define RT5645_HP_OC_TH_120			(0x2 << 8) +#define RT5645_HP_OC_TH_135			(0x3 << 8) + +/* Class D Over Current Control (0x8c) */ +#define RT5645_CLSD_OC_MASK			(0x1 << 9) +#define RT5645_CLSD_OC_SFT			9 +#define RT5645_CLSD_OC_PU			(0x0 << 9) +#define RT5645_CLSD_OC_PD			(0x1 << 9) +#define RT5645_AUTO_PD_MASK			(0x1 << 8) +#define RT5645_AUTO_PD_SFT			8 +#define RT5645_AUTO_PD_DIS			(0x0 << 8) +#define RT5645_AUTO_PD_EN			(0x1 << 8) +#define RT5645_CLSD_OC_TH_MASK			(0x3f) +#define RT5645_CLSD_OC_TH_SFT			0 + +/* Class D Output Control (0x8d) */ +#define RT5645_CLSD_RATIO_MASK			(0xf << 12) +#define RT5645_CLSD_RATIO_SFT			12 +#define RT5645_CLSD_OM_MASK			(0x1 << 11) +#define RT5645_CLSD_OM_SFT			11 +#define RT5645_CLSD_OM_MONO			(0x0 << 11) +#define RT5645_CLSD_OM_STO			(0x1 << 11) +#define RT5645_CLSD_SCH_MASK			(0x1 << 10) +#define RT5645_CLSD_SCH_SFT			10 +#define RT5645_CLSD_SCH_L			(0x0 << 10) +#define RT5645_CLSD_SCH_S			(0x1 << 10) + +/* Depop Mode Control 1 (0x8e) */ +#define RT5645_SMT_TRIG_MASK			(0x1 << 15) +#define RT5645_SMT_TRIG_SFT			15 +#define RT5645_SMT_TRIG_DIS			(0x0 << 15) +#define RT5645_SMT_TRIG_EN			(0x1 << 15) +#define RT5645_HP_L_SMT_MASK			(0x1 << 9) +#define RT5645_HP_L_SMT_SFT			9 +#define RT5645_HP_L_SMT_DIS			(0x0 << 9) +#define RT5645_HP_L_SMT_EN			(0x1 << 9) +#define RT5645_HP_R_SMT_MASK			(0x1 << 8) +#define RT5645_HP_R_SMT_SFT			8 +#define RT5645_HP_R_SMT_DIS			(0x0 << 8) +#define RT5645_HP_R_SMT_EN			(0x1 << 8) +#define RT5645_HP_CD_PD_MASK			(0x1 << 7) +#define RT5645_HP_CD_PD_SFT			7 +#define RT5645_HP_CD_PD_DIS			(0x0 << 7) +#define RT5645_HP_CD_PD_EN			(0x1 << 7) +#define RT5645_RSTN_MASK			(0x1 << 6) +#define RT5645_RSTN_SFT				6 +#define RT5645_RSTN_DIS				(0x0 << 6) +#define RT5645_RSTN_EN				(0x1 << 6) +#define RT5645_RSTP_MASK			(0x1 << 5) +#define RT5645_RSTP_SFT				5 +#define RT5645_RSTP_DIS				(0x0 << 5) +#define RT5645_RSTP_EN				(0x1 << 5) +#define RT5645_HP_CO_MASK			(0x1 << 4) +#define RT5645_HP_CO_SFT			4 +#define RT5645_HP_CO_DIS			(0x0 << 4) +#define RT5645_HP_CO_EN				(0x1 << 4) +#define RT5645_HP_CP_MASK			(0x1 << 3) +#define RT5645_HP_CP_SFT			3 +#define RT5645_HP_CP_PD				(0x0 << 3) +#define RT5645_HP_CP_PU				(0x1 << 3) +#define RT5645_HP_SG_MASK			(0x1 << 2) +#define RT5645_HP_SG_SFT			2 +#define RT5645_HP_SG_DIS			(0x0 << 2) +#define RT5645_HP_SG_EN				(0x1 << 2) +#define RT5645_HP_DP_MASK			(0x1 << 1) +#define RT5645_HP_DP_SFT			1 +#define RT5645_HP_DP_PD				(0x0 << 1) +#define RT5645_HP_DP_PU				(0x1 << 1) +#define RT5645_HP_CB_MASK			(0x1) +#define RT5645_HP_CB_SFT			0 +#define RT5645_HP_CB_PD				(0x0) +#define RT5645_HP_CB_PU				(0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5645_DEPOP_MASK			(0x1 << 13) +#define RT5645_DEPOP_SFT			13 +#define RT5645_DEPOP_AUTO			(0x0 << 13) +#define RT5645_DEPOP_MAN			(0x1 << 13) +#define RT5645_RAMP_MASK			(0x1 << 12) +#define RT5645_RAMP_SFT				12 +#define RT5645_RAMP_DIS				(0x0 << 12) +#define RT5645_RAMP_EN				(0x1 << 12) +#define RT5645_BPS_MASK				(0x1 << 11) +#define RT5645_BPS_SFT				11 +#define RT5645_BPS_DIS				(0x0 << 11) +#define RT5645_BPS_EN				(0x1 << 11) +#define RT5645_FAST_UPDN_MASK			(0x1 << 10) +#define RT5645_FAST_UPDN_SFT			10 +#define RT5645_FAST_UPDN_DIS			(0x0 << 10) +#define RT5645_FAST_UPDN_EN			(0x1 << 10) +#define RT5645_MRES_MASK			(0x3 << 8) +#define RT5645_MRES_SFT				8 +#define RT5645_MRES_15MO			(0x0 << 8) +#define RT5645_MRES_25MO			(0x1 << 8) +#define RT5645_MRES_35MO			(0x2 << 8) +#define RT5645_MRES_45MO			(0x3 << 8) +#define RT5645_VLO_MASK				(0x1 << 7) +#define RT5645_VLO_SFT				7 +#define RT5645_VLO_3V				(0x0 << 7) +#define RT5645_VLO_32V				(0x1 << 7) +#define RT5645_DIG_DP_MASK			(0x1 << 6) +#define RT5645_DIG_DP_SFT			6 +#define RT5645_DIG_DP_DIS			(0x0 << 6) +#define RT5645_DIG_DP_EN			(0x1 << 6) +#define RT5645_DP_TH_MASK			(0x3 << 4) +#define RT5645_DP_TH_SFT			4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5645_CP_SYS_MASK			(0x7 << 12) +#define RT5645_CP_SYS_SFT			12 +#define RT5645_CP_FQ1_MASK			(0x7 << 8) +#define RT5645_CP_FQ1_SFT			8 +#define RT5645_CP_FQ2_MASK			(0x7 << 4) +#define RT5645_CP_FQ2_SFT			4 +#define RT5645_CP_FQ3_MASK			(0x7) +#define RT5645_CP_FQ3_SFT			0 +#define RT5645_CP_FQ_1_5_KHZ			0 +#define RT5645_CP_FQ_3_KHZ			1 +#define RT5645_CP_FQ_6_KHZ			2 +#define RT5645_CP_FQ_12_KHZ			3 +#define RT5645_CP_FQ_24_KHZ			4 +#define RT5645_CP_FQ_48_KHZ			5 +#define RT5645_CP_FQ_96_KHZ			6 +#define RT5645_CP_FQ_192_KHZ			7 + +/* PV detection and SPK gain control (0x92) */ +#define RT5645_PVDD_DET_MASK			(0x1 << 15) +#define RT5645_PVDD_DET_SFT			15 +#define RT5645_PVDD_DET_DIS			(0x0 << 15) +#define RT5645_PVDD_DET_EN			(0x1 << 15) +#define RT5645_SPK_AG_MASK			(0x1 << 14) +#define RT5645_SPK_AG_SFT			14 +#define RT5645_SPK_AG_DIS			(0x0 << 14) +#define RT5645_SPK_AG_EN			(0x1 << 14) + +/* Micbias Control (0x93) */ +#define RT5645_MIC1_BS_MASK			(0x1 << 15) +#define RT5645_MIC1_BS_SFT			15 +#define RT5645_MIC1_BS_9AV			(0x0 << 15) +#define RT5645_MIC1_BS_75AV			(0x1 << 15) +#define RT5645_MIC2_BS_MASK			(0x1 << 14) +#define RT5645_MIC2_BS_SFT			14 +#define RT5645_MIC2_BS_9AV			(0x0 << 14) +#define RT5645_MIC2_BS_75AV			(0x1 << 14) +#define RT5645_MIC1_CLK_MASK			(0x1 << 13) +#define RT5645_MIC1_CLK_SFT			13 +#define RT5645_MIC1_CLK_DIS			(0x0 << 13) +#define RT5645_MIC1_CLK_EN			(0x1 << 13) +#define RT5645_MIC2_CLK_MASK			(0x1 << 12) +#define RT5645_MIC2_CLK_SFT			12 +#define RT5645_MIC2_CLK_DIS			(0x0 << 12) +#define RT5645_MIC2_CLK_EN			(0x1 << 12) +#define RT5645_MIC1_OVCD_MASK			(0x1 << 11) +#define RT5645_MIC1_OVCD_SFT			11 +#define RT5645_MIC1_OVCD_DIS			(0x0 << 11) +#define RT5645_MIC1_OVCD_EN			(0x1 << 11) +#define RT5645_MIC1_OVTH_MASK			(0x3 << 9) +#define RT5645_MIC1_OVTH_SFT			9 +#define RT5645_MIC1_OVTH_600UA			(0x0 << 9) +#define RT5645_MIC1_OVTH_1500UA			(0x1 << 9) +#define RT5645_MIC1_OVTH_2000UA			(0x2 << 9) +#define RT5645_MIC2_OVCD_MASK			(0x1 << 8) +#define RT5645_MIC2_OVCD_SFT			8 +#define RT5645_MIC2_OVCD_DIS			(0x0 << 8) +#define RT5645_MIC2_OVCD_EN			(0x1 << 8) +#define RT5645_MIC2_OVTH_MASK			(0x3 << 6) +#define RT5645_MIC2_OVTH_SFT			6 +#define RT5645_MIC2_OVTH_600UA			(0x0 << 6) +#define RT5645_MIC2_OVTH_1500UA			(0x1 << 6) +#define RT5645_MIC2_OVTH_2000UA			(0x2 << 6) +#define RT5645_PWR_MB_MASK			(0x1 << 5) +#define RT5645_PWR_MB_SFT			5 +#define RT5645_PWR_MB_PD			(0x0 << 5) +#define RT5645_PWR_MB_PU			(0x1 << 5) +#define RT5645_PWR_CLK25M_MASK			(0x1 << 4) +#define RT5645_PWR_CLK25M_SFT			4 +#define RT5645_PWR_CLK25M_PD			(0x0 << 4) +#define RT5645_PWR_CLK25M_PU			(0x1 << 4) + +/* VAD Control 4 (0x9d) */ +#define RT5645_VAD_SEL_MASK			(0x3 << 8) +#define RT5645_VAD_SEL_SFT			8 + +/* EQ Control 1 (0xb0) */ +#define RT5645_EQ_SRC_MASK			(0x1 << 15) +#define RT5645_EQ_SRC_SFT			15 +#define RT5645_EQ_SRC_DAC			(0x0 << 15) +#define RT5645_EQ_SRC_ADC			(0x1 << 15) +#define RT5645_EQ_UPD				(0x1 << 14) +#define RT5645_EQ_UPD_BIT			14 +#define RT5645_EQ_CD_MASK			(0x1 << 13) +#define RT5645_EQ_CD_SFT			13 +#define RT5645_EQ_CD_DIS			(0x0 << 13) +#define RT5645_EQ_CD_EN				(0x1 << 13) +#define RT5645_EQ_DITH_MASK			(0x3 << 8) +#define RT5645_EQ_DITH_SFT			8 +#define RT5645_EQ_DITH_NOR			(0x0 << 8) +#define RT5645_EQ_DITH_LSB			(0x1 << 8) +#define RT5645_EQ_DITH_LSB_1			(0x2 << 8) +#define RT5645_EQ_DITH_LSB_2			(0x3 << 8) + +/* EQ Control 2 (0xb1) */ +#define RT5645_EQ_HPF1_M_MASK			(0x1 << 8) +#define RT5645_EQ_HPF1_M_SFT			8 +#define RT5645_EQ_HPF1_M_HI			(0x0 << 8) +#define RT5645_EQ_HPF1_M_1ST			(0x1 << 8) +#define RT5645_EQ_LPF1_M_MASK			(0x1 << 7) +#define RT5645_EQ_LPF1_M_SFT			7 +#define RT5645_EQ_LPF1_M_LO			(0x0 << 7) +#define RT5645_EQ_LPF1_M_1ST			(0x1 << 7) +#define RT5645_EQ_HPF2_MASK			(0x1 << 6) +#define RT5645_EQ_HPF2_SFT			6 +#define RT5645_EQ_HPF2_DIS			(0x0 << 6) +#define RT5645_EQ_HPF2_EN			(0x1 << 6) +#define RT5645_EQ_HPF1_MASK			(0x1 << 5) +#define RT5645_EQ_HPF1_SFT			5 +#define RT5645_EQ_HPF1_DIS			(0x0 << 5) +#define RT5645_EQ_HPF1_EN			(0x1 << 5) +#define RT5645_EQ_BPF4_MASK			(0x1 << 4) +#define RT5645_EQ_BPF4_SFT			4 +#define RT5645_EQ_BPF4_DIS			(0x0 << 4) +#define RT5645_EQ_BPF4_EN			(0x1 << 4) +#define RT5645_EQ_BPF3_MASK			(0x1 << 3) +#define RT5645_EQ_BPF3_SFT			3 +#define RT5645_EQ_BPF3_DIS			(0x0 << 3) +#define RT5645_EQ_BPF3_EN			(0x1 << 3) +#define RT5645_EQ_BPF2_MASK			(0x1 << 2) +#define RT5645_EQ_BPF2_SFT			2 +#define RT5645_EQ_BPF2_DIS			(0x0 << 2) +#define RT5645_EQ_BPF2_EN			(0x1 << 2) +#define RT5645_EQ_BPF1_MASK			(0x1 << 1) +#define RT5645_EQ_BPF1_SFT			1 +#define RT5645_EQ_BPF1_DIS			(0x0 << 1) +#define RT5645_EQ_BPF1_EN			(0x1 << 1) +#define RT5645_EQ_LPF_MASK			(0x1) +#define RT5645_EQ_LPF_SFT			0 +#define RT5645_EQ_LPF_DIS			(0x0) +#define RT5645_EQ_LPF_EN			(0x1) +#define RT5645_EQ_CTRL_MASK			(0x7f) + +/* Memory Test (0xb2) */ +#define RT5645_MT_MASK				(0x1 << 15) +#define RT5645_MT_SFT				15 +#define RT5645_MT_DIS				(0x0 << 15) +#define RT5645_MT_EN				(0x1 << 15) + +/* DRC/AGC Control 1 (0xb4) */ +#define RT5645_DRC_AGC_P_MASK			(0x1 << 15) +#define RT5645_DRC_AGC_P_SFT			15 +#define RT5645_DRC_AGC_P_DAC			(0x0 << 15) +#define RT5645_DRC_AGC_P_ADC			(0x1 << 15) +#define RT5645_DRC_AGC_MASK			(0x1 << 14) +#define RT5645_DRC_AGC_SFT			14 +#define RT5645_DRC_AGC_DIS			(0x0 << 14) +#define RT5645_DRC_AGC_EN			(0x1 << 14) +#define RT5645_DRC_AGC_UPD			(0x1 << 13) +#define RT5645_DRC_AGC_UPD_BIT			13 +#define RT5645_DRC_AGC_AR_MASK			(0x1f << 8) +#define RT5645_DRC_AGC_AR_SFT			8 +#define RT5645_DRC_AGC_R_MASK			(0x7 << 5) +#define RT5645_DRC_AGC_R_SFT			5 +#define RT5645_DRC_AGC_R_48K			(0x1 << 5) +#define RT5645_DRC_AGC_R_96K			(0x2 << 5) +#define RT5645_DRC_AGC_R_192K			(0x3 << 5) +#define RT5645_DRC_AGC_R_441K			(0x5 << 5) +#define RT5645_DRC_AGC_R_882K			(0x6 << 5) +#define RT5645_DRC_AGC_R_1764K			(0x7 << 5) +#define RT5645_DRC_AGC_RC_MASK			(0x1f) +#define RT5645_DRC_AGC_RC_SFT			0 + +/* DRC/AGC Control 2 (0xb5) */ +#define RT5645_DRC_AGC_POB_MASK			(0x3f << 8) +#define RT5645_DRC_AGC_POB_SFT			8 +#define RT5645_DRC_AGC_CP_MASK			(0x1 << 7) +#define RT5645_DRC_AGC_CP_SFT			7 +#define RT5645_DRC_AGC_CP_DIS			(0x0 << 7) +#define RT5645_DRC_AGC_CP_EN			(0x1 << 7) +#define RT5645_DRC_AGC_CPR_MASK			(0x3 << 5) +#define RT5645_DRC_AGC_CPR_SFT			5 +#define RT5645_DRC_AGC_CPR_1_1			(0x0 << 5) +#define RT5645_DRC_AGC_CPR_1_2			(0x1 << 5) +#define RT5645_DRC_AGC_CPR_1_3			(0x2 << 5) +#define RT5645_DRC_AGC_CPR_1_4			(0x3 << 5) +#define RT5645_DRC_AGC_PRB_MASK			(0x1f) +#define RT5645_DRC_AGC_PRB_SFT			0 + +/* DRC/AGC Control 3 (0xb6) */ +#define RT5645_DRC_AGC_NGB_MASK			(0xf << 12) +#define RT5645_DRC_AGC_NGB_SFT			12 +#define RT5645_DRC_AGC_TAR_MASK			(0x1f << 7) +#define RT5645_DRC_AGC_TAR_SFT			7 +#define RT5645_DRC_AGC_NG_MASK			(0x1 << 6) +#define RT5645_DRC_AGC_NG_SFT			6 +#define RT5645_DRC_AGC_NG_DIS			(0x0 << 6) +#define RT5645_DRC_AGC_NG_EN			(0x1 << 6) +#define RT5645_DRC_AGC_NGH_MASK			(0x1 << 5) +#define RT5645_DRC_AGC_NGH_SFT			5 +#define RT5645_DRC_AGC_NGH_DIS			(0x0 << 5) +#define RT5645_DRC_AGC_NGH_EN			(0x1 << 5) +#define RT5645_DRC_AGC_NGT_MASK			(0x1f) +#define RT5645_DRC_AGC_NGT_SFT			0 + +/* ANC Control 1 (0xb8) */ +#define RT5645_ANC_M_MASK			(0x1 << 15) +#define RT5645_ANC_M_SFT			15 +#define RT5645_ANC_M_NOR			(0x0 << 15) +#define RT5645_ANC_M_REV			(0x1 << 15) +#define RT5645_ANC_MASK				(0x1 << 14) +#define RT5645_ANC_SFT				14 +#define RT5645_ANC_DIS				(0x0 << 14) +#define RT5645_ANC_EN				(0x1 << 14) +#define RT5645_ANC_MD_MASK			(0x3 << 12) +#define RT5645_ANC_MD_SFT			12 +#define RT5645_ANC_MD_DIS			(0x0 << 12) +#define RT5645_ANC_MD_67MS			(0x1 << 12) +#define RT5645_ANC_MD_267MS			(0x2 << 12) +#define RT5645_ANC_MD_1067MS			(0x3 << 12) +#define RT5645_ANC_SN_MASK			(0x1 << 11) +#define RT5645_ANC_SN_SFT			11 +#define RT5645_ANC_SN_DIS			(0x0 << 11) +#define RT5645_ANC_SN_EN			(0x1 << 11) +#define RT5645_ANC_CLK_MASK			(0x1 << 10) +#define RT5645_ANC_CLK_SFT			10 +#define RT5645_ANC_CLK_ANC			(0x0 << 10) +#define RT5645_ANC_CLK_REG			(0x1 << 10) +#define RT5645_ANC_ZCD_MASK			(0x3 << 8) +#define RT5645_ANC_ZCD_SFT			8 +#define RT5645_ANC_ZCD_DIS			(0x0 << 8) +#define RT5645_ANC_ZCD_T1			(0x1 << 8) +#define RT5645_ANC_ZCD_T2			(0x2 << 8) +#define RT5645_ANC_ZCD_WT			(0x3 << 8) +#define RT5645_ANC_CS_MASK			(0x1 << 7) +#define RT5645_ANC_CS_SFT			7 +#define RT5645_ANC_CS_DIS			(0x0 << 7) +#define RT5645_ANC_CS_EN			(0x1 << 7) +#define RT5645_ANC_SW_MASK			(0x1 << 6) +#define RT5645_ANC_SW_SFT			6 +#define RT5645_ANC_SW_NOR			(0x0 << 6) +#define RT5645_ANC_SW_AUTO			(0x1 << 6) +#define RT5645_ANC_CO_L_MASK			(0x3f) +#define RT5645_ANC_CO_L_SFT			0 + +/* ANC Control 2 (0xb6) */ +#define RT5645_ANC_FG_R_MASK			(0xf << 12) +#define RT5645_ANC_FG_R_SFT			12 +#define RT5645_ANC_FG_L_MASK			(0xf << 8) +#define RT5645_ANC_FG_L_SFT			8 +#define RT5645_ANC_CG_R_MASK			(0xf << 4) +#define RT5645_ANC_CG_R_SFT			4 +#define RT5645_ANC_CG_L_MASK			(0xf) +#define RT5645_ANC_CG_L_SFT			0 + +/* ANC Control 3 (0xb6) */ +#define RT5645_ANC_CD_MASK			(0x1 << 6) +#define RT5645_ANC_CD_SFT			6 +#define RT5645_ANC_CD_BOTH			(0x0 << 6) +#define RT5645_ANC_CD_IND			(0x1 << 6) +#define RT5645_ANC_CO_R_MASK			(0x3f) +#define RT5645_ANC_CO_R_SFT			0 + +/* Jack Detect Control (0xbb) */ +#define RT5645_JD_MASK				(0x7 << 13) +#define RT5645_JD_SFT				13 +#define RT5645_JD_DIS				(0x0 << 13) +#define RT5645_JD_GPIO1				(0x1 << 13) +#define RT5645_JD_JD1_IN4P			(0x2 << 13) +#define RT5645_JD_JD2_IN4N			(0x3 << 13) +#define RT5645_JD_GPIO2				(0x4 << 13) +#define RT5645_JD_GPIO3				(0x5 << 13) +#define RT5645_JD_GPIO4				(0x6 << 13) +#define RT5645_JD_HP_MASK			(0x1 << 11) +#define RT5645_JD_HP_SFT			11 +#define RT5645_JD_HP_DIS			(0x0 << 11) +#define RT5645_JD_HP_EN				(0x1 << 11) +#define RT5645_JD_HP_TRG_MASK			(0x1 << 10) +#define RT5645_JD_HP_TRG_SFT			10 +#define RT5645_JD_HP_TRG_LO			(0x0 << 10) +#define RT5645_JD_HP_TRG_HI			(0x1 << 10) +#define RT5645_JD_SPL_MASK			(0x1 << 9) +#define RT5645_JD_SPL_SFT			9 +#define RT5645_JD_SPL_DIS			(0x0 << 9) +#define RT5645_JD_SPL_EN			(0x1 << 9) +#define RT5645_JD_SPL_TRG_MASK			(0x1 << 8) +#define RT5645_JD_SPL_TRG_SFT			8 +#define RT5645_JD_SPL_TRG_LO			(0x0 << 8) +#define RT5645_JD_SPL_TRG_HI			(0x1 << 8) +#define RT5645_JD_SPR_MASK			(0x1 << 7) +#define RT5645_JD_SPR_SFT			7 +#define RT5645_JD_SPR_DIS			(0x0 << 7) +#define RT5645_JD_SPR_EN			(0x1 << 7) +#define RT5645_JD_SPR_TRG_MASK			(0x1 << 6) +#define RT5645_JD_SPR_TRG_SFT			6 +#define RT5645_JD_SPR_TRG_LO			(0x0 << 6) +#define RT5645_JD_SPR_TRG_HI			(0x1 << 6) +#define RT5645_JD_MO_MASK			(0x1 << 5) +#define RT5645_JD_MO_SFT			5 +#define RT5645_JD_MO_DIS			(0x0 << 5) +#define RT5645_JD_MO_EN				(0x1 << 5) +#define RT5645_JD_MO_TRG_MASK			(0x1 << 4) +#define RT5645_JD_MO_TRG_SFT			4 +#define RT5645_JD_MO_TRG_LO			(0x0 << 4) +#define RT5645_JD_MO_TRG_HI			(0x1 << 4) +#define RT5645_JD_LO_MASK			(0x1 << 3) +#define RT5645_JD_LO_SFT			3 +#define RT5645_JD_LO_DIS			(0x0 << 3) +#define RT5645_JD_LO_EN				(0x1 << 3) +#define RT5645_JD_LO_TRG_MASK			(0x1 << 2) +#define RT5645_JD_LO_TRG_SFT			2 +#define RT5645_JD_LO_TRG_LO			(0x0 << 2) +#define RT5645_JD_LO_TRG_HI			(0x1 << 2) +#define RT5645_JD1_IN4P_MASK			(0x1 << 1) +#define RT5645_JD1_IN4P_SFT			1 +#define RT5645_JD1_IN4P_DIS			(0x0 << 1) +#define RT5645_JD1_IN4P_EN			(0x1 << 1) +#define RT5645_JD2_IN4N_MASK			(0x1) +#define RT5645_JD2_IN4N_SFT			0 +#define RT5645_JD2_IN4N_DIS			(0x0) +#define RT5645_JD2_IN4N_EN			(0x1) + +/* Jack detect for ANC (0xbc) */ +#define RT5645_ANC_DET_MASK			(0x3 << 4) +#define RT5645_ANC_DET_SFT			4 +#define RT5645_ANC_DET_DIS			(0x0 << 4) +#define RT5645_ANC_DET_MB1			(0x1 << 4) +#define RT5645_ANC_DET_MB2			(0x2 << 4) +#define RT5645_ANC_DET_JD			(0x3 << 4) +#define RT5645_AD_TRG_MASK			(0x1 << 3) +#define RT5645_AD_TRG_SFT			3 +#define RT5645_AD_TRG_LO			(0x0 << 3) +#define RT5645_AD_TRG_HI			(0x1 << 3) +#define RT5645_ANCM_DET_MASK			(0x3 << 4) +#define RT5645_ANCM_DET_SFT			4 +#define RT5645_ANCM_DET_DIS			(0x0 << 4) +#define RT5645_ANCM_DET_MB1			(0x1 << 4) +#define RT5645_ANCM_DET_MB2			(0x2 << 4) +#define RT5645_ANCM_DET_JD			(0x3 << 4) +#define RT5645_AMD_TRG_MASK			(0x1 << 3) +#define RT5645_AMD_TRG_SFT			3 +#define RT5645_AMD_TRG_LO			(0x0 << 3) +#define RT5645_AMD_TRG_HI			(0x1 << 3) + +/* IRQ Control 1 (0xbd) */ +#define RT5645_IRQ_JD_MASK			(0x1 << 15) +#define RT5645_IRQ_JD_SFT			15 +#define RT5645_IRQ_JD_BP			(0x0 << 15) +#define RT5645_IRQ_JD_NOR			(0x1 << 15) +#define RT5645_IRQ_OT_MASK			(0x1 << 14) +#define RT5645_IRQ_OT_SFT			14 +#define RT5645_IRQ_OT_BP			(0x0 << 14) +#define RT5645_IRQ_OT_NOR			(0x1 << 14) +#define RT5645_JD_STKY_MASK			(0x1 << 13) +#define RT5645_JD_STKY_SFT			13 +#define RT5645_JD_STKY_DIS			(0x0 << 13) +#define RT5645_JD_STKY_EN			(0x1 << 13) +#define RT5645_OT_STKY_MASK			(0x1 << 12) +#define RT5645_OT_STKY_SFT			12 +#define RT5645_OT_STKY_DIS			(0x0 << 12) +#define RT5645_OT_STKY_EN			(0x1 << 12) +#define RT5645_JD_P_MASK			(0x1 << 11) +#define RT5645_JD_P_SFT				11 +#define RT5645_JD_P_NOR				(0x0 << 11) +#define RT5645_JD_P_INV				(0x1 << 11) +#define RT5645_OT_P_MASK			(0x1 << 10) +#define RT5645_OT_P_SFT				10 +#define RT5645_OT_P_NOR				(0x0 << 10) +#define RT5645_OT_P_INV				(0x1 << 10) + +/* IRQ Control 2 (0xbe) */ +#define RT5645_IRQ_MB1_OC_MASK			(0x1 << 15) +#define RT5645_IRQ_MB1_OC_SFT			15 +#define RT5645_IRQ_MB1_OC_BP			(0x0 << 15) +#define RT5645_IRQ_MB1_OC_NOR			(0x1 << 15) +#define RT5645_IRQ_MB2_OC_MASK			(0x1 << 14) +#define RT5645_IRQ_MB2_OC_SFT			14 +#define RT5645_IRQ_MB2_OC_BP			(0x0 << 14) +#define RT5645_IRQ_MB2_OC_NOR			(0x1 << 14) +#define RT5645_MB1_OC_STKY_MASK			(0x1 << 13) +#define RT5645_MB1_OC_STKY_SFT			13 +#define RT5645_MB1_OC_STKY_DIS			(0x0 << 13) +#define RT5645_MB1_OC_STKY_EN			(0x1 << 13) +#define RT5645_MB2_OC_STKY_MASK			(0x1 << 12) +#define RT5645_MB2_OC_STKY_SFT			12 +#define RT5645_MB2_OC_STKY_DIS			(0x0 << 12) +#define RT5645_MB2_OC_STKY_EN			(0x1 << 12) +#define RT5645_MB1_OC_P_MASK			(0x1 << 7) +#define RT5645_MB1_OC_P_SFT			7 +#define RT5645_MB1_OC_P_NOR			(0x0 << 7) +#define RT5645_MB1_OC_P_INV			(0x1 << 7) +#define RT5645_MB2_OC_P_MASK			(0x1 << 6) +#define RT5645_MB2_OC_P_SFT			6 +#define RT5645_MB2_OC_P_NOR			(0x0 << 6) +#define RT5645_MB2_OC_P_INV			(0x1 << 6) +#define RT5645_MB1_OC_CLR			(0x1 << 3) +#define RT5645_MB1_OC_CLR_SFT			3 +#define RT5645_MB2_OC_CLR			(0x1 << 2) +#define RT5645_MB2_OC_CLR_SFT			2 + +/* GPIO Control 1 (0xc0) */ +#define RT5645_GP1_PIN_MASK			(0x1 << 15) +#define RT5645_GP1_PIN_SFT			15 +#define RT5645_GP1_PIN_GPIO1			(0x0 << 15) +#define RT5645_GP1_PIN_IRQ			(0x1 << 15) +#define RT5645_GP2_PIN_MASK			(0x1 << 14) +#define RT5645_GP2_PIN_SFT			14 +#define RT5645_GP2_PIN_GPIO2			(0x0 << 14) +#define RT5645_GP2_PIN_DMIC1_SCL		(0x1 << 14) +#define RT5645_GP3_PIN_MASK			(0x3 << 12) +#define RT5645_GP3_PIN_SFT			12 +#define RT5645_GP3_PIN_GPIO3			(0x0 << 12) +#define RT5645_GP3_PIN_DMIC1_SDA		(0x1 << 12) +#define RT5645_GP3_PIN_IRQ			(0x2 << 12) +#define RT5645_GP4_PIN_MASK			(0x1 << 11) +#define RT5645_GP4_PIN_SFT			11 +#define RT5645_GP4_PIN_GPIO4			(0x0 << 11) +#define RT5645_GP4_PIN_DMIC2_SDA		(0x1 << 11) +#define RT5645_DP_SIG_MASK			(0x1 << 10) +#define RT5645_DP_SIG_SFT			10 +#define RT5645_DP_SIG_TEST			(0x0 << 10) +#define RT5645_DP_SIG_AP			(0x1 << 10) +#define RT5645_GPIO_M_MASK			(0x1 << 9) +#define RT5645_GPIO_M_SFT			9 +#define RT5645_GPIO_M_FLT			(0x0 << 9) +#define RT5645_GPIO_M_PH			(0x1 << 9) +#define RT5645_I2S2_SEL				(0x1 << 8) +#define RT5645_I2S2_SEL_SFT			8 +#define RT5645_GP5_PIN_MASK			(0x1 << 7) +#define RT5645_GP5_PIN_SFT			7 +#define RT5645_GP5_PIN_GPIO5			(0x0 << 7) +#define RT5645_GP5_PIN_DMIC1_SDA		(0x1 << 7) +#define RT5645_GP6_PIN_MASK			(0x1 << 6) +#define RT5645_GP6_PIN_SFT			6 +#define RT5645_GP6_PIN_GPIO6			(0x0 << 6) +#define RT5645_GP6_PIN_DMIC2_SDA		(0x1 << 6) +#define RT5645_GP8_PIN_MASK			(0x1 << 3) +#define RT5645_GP8_PIN_SFT			3 +#define RT5645_GP8_PIN_GPIO8			(0x0 << 3) +#define RT5645_GP8_PIN_DMIC2_SDA		(0x1 << 3) +#define RT5645_GP12_PIN_MASK			(0x1 << 2) +#define RT5645_GP12_PIN_SFT			2 +#define RT5645_GP12_PIN_GPIO12			(0x0 << 2) +#define RT5645_GP12_PIN_DMIC2_SDA		(0x1 << 2) +#define RT5645_GP11_PIN_MASK			(0x1 << 1) +#define RT5645_GP11_PIN_SFT			1 +#define RT5645_GP11_PIN_GPIO11			(0x0 << 1) +#define RT5645_GP11_PIN_DMIC1_SDA		(0x1 << 1) +#define RT5645_GP10_PIN_MASK			(0x1) +#define RT5645_GP10_PIN_SFT			0 +#define RT5645_GP10_PIN_GPIO10			(0x0) +#define RT5645_GP10_PIN_DMIC2_SDA		(0x1) + +/* GPIO Control 3 (0xc2) */ +#define RT5645_GP4_PF_MASK			(0x1 << 11) +#define RT5645_GP4_PF_SFT			11 +#define RT5645_GP4_PF_IN			(0x0 << 11) +#define RT5645_GP4_PF_OUT			(0x1 << 11) +#define RT5645_GP4_OUT_MASK			(0x1 << 10) +#define RT5645_GP4_OUT_SFT			10 +#define RT5645_GP4_OUT_LO			(0x0 << 10) +#define RT5645_GP4_OUT_HI			(0x1 << 10) +#define RT5645_GP4_P_MASK			(0x1 << 9) +#define RT5645_GP4_P_SFT			9 +#define RT5645_GP4_P_NOR			(0x0 << 9) +#define RT5645_GP4_P_INV			(0x1 << 9) +#define RT5645_GP3_PF_MASK			(0x1 << 8) +#define RT5645_GP3_PF_SFT			8 +#define RT5645_GP3_PF_IN			(0x0 << 8) +#define RT5645_GP3_PF_OUT			(0x1 << 8) +#define RT5645_GP3_OUT_MASK			(0x1 << 7) +#define RT5645_GP3_OUT_SFT			7 +#define RT5645_GP3_OUT_LO			(0x0 << 7) +#define RT5645_GP3_OUT_HI			(0x1 << 7) +#define RT5645_GP3_P_MASK			(0x1 << 6) +#define RT5645_GP3_P_SFT			6 +#define RT5645_GP3_P_NOR			(0x0 << 6) +#define RT5645_GP3_P_INV			(0x1 << 6) +#define RT5645_GP2_PF_MASK			(0x1 << 5) +#define RT5645_GP2_PF_SFT			5 +#define RT5645_GP2_PF_IN			(0x0 << 5) +#define RT5645_GP2_PF_OUT			(0x1 << 5) +#define RT5645_GP2_OUT_MASK			(0x1 << 4) +#define RT5645_GP2_OUT_SFT			4 +#define RT5645_GP2_OUT_LO			(0x0 << 4) +#define RT5645_GP2_OUT_HI			(0x1 << 4) +#define RT5645_GP2_P_MASK			(0x1 << 3) +#define RT5645_GP2_P_SFT			3 +#define RT5645_GP2_P_NOR			(0x0 << 3) +#define RT5645_GP2_P_INV			(0x1 << 3) +#define RT5645_GP1_PF_MASK			(0x1 << 2) +#define RT5645_GP1_PF_SFT			2 +#define RT5645_GP1_PF_IN			(0x0 << 2) +#define RT5645_GP1_PF_OUT			(0x1 << 2) +#define RT5645_GP1_OUT_MASK			(0x1 << 1) +#define RT5645_GP1_OUT_SFT			1 +#define RT5645_GP1_OUT_LO			(0x0 << 1) +#define RT5645_GP1_OUT_HI			(0x1 << 1) +#define RT5645_GP1_P_MASK			(0x1) +#define RT5645_GP1_P_SFT			0 +#define RT5645_GP1_P_NOR			(0x0) +#define RT5645_GP1_P_INV			(0x1) + +/* Programmable Register Array Control 1 (0xc8) */ +#define RT5645_REG_SEQ_MASK			(0xf << 12) +#define RT5645_REG_SEQ_SFT			12 +#define RT5645_SEQ1_ST_MASK			(0x1 << 11) /*RO*/ +#define RT5645_SEQ1_ST_SFT			11 +#define RT5645_SEQ1_ST_RUN			(0x0 << 11) +#define RT5645_SEQ1_ST_FIN			(0x1 << 11) +#define RT5645_SEQ2_ST_MASK			(0x1 << 10) /*RO*/ +#define RT5645_SEQ2_ST_SFT			10 +#define RT5645_SEQ2_ST_RUN			(0x0 << 10) +#define RT5645_SEQ2_ST_FIN			(0x1 << 10) +#define RT5645_REG_LV_MASK			(0x1 << 9) +#define RT5645_REG_LV_SFT			9 +#define RT5645_REG_LV_MX			(0x0 << 9) +#define RT5645_REG_LV_PR			(0x1 << 9) +#define RT5645_SEQ_2_PT_MASK			(0x1 << 8) +#define RT5645_SEQ_2_PT_BIT			8 +#define RT5645_REG_IDX_MASK			(0xff) +#define RT5645_REG_IDX_SFT			0 + +/* Programmable Register Array Control 2 (0xc9) */ +#define RT5645_REG_DAT_MASK			(0xffff) +#define RT5645_REG_DAT_SFT			0 + +/* Programmable Register Array Control 3 (0xca) */ +#define RT5645_SEQ_DLY_MASK			(0xff << 8) +#define RT5645_SEQ_DLY_SFT			8 +#define RT5645_PROG_MASK			(0x1 << 7) +#define RT5645_PROG_SFT				7 +#define RT5645_PROG_DIS				(0x0 << 7) +#define RT5645_PROG_EN				(0x1 << 7) +#define RT5645_SEQ1_PT_RUN			(0x1 << 6) +#define RT5645_SEQ1_PT_RUN_BIT			6 +#define RT5645_SEQ2_PT_RUN			(0x1 << 5) +#define RT5645_SEQ2_PT_RUN_BIT			5 + +/* Programmable Register Array Control 4 (0xcb) */ +#define RT5645_SEQ1_START_MASK			(0xf << 8) +#define RT5645_SEQ1_START_SFT			8 +#define RT5645_SEQ1_END_MASK			(0xf) +#define RT5645_SEQ1_END_SFT			0 + +/* Programmable Register Array Control 5 (0xcc) */ +#define RT5645_SEQ2_START_MASK			(0xf << 8) +#define RT5645_SEQ2_START_SFT			8 +#define RT5645_SEQ2_END_MASK			(0xf) +#define RT5645_SEQ2_END_SFT			0 + +/* Scramble Function (0xcd) */ +#define RT5645_SCB_KEY_MASK			(0xff) +#define RT5645_SCB_KEY_SFT			0 + +/* Scramble Control (0xce) */ +#define RT5645_SCB_SWAP_MASK			(0x1 << 15) +#define RT5645_SCB_SWAP_SFT			15 +#define RT5645_SCB_SWAP_DIS			(0x0 << 15) +#define RT5645_SCB_SWAP_EN			(0x1 << 15) +#define RT5645_SCB_MASK				(0x1 << 14) +#define RT5645_SCB_SFT				14 +#define RT5645_SCB_DIS				(0x0 << 14) +#define RT5645_SCB_EN				(0x1 << 14) + +/* Baseback Control (0xcf) */ +#define RT5645_BB_MASK				(0x1 << 15) +#define RT5645_BB_SFT				15 +#define RT5645_BB_DIS				(0x0 << 15) +#define RT5645_BB_EN				(0x1 << 15) +#define RT5645_BB_CT_MASK			(0x7 << 12) +#define RT5645_BB_CT_SFT			12 +#define RT5645_BB_CT_A				(0x0 << 12) +#define RT5645_BB_CT_B				(0x1 << 12) +#define RT5645_BB_CT_C				(0x2 << 12) +#define RT5645_BB_CT_D				(0x3 << 12) +#define RT5645_M_BB_L_MASK			(0x1 << 9) +#define RT5645_M_BB_L_SFT			9 +#define RT5645_M_BB_R_MASK			(0x1 << 8) +#define RT5645_M_BB_R_SFT			8 +#define RT5645_M_BB_HPF_L_MASK			(0x1 << 7) +#define RT5645_M_BB_HPF_L_SFT			7 +#define RT5645_M_BB_HPF_R_MASK			(0x1 << 6) +#define RT5645_M_BB_HPF_R_SFT			6 +#define RT5645_G_BB_BST_MASK			(0x3f) +#define RT5645_G_BB_BST_SFT			0 + +/* MP3 Plus Control 1 (0xd0) */ +#define RT5645_M_MP3_L_MASK			(0x1 << 15) +#define RT5645_M_MP3_L_SFT			15 +#define RT5645_M_MP3_R_MASK			(0x1 << 14) +#define RT5645_M_MP3_R_SFT			14 +#define RT5645_M_MP3_MASK			(0x1 << 13) +#define RT5645_M_MP3_SFT			13 +#define RT5645_M_MP3_DIS			(0x0 << 13) +#define RT5645_M_MP3_EN				(0x1 << 13) +#define RT5645_EG_MP3_MASK			(0x1f << 8) +#define RT5645_EG_MP3_SFT			8 +#define RT5645_MP3_HLP_MASK			(0x1 << 7) +#define RT5645_MP3_HLP_SFT			7 +#define RT5645_MP3_HLP_DIS			(0x0 << 7) +#define RT5645_MP3_HLP_EN			(0x1 << 7) +#define RT5645_M_MP3_ORG_L_MASK			(0x1 << 6) +#define RT5645_M_MP3_ORG_L_SFT			6 +#define RT5645_M_MP3_ORG_R_MASK			(0x1 << 5) +#define RT5645_M_MP3_ORG_R_SFT			5 + +/* MP3 Plus Control 2 (0xd1) */ +#define RT5645_MP3_WT_MASK			(0x1 << 13) +#define RT5645_MP3_WT_SFT			13 +#define RT5645_MP3_WT_1_4			(0x0 << 13) +#define RT5645_MP3_WT_1_2			(0x1 << 13) +#define RT5645_OG_MP3_MASK			(0x1f << 8) +#define RT5645_OG_MP3_SFT			8 +#define RT5645_HG_MP3_MASK			(0x3f) +#define RT5645_HG_MP3_SFT			0 + +/* 3D HP Control 1 (0xd2) */ +#define RT5645_3D_CF_MASK			(0x1 << 15) +#define RT5645_3D_CF_SFT			15 +#define RT5645_3D_CF_DIS			(0x0 << 15) +#define RT5645_3D_CF_EN				(0x1 << 15) +#define RT5645_3D_HP_MASK			(0x1 << 14) +#define RT5645_3D_HP_SFT			14 +#define RT5645_3D_HP_DIS			(0x0 << 14) +#define RT5645_3D_HP_EN				(0x1 << 14) +#define RT5645_3D_BT_MASK			(0x1 << 13) +#define RT5645_3D_BT_SFT			13 +#define RT5645_3D_BT_DIS			(0x0 << 13) +#define RT5645_3D_BT_EN				(0x1 << 13) +#define RT5645_3D_1F_MIX_MASK			(0x3 << 11) +#define RT5645_3D_1F_MIX_SFT			11 +#define RT5645_3D_HP_M_MASK			(0x1 << 10) +#define RT5645_3D_HP_M_SFT			10 +#define RT5645_3D_HP_M_SUR			(0x0 << 10) +#define RT5645_3D_HP_M_FRO			(0x1 << 10) +#define RT5645_M_3D_HRTF_MASK			(0x1 << 9) +#define RT5645_M_3D_HRTF_SFT			9 +#define RT5645_M_3D_D2H_MASK			(0x1 << 8) +#define RT5645_M_3D_D2H_SFT			8 +#define RT5645_M_3D_D2R_MASK			(0x1 << 7) +#define RT5645_M_3D_D2R_SFT			7 +#define RT5645_M_3D_REVB_MASK			(0x1 << 6) +#define RT5645_M_3D_REVB_SFT			6 + +/* Adjustable high pass filter control 1 (0xd3) */ +#define RT5645_2ND_HPF_MASK			(0x1 << 15) +#define RT5645_2ND_HPF_SFT			15 +#define RT5645_2ND_HPF_DIS			(0x0 << 15) +#define RT5645_2ND_HPF_EN			(0x1 << 15) +#define RT5645_HPF_CF_L_MASK			(0x7 << 12) +#define RT5645_HPF_CF_L_SFT			12 +#define RT5645_1ST_HPF_MASK			(0x1 << 11) +#define RT5645_1ST_HPF_SFT			11 +#define RT5645_1ST_HPF_DIS			(0x0 << 11) +#define RT5645_1ST_HPF_EN			(0x1 << 11) +#define RT5645_HPF_CF_R_MASK			(0x7 << 8) +#define RT5645_HPF_CF_R_SFT			8 +#define RT5645_ZD_T_MASK			(0x3 << 6) +#define RT5645_ZD_T_SFT				6 +#define RT5645_ZD_F_MASK			(0x3 << 4) +#define RT5645_ZD_F_SFT				4 +#define RT5645_ZD_F_IM				(0x0 << 4) +#define RT5645_ZD_F_ZC_IM			(0x1 << 4) +#define RT5645_ZD_F_ZC_IOD			(0x2 << 4) +#define RT5645_ZD_F_UN				(0x3 << 4) + +/* HP calibration control and Amp detection (0xd6) */ +#define RT5645_SI_DAC_MASK			(0x1 << 11) +#define RT5645_SI_DAC_SFT			11 +#define RT5645_SI_DAC_AUTO			(0x0 << 11) +#define RT5645_SI_DAC_TEST			(0x1 << 11) +#define RT5645_DC_CAL_M_MASK			(0x1 << 10) +#define RT5645_DC_CAL_M_SFT			10 +#define RT5645_DC_CAL_M_CAL			(0x0 << 10) +#define RT5645_DC_CAL_M_NOR			(0x1 << 10) +#define RT5645_DC_CAL_MASK			(0x1 << 9) +#define RT5645_DC_CAL_SFT			9 +#define RT5645_DC_CAL_DIS			(0x0 << 9) +#define RT5645_DC_CAL_EN			(0x1 << 9) +#define RT5645_HPD_RCV_MASK			(0x7 << 6) +#define RT5645_HPD_RCV_SFT			6 +#define RT5645_HPD_PS_MASK			(0x1 << 5) +#define RT5645_HPD_PS_SFT			5 +#define RT5645_HPD_PS_DIS			(0x0 << 5) +#define RT5645_HPD_PS_EN			(0x1 << 5) +#define RT5645_CAL_M_MASK			(0x1 << 4) +#define RT5645_CAL_M_SFT			4 +#define RT5645_CAL_M_DEP			(0x0 << 4) +#define RT5645_CAL_M_CAL			(0x1 << 4) +#define RT5645_CAL_MASK				(0x1 << 3) +#define RT5645_CAL_SFT				3 +#define RT5645_CAL_DIS				(0x0 << 3) +#define RT5645_CAL_EN				(0x1 << 3) +#define RT5645_CAL_TEST_MASK			(0x1 << 2) +#define RT5645_CAL_TEST_SFT			2 +#define RT5645_CAL_TEST_DIS			(0x0 << 2) +#define RT5645_CAL_TEST_EN			(0x1 << 2) +#define RT5645_CAL_P_MASK			(0x3) +#define RT5645_CAL_P_SFT			0 +#define RT5645_CAL_P_NONE			(0x0) +#define RT5645_CAL_P_CAL			(0x1) +#define RT5645_CAL_P_DAC_CAL			(0x2) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5645_SV_MASK				(0x1 << 15) +#define RT5645_SV_SFT				15 +#define RT5645_SV_DIS				(0x0 << 15) +#define RT5645_SV_EN				(0x1 << 15) +#define RT5645_SPO_SV_MASK			(0x1 << 14) +#define RT5645_SPO_SV_SFT			14 +#define RT5645_SPO_SV_DIS			(0x0 << 14) +#define RT5645_SPO_SV_EN			(0x1 << 14) +#define RT5645_OUT_SV_MASK			(0x1 << 13) +#define RT5645_OUT_SV_SFT			13 +#define RT5645_OUT_SV_DIS			(0x0 << 13) +#define RT5645_OUT_SV_EN			(0x1 << 13) +#define RT5645_HP_SV_MASK			(0x1 << 12) +#define RT5645_HP_SV_SFT			12 +#define RT5645_HP_SV_DIS			(0x0 << 12) +#define RT5645_HP_SV_EN				(0x1 << 12) +#define RT5645_ZCD_DIG_MASK			(0x1 << 11) +#define RT5645_ZCD_DIG_SFT			11 +#define RT5645_ZCD_DIG_DIS			(0x0 << 11) +#define RT5645_ZCD_DIG_EN			(0x1 << 11) +#define RT5645_ZCD_MASK				(0x1 << 10) +#define RT5645_ZCD_SFT				10 +#define RT5645_ZCD_PD				(0x0 << 10) +#define RT5645_ZCD_PU				(0x1 << 10) +#define RT5645_M_ZCD_MASK			(0x3f << 4) +#define RT5645_M_ZCD_SFT			4 +#define RT5645_M_ZCD_RM_L			(0x1 << 9) +#define RT5645_M_ZCD_RM_R			(0x1 << 8) +#define RT5645_M_ZCD_SM_L			(0x1 << 7) +#define RT5645_M_ZCD_SM_R			(0x1 << 6) +#define RT5645_M_ZCD_OM_L			(0x1 << 5) +#define RT5645_M_ZCD_OM_R			(0x1 << 4) +#define RT5645_SV_DLY_MASK			(0xf) +#define RT5645_SV_DLY_SFT			0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5645_ZCD_HP_MASK			(0x1 << 15) +#define RT5645_ZCD_HP_SFT			15 +#define RT5645_ZCD_HP_DIS			(0x0 << 15) +#define RT5645_ZCD_HP_EN			(0x1 << 15) + + +/* Codec Private Register definition */ +/* 3D Speaker Control (0x63) */ +#define RT5645_3D_SPK_MASK			(0x1 << 15) +#define RT5645_3D_SPK_SFT			15 +#define RT5645_3D_SPK_DIS			(0x0 << 15) +#define RT5645_3D_SPK_EN			(0x1 << 15) +#define RT5645_3D_SPK_M_MASK			(0x3 << 13) +#define RT5645_3D_SPK_M_SFT			13 +#define RT5645_3D_SPK_CG_MASK			(0x1f << 8) +#define RT5645_3D_SPK_CG_SFT			8 +#define RT5645_3D_SPK_SG_MASK			(0x1f) +#define RT5645_3D_SPK_SG_SFT			0 + +/* Wind Noise Detection Control 1 (0x6c) */ +#define RT5645_WND_MASK				(0x1 << 15) +#define RT5645_WND_SFT				15 +#define RT5645_WND_DIS				(0x0 << 15) +#define RT5645_WND_EN				(0x1 << 15) + +/* Wind Noise Detection Control 2 (0x6d) */ +#define RT5645_WND_FC_NW_MASK			(0x3f << 10) +#define RT5645_WND_FC_NW_SFT			10 +#define RT5645_WND_FC_WK_MASK			(0x3f << 4) +#define RT5645_WND_FC_WK_SFT			4 + +/* Wind Noise Detection Control 3 (0x6e) */ +#define RT5645_HPF_FC_MASK			(0x3f << 6) +#define RT5645_HPF_FC_SFT			6 +#define RT5645_WND_FC_ST_MASK			(0x3f) +#define RT5645_WND_FC_ST_SFT			0 + +/* Wind Noise Detection Control 4 (0x6f) */ +#define RT5645_WND_TH_LO_MASK			(0x3ff) +#define RT5645_WND_TH_LO_SFT			0 + +/* Wind Noise Detection Control 5 (0x70) */ +#define RT5645_WND_TH_HI_MASK			(0x3ff) +#define RT5645_WND_TH_HI_SFT			0 + +/* Wind Noise Detection Control 8 (0x73) */ +#define RT5645_WND_WIND_MASK			(0x1 << 13) /* Read-Only */ +#define RT5645_WND_WIND_SFT			13 +#define RT5645_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */ +#define RT5645_WND_STRONG_SFT			12 +enum { +	RT5645_NO_WIND, +	RT5645_BREEZE, +	RT5645_STORM, +}; + +/* Dipole Speaker Interface (0x75) */ +#define RT5645_DP_ATT_MASK			(0x3 << 14) +#define RT5645_DP_ATT_SFT			14 +#define RT5645_DP_SPK_MASK			(0x1 << 10) +#define RT5645_DP_SPK_SFT			10 +#define RT5645_DP_SPK_DIS			(0x0 << 10) +#define RT5645_DP_SPK_EN			(0x1 << 10) + +/* EQ Pre Volume Control (0xb3) */ +#define RT5645_EQ_PRE_VOL_MASK			(0xffff) +#define RT5645_EQ_PRE_VOL_SFT			0 + +/* EQ Post Volume Control (0xb4) */ +#define RT5645_EQ_PST_VOL_MASK			(0xffff) +#define RT5645_EQ_PST_VOL_SFT			0 + +/* Jack Detect Control 3 (0xf8) */ +#define RT5645_CMP_MIC_IN_DET_MASK		(0x7 << 12) +#define RT5645_JD_CBJ_EN			(0x1 << 7) +#define RT5645_JD_CBJ_POL			(0x1 << 6) +#define RT5645_JD_TRI_CBJ_SEL_MASK		(0x7 << 3) +#define RT5645_JD_TRI_CBJ_SEL_SFT		(3) +#define RT5645_JD_TRI_HPO_SEL_MASK		(0x7) +#define RT5645_JD_TRI_HPO_SEL_SFT		(0) +#define RT5645_JD_F_GPIO_JD1			(0x0) +#define RT5645_JD_F_JD1_1			(0x1) +#define RT5645_JD_F_JD1_2			(0x2) +#define RT5645_JD_F_JD2				(0x3) +#define RT5645_JD_F_JD3				(0x4) +#define RT5645_JD_F_GPIO_JD2			(0x5) +#define RT5645_JD_F_MX0B_12			(0x6) + +/* Digital Misc Control (0xfa) */ +#define RT5645_RST_DSP				(0x1 << 13) +#define RT5645_IF1_ADC1_IN1_SEL			(0x1 << 12) +#define RT5645_IF1_ADC1_IN1_SFT			12 +#define RT5645_IF1_ADC1_IN2_SEL			(0x1 << 11) +#define RT5645_IF1_ADC1_IN2_SFT			11 +#define RT5645_IF1_ADC2_IN1_SEL			(0x1 << 10) +#define RT5645_IF1_ADC2_IN1_SFT			10 +#define RT5645_DIG_GATE_CTRL			0x1 + +/* General Control2 (0xfb) */ +#define RT5645_RXDC_SRC_MASK			(0x1 << 7) +#define RT5645_RXDC_SRC_STO			(0x0 << 7) +#define RT5645_RXDC_SRC_MONO			(0x1 << 7) +#define RT5645_RXDC_SRC_SFT			(7) +#define RT5645_RXDP2_SEL_MASK			(0x1 << 3) +#define RT5645_RXDP2_SEL_IF2			(0x0 << 3) +#define RT5645_RXDP2_SEL_ADC			(0x1 << 3) +#define RT5645_RXDP2_SEL_SFT			(3) + + +/* Vendor ID (0xfd) */ +#define RT5645_VER_C				0x2 +#define RT5645_VER_D				0x3 + + +/* Volume Rescale */ +#define RT5645_VOL_RSCL_MAX 0x27 +#define RT5645_VOL_RSCL_RANGE 0x1F +/* Debug String Length */ +#define RT5645_REG_DISP_LEN 23 + + +/* System Clock Source */ +enum { +	RT5645_SCLK_S_MCLK, +	RT5645_SCLK_S_PLL1, +	RT5645_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { +	RT5645_PLL1_S_MCLK, +	RT5645_PLL1_S_BCLK1, +	RT5645_PLL1_S_BCLK2, +}; + +enum { +	RT5645_AIF1, +	RT5645_AIF2, +	RT5645_AIFS, +}; + +enum { +	RT5645_DMIC_DATA_IN2P, +	RT5645_DMIC_DATA_GPIO6, +	RT5645_DMIC_DATA_GPIO10, +	RT5645_DMIC_DATA_GPIO12, +}; + +enum { +	RT5645_DMIC_DATA_IN2N, +	RT5645_DMIC_DATA_GPIO5, +	RT5645_DMIC_DATA_GPIO11, +}; + +struct rt5645_priv { +	struct snd_soc_codec *codec; +	struct rt5645_platform_data pdata; +	struct regmap *regmap; + +	int sysclk; +	int sysclk_src; +	int lrck[RT5645_AIFS]; +	int bclk[RT5645_AIFS]; +	int master[RT5645_AIFS]; + +	int pll_src; +	int pll_in; +	int pll_out; +}; + +#endif /* __RT5645_H__ */ diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c new file mode 100644 index 00000000000..ea4b1c652a2 --- /dev/null +++ b/sound/soc/codecs/rt5651.c @@ -0,0 +1,1818 @@ +/* + * rt5651.c  --  RT5651 ALSA SoC audio codec driver + * + * Copyright 2014 Realtek Semiconductor Corp. + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rl6231.h" +#include "rt5651.h" + +#define RT5651_DEVICE_ID_VALUE 0x6281 + +#define RT5651_PR_RANGE_BASE (0xff + 1) +#define RT5651_PR_SPACING 0x100 + +#define RT5651_PR_BASE (RT5651_PR_RANGE_BASE + (0 * RT5651_PR_SPACING)) + +static const struct regmap_range_cfg rt5651_ranges[] = { +	{ .name = "PR", .range_min = RT5651_PR_BASE, +	  .range_max = RT5651_PR_BASE + 0xb4, +	  .selector_reg = RT5651_PRIV_INDEX, +	  .selector_mask = 0xff, +	  .selector_shift = 0x0, +	  .window_start = RT5651_PRIV_DATA, +	  .window_len = 0x1, }, +}; + +static struct reg_default init_list[] = { +	{RT5651_PR_BASE + 0x3d,	0x3e00}, +}; + +static const struct reg_default rt5651_reg[] = { +	{ 0x00, 0x0000 }, +	{ 0x02, 0xc8c8 }, +	{ 0x03, 0xc8c8 }, +	{ 0x05, 0x0000 }, +	{ 0x0d, 0x0000 }, +	{ 0x0e, 0x0000 }, +	{ 0x0f, 0x0808 }, +	{ 0x10, 0x0808 }, +	{ 0x19, 0xafaf }, +	{ 0x1a, 0xafaf }, +	{ 0x1b, 0x0c00 }, +	{ 0x1c, 0x2f2f }, +	{ 0x1d, 0x2f2f }, +	{ 0x1e, 0x0000 }, +	{ 0x27, 0x7860 }, +	{ 0x28, 0x7070 }, +	{ 0x29, 0x8080 }, +	{ 0x2a, 0x5252 }, +	{ 0x2b, 0x5454 }, +	{ 0x2f, 0x0000 }, +	{ 0x30, 0x5000 }, +	{ 0x3b, 0x0000 }, +	{ 0x3c, 0x006f }, +	{ 0x3d, 0x0000 }, +	{ 0x3e, 0x006f }, +	{ 0x45, 0x6000 }, +	{ 0x4d, 0x0000 }, +	{ 0x4e, 0x0000 }, +	{ 0x4f, 0x0279 }, +	{ 0x50, 0x0000 }, +	{ 0x51, 0x0000 }, +	{ 0x52, 0x0279 }, +	{ 0x53, 0xf000 }, +	{ 0x61, 0x0000 }, +	{ 0x62, 0x0000 }, +	{ 0x63, 0x00c0 }, +	{ 0x64, 0x0000 }, +	{ 0x65, 0x0000 }, +	{ 0x66, 0x0000 }, +	{ 0x70, 0x8000 }, +	{ 0x71, 0x8000 }, +	{ 0x73, 0x1104 }, +	{ 0x74, 0x0c00 }, +	{ 0x75, 0x1400 }, +	{ 0x77, 0x0c00 }, +	{ 0x78, 0x4000 }, +	{ 0x79, 0x0123 }, +	{ 0x80, 0x0000 }, +	{ 0x81, 0x0000 }, +	{ 0x82, 0x0000 }, +	{ 0x83, 0x0800 }, +	{ 0x84, 0x0000 }, +	{ 0x85, 0x0008 }, +	{ 0x89, 0x0000 }, +	{ 0x8e, 0x0004 }, +	{ 0x8f, 0x1100 }, +	{ 0x90, 0x0000 }, +	{ 0x93, 0x2000 }, +	{ 0x94, 0x0200 }, +	{ 0xb0, 0x2080 }, +	{ 0xb1, 0x0000 }, +	{ 0xb4, 0x2206 }, +	{ 0xb5, 0x1f00 }, +	{ 0xb6, 0x0000 }, +	{ 0xbb, 0x0000 }, +	{ 0xbc, 0x0000 }, +	{ 0xbd, 0x0000 }, +	{ 0xbe, 0x0000 }, +	{ 0xbf, 0x0000 }, +	{ 0xc0, 0x0400 }, +	{ 0xc1, 0x0000 }, +	{ 0xc2, 0x0000 }, +	{ 0xcf, 0x0013 }, +	{ 0xd0, 0x0680 }, +	{ 0xd1, 0x1c17 }, +	{ 0xd3, 0xb320 }, +	{ 0xd9, 0x0809 }, +	{ 0xfa, 0x0010 }, +	{ 0xfe, 0x10ec }, +	{ 0xff, 0x6281 }, +}; + +static bool rt5651_volatile_register(struct device *dev,  unsigned int reg) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) { +		if ((reg >= rt5651_ranges[i].window_start && +		     reg <= rt5651_ranges[i].window_start + +		     rt5651_ranges[i].window_len) || +		    (reg >= rt5651_ranges[i].range_min && +		     reg <= rt5651_ranges[i].range_max)) { +			return true; +		} +	} + +	switch (reg) { +	case RT5651_RESET: +	case RT5651_PRIV_DATA: +	case RT5651_EQ_CTRL1: +	case RT5651_ALC_1: +	case RT5651_IRQ_CTRL2: +	case RT5651_INT_IRQ_ST: +	case RT5651_PGM_REG_ARR1: +	case RT5651_PGM_REG_ARR3: +	case RT5651_VENDOR_ID: +	case RT5651_DEVICE_ID: +		return true; +	default: +		return false; +	} +} + +static bool rt5651_readable_register(struct device *dev, unsigned int reg) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) { +		if ((reg >= rt5651_ranges[i].window_start && +		     reg <= rt5651_ranges[i].window_start + +		     rt5651_ranges[i].window_len) || +		    (reg >= rt5651_ranges[i].range_min && +		     reg <= rt5651_ranges[i].range_max)) { +			return true; +		} +	} + +	switch (reg) { +	case RT5651_RESET: +	case RT5651_VERSION_ID: +	case RT5651_VENDOR_ID: +	case RT5651_DEVICE_ID: +	case RT5651_HP_VOL: +	case RT5651_LOUT_CTRL1: +	case RT5651_LOUT_CTRL2: +	case RT5651_IN1_IN2: +	case RT5651_IN3: +	case RT5651_INL1_INR1_VOL: +	case RT5651_INL2_INR2_VOL: +	case RT5651_DAC1_DIG_VOL: +	case RT5651_DAC2_DIG_VOL: +	case RT5651_DAC2_CTRL: +	case RT5651_ADC_DIG_VOL: +	case RT5651_ADC_DATA: +	case RT5651_ADC_BST_VOL: +	case RT5651_STO1_ADC_MIXER: +	case RT5651_STO2_ADC_MIXER: +	case RT5651_AD_DA_MIXER: +	case RT5651_STO_DAC_MIXER: +	case RT5651_DD_MIXER: +	case RT5651_DIG_INF_DATA: +	case RT5651_PDM_CTL: +	case RT5651_REC_L1_MIXER: +	case RT5651_REC_L2_MIXER: +	case RT5651_REC_R1_MIXER: +	case RT5651_REC_R2_MIXER: +	case RT5651_HPO_MIXER: +	case RT5651_OUT_L1_MIXER: +	case RT5651_OUT_L2_MIXER: +	case RT5651_OUT_L3_MIXER: +	case RT5651_OUT_R1_MIXER: +	case RT5651_OUT_R2_MIXER: +	case RT5651_OUT_R3_MIXER: +	case RT5651_LOUT_MIXER: +	case RT5651_PWR_DIG1: +	case RT5651_PWR_DIG2: +	case RT5651_PWR_ANLG1: +	case RT5651_PWR_ANLG2: +	case RT5651_PWR_MIXER: +	case RT5651_PWR_VOL: +	case RT5651_PRIV_INDEX: +	case RT5651_PRIV_DATA: +	case RT5651_I2S1_SDP: +	case RT5651_I2S2_SDP: +	case RT5651_ADDA_CLK1: +	case RT5651_ADDA_CLK2: +	case RT5651_DMIC: +	case RT5651_TDM_CTL_1: +	case RT5651_TDM_CTL_2: +	case RT5651_TDM_CTL_3: +	case RT5651_GLB_CLK: +	case RT5651_PLL_CTRL1: +	case RT5651_PLL_CTRL2: +	case RT5651_PLL_MODE_1: +	case RT5651_PLL_MODE_2: +	case RT5651_PLL_MODE_3: +	case RT5651_PLL_MODE_4: +	case RT5651_PLL_MODE_5: +	case RT5651_PLL_MODE_6: +	case RT5651_PLL_MODE_7: +	case RT5651_DEPOP_M1: +	case RT5651_DEPOP_M2: +	case RT5651_DEPOP_M3: +	case RT5651_CHARGE_PUMP: +	case RT5651_MICBIAS: +	case RT5651_A_JD_CTL1: +	case RT5651_EQ_CTRL1: +	case RT5651_EQ_CTRL2: +	case RT5651_ALC_1: +	case RT5651_ALC_2: +	case RT5651_ALC_3: +	case RT5651_JD_CTRL1: +	case RT5651_JD_CTRL2: +	case RT5651_IRQ_CTRL1: +	case RT5651_IRQ_CTRL2: +	case RT5651_INT_IRQ_ST: +	case RT5651_GPIO_CTRL1: +	case RT5651_GPIO_CTRL2: +	case RT5651_GPIO_CTRL3: +	case RT5651_PGM_REG_ARR1: +	case RT5651_PGM_REG_ARR2: +	case RT5651_PGM_REG_ARR3: +	case RT5651_PGM_REG_ARR4: +	case RT5651_PGM_REG_ARR5: +	case RT5651_SCB_FUNC: +	case RT5651_SCB_CTRL: +	case RT5651_BASE_BACK: +	case RT5651_MP3_PLUS1: +	case RT5651_MP3_PLUS2: +	case RT5651_ADJ_HPF_CTRL1: +	case RT5651_ADJ_HPF_CTRL2: +	case RT5651_HP_CALIB_AMP_DET: +	case RT5651_HP_CALIB2: +	case RT5651_SV_ZCD1: +	case RT5651_SV_ZCD2: +	case RT5651_D_MISC: +	case RT5651_DUMMY2: +	case RT5651_DUMMY3: +		return true; +	default: +		return false; +	} +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { +	TLV_DB_RANGE_HEAD(7), +	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), +	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), +	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), +	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), +	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), +	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), +	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +/* Interface data select */ +static const char * const rt5651_data_select[] = { +	"Normal", "Swap", "left copy to right", "right copy to left"}; + +static SOC_ENUM_SINGLE_DECL(rt5651_if2_dac_enum, RT5651_DIG_INF_DATA, +				RT5651_IF2_DAC_SEL_SFT, rt5651_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_enum, RT5651_DIG_INF_DATA, +				RT5651_IF2_ADC_SEL_SFT, rt5651_data_select); + +static const struct snd_kcontrol_new rt5651_snd_controls[] = { +	/* Headphone Output Volume */ +	SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL, +		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv), +	/* OUTPUT Control */ +	SOC_DOUBLE_TLV("OUT Playback Volume", RT5651_LOUT_CTRL1, +		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv), + +	/* DAC Digital Volume */ +	SOC_DOUBLE("DAC2 Playback Switch", RT5651_DAC2_CTRL, +		RT5651_M_DAC_L2_VOL_SFT, RT5651_M_DAC_R2_VOL_SFT, 1, 1), +	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5651_DAC1_DIG_VOL, +			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, +			175, 0, dac_vol_tlv), +	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL, +			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, +			175, 0, dac_vol_tlv), +	/* IN1/IN2 Control */ +	SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2, +		RT5651_BST_SFT1, 8, 0, bst_tlv), +	SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2, +		RT5651_BST_SFT2, 8, 0, bst_tlv), +	/* INL/INR Volume Control */ +	SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL, +			RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT, +			31, 1, in_vol_tlv), +	/* ADC Digital Volume Control */ +	SOC_DOUBLE("ADC Capture Switch", RT5651_ADC_DIG_VOL, +		RT5651_L_MUTE_SFT, RT5651_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE_TLV("ADC Capture Volume", RT5651_ADC_DIG_VOL, +			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, +			127, 0, adc_vol_tlv), +	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5651_ADC_DATA, +			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, +			127, 0, adc_vol_tlv), +	/* ADC Boost Volume Control */ +	SOC_DOUBLE_TLV("ADC Boost Gain", RT5651_ADC_BST_VOL, +			RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT, +			3, 0, adc_bst_tlv), + +	/* ASRC */ +	SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1, +		RT5651_STO1_T_SFT, 1, 0), +	SOC_SINGLE("IF2 ASRC Switch", RT5651_PLL_MODE_1, +		RT5651_STO2_T_SFT, 1, 0), +	SOC_SINGLE("DMIC ASRC Switch", RT5651_PLL_MODE_1, +		RT5651_DMIC_1_M_SFT, 1, 0), + +	SOC_ENUM("ADC IF2 Data Switch", rt5651_if2_adc_enum), +	SOC_ENUM("DAC IF2 Data Switch", rt5651_if2_dac_enum), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); +	int idx = -EINVAL; + +	idx = rl6231_calc_dmic_clk(rt5651->sysclk); + +	if (idx < 0) +		dev_err(codec->dev, "Failed to set DMIC clock\n"); +	else +		snd_soc_update_bits(codec, RT5651_DMIC, RT5651_DMIC_CLK_MASK, +					idx << RT5651_DMIC_CLK_SFT); + +	return idx; +} + +static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source, +			 struct snd_soc_dapm_widget *sink) +{ +	unsigned int val; + +	val = snd_soc_read(source->codec, RT5651_GLB_CLK); +	val &= RT5651_SCLK_SRC_MASK; +	if (val == RT5651_SCLK_SRC_PLL1) +		return 1; +	else +		return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER, +			RT5651_M_STO1_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER, +			RT5651_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto1_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER, +			RT5651_M_STO1_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER, +			RT5651_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto2_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER, +			RT5651_M_STO2_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER, +			RT5651_M_STO2_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto2_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER, +			RT5651_M_STO2_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER, +			RT5651_M_STO2_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dac_l_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER, +			RT5651_M_ADCMIX_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER, +			RT5651_M_IF1_DAC_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dac_r_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER, +			RT5651_M_ADCMIX_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER, +			RT5651_M_IF1_DAC_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER, +			RT5651_M_DAC_L1_MIXL_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_STO_DAC_MIXER, +			RT5651_M_DAC_L2_MIXL_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER, +			RT5651_M_DAC_R1_MIXL_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER, +			RT5651_M_DAC_R1_MIXR_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_STO_DAC_MIXER, +			RT5651_M_DAC_R2_MIXR_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER, +			RT5651_M_DAC_L1_MIXR_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dd_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_DD_MIXER, +			RT5651_M_STO_DD_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER, +			RT5651_M_STO_DD_L2_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER, +			RT5651_M_STO_DD_R2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dd_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_DD_MIXER, +			RT5651_M_STO_DD_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER, +			RT5651_M_STO_DD_R2_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER, +			RT5651_M_STO_DD_L2_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5651_rec_l_mix[] = { +	SOC_DAPM_SINGLE("INL1 Switch", RT5651_REC_L2_MIXER, +			RT5651_M_IN1_L_RM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_L2_MIXER, +			RT5651_M_BST3_RM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_L2_MIXER, +			RT5651_M_BST2_RM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_L2_MIXER, +			RT5651_M_BST1_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_rec_r_mix[] = { +	SOC_DAPM_SINGLE("INR1 Switch", RT5651_REC_R2_MIXER, +			RT5651_M_IN1_R_RM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_R2_MIXER, +			RT5651_M_BST3_RM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_R2_MIXER, +			RT5651_M_BST2_RM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_R2_MIXER, +			RT5651_M_BST1_RM_R_SFT, 1, 1), +}; + +/* Analog Output Mixer */ + +static const struct snd_kcontrol_new rt5651_out_l_mix[] = { +	SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_L3_MIXER, +			RT5651_M_BST1_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_L3_MIXER, +			RT5651_M_BST2_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL1 Switch", RT5651_OUT_L3_MIXER, +			RT5651_M_IN1_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("REC MIXL Switch", RT5651_OUT_L3_MIXER, +			RT5651_M_RM_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_OUT_L3_MIXER, +			RT5651_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_out_r_mix[] = { +	SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_R3_MIXER, +			RT5651_M_BST2_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_R3_MIXER, +			RT5651_M_BST1_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR1 Switch", RT5651_OUT_R3_MIXER, +			RT5651_M_IN1_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("REC MIXR Switch", RT5651_OUT_R3_MIXER, +			RT5651_M_RM_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_OUT_R3_MIXER, +			RT5651_M_DAC_R1_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_hpo_mix[] = { +	SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5651_HPO_MIXER, +			RT5651_M_DAC1_HM_SFT, 1, 1), +	SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5651_HPO_MIXER, +			RT5651_M_HPVOL_HM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_lout_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_LOUT_MIXER, +			RT5651_M_DAC_L1_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_LOUT_MIXER, +			RT5651_M_DAC_R1_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5651_LOUT_MIXER, +			RT5651_M_OV_L_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5651_LOUT_MIXER, +			RT5651_M_OV_R_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new outvol_l_control = +	SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1, +			RT5651_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_r_control = +	SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1, +			RT5651_VOL_R_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_l_mute_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1, +				    RT5651_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_mute_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1, +				    RT5651_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpovol_l_control = +	SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL, +			RT5651_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new hpovol_r_control = +	SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL, +			RT5651_VOL_R_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_l_mute_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL, +				    RT5651_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_r_mute_control = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL, +				    RT5651_R_MUTE_SFT, 1, 1); + +/* INL/R source */ +static const char * const rt5651_inl_src[] = {"IN2P", "HPOVOLLP"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_inl_enum, RT5651_INL1_INR1_VOL, +	RT5651_INL_SEL_SFT, rt5651_inl_src); + +static const struct snd_kcontrol_new rt5651_inl1_mux = +	SOC_DAPM_ENUM("INL1 source", rt5651_inl_enum); + +static const char * const rt5651_inr1_src[] = {"IN2N", "HPOVOLRP"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_inr1_enum, RT5651_INL1_INR1_VOL, +	RT5651_INR_SEL_SFT, rt5651_inr1_src); + +static const struct snd_kcontrol_new rt5651_inr1_mux = +	SOC_DAPM_ENUM("INR1 source", rt5651_inr1_enum); + +static const char * const rt5651_inl2_src[] = {"IN3P", "OUTVOLLP"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_inl2_enum, RT5651_INL2_INR2_VOL, +	RT5651_INL_SEL_SFT, rt5651_inl2_src); + +static const struct snd_kcontrol_new rt5651_inl2_mux = +	SOC_DAPM_ENUM("INL2 source", rt5651_inl2_enum); + +static const char * const rt5651_inr2_src[] = {"IN3N", "OUTVOLRP"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_inr2_enum, RT5651_INL2_INR2_VOL, +	RT5651_INR_SEL_SFT, rt5651_inr2_src); + +static const struct snd_kcontrol_new rt5651_inr2_mux = +	SOC_DAPM_ENUM("INR2 source", rt5651_inr2_enum); + + +/* Stereo ADC source */ +static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_stereo1_adc1_enum, RT5651_STO1_ADC_MIXER, +	RT5651_STO1_ADC_1_SRC_SFT, rt5651_stereo1_adc1_src); + +static const struct snd_kcontrol_new rt5651_sto1_adc_l1_mux = +	SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5651_stereo1_adc1_enum); + +static const struct snd_kcontrol_new rt5651_sto1_adc_r1_mux = +	SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5651_stereo1_adc1_enum); + +static const char * const rt5651_stereo1_adc2_src[] = {"DMIC", "DD MIX"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_stereo1_adc2_enum, RT5651_STO1_ADC_MIXER, +	RT5651_STO1_ADC_2_SRC_SFT, rt5651_stereo1_adc2_src); + +static const struct snd_kcontrol_new rt5651_sto1_adc_l2_mux = +	SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5651_stereo1_adc2_enum); + +static const struct snd_kcontrol_new rt5651_sto1_adc_r2_mux = +	SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5651_stereo1_adc2_enum); + +/* Mono ADC source */ +static const char * const rt5651_sto2_adc_l1_src[] = {"DD MIXL", "ADCL"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_sto2_adc_l1_enum, RT5651_STO1_ADC_MIXER, +	RT5651_STO2_ADC_L1_SRC_SFT, rt5651_sto2_adc_l1_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_l1_mux = +	SOC_DAPM_ENUM("Stereo2 ADC1 left source", rt5651_sto2_adc_l1_enum); + +static const char * const rt5651_sto2_adc_l2_src[] = {"DMIC L", "DD MIXL"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_sto2_adc_l2_enum, RT5651_STO1_ADC_MIXER, +	RT5651_STO2_ADC_L2_SRC_SFT, rt5651_sto2_adc_l2_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_l2_mux = +	SOC_DAPM_ENUM("Stereo2 ADC2 left source", rt5651_sto2_adc_l2_enum); + +static const char * const rt5651_sto2_adc_r1_src[] = {"DD MIXR", "ADCR"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_sto2_adc_r1_enum, RT5651_STO1_ADC_MIXER, +	RT5651_STO2_ADC_R1_SRC_SFT, rt5651_sto2_adc_r1_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_r1_mux = +	SOC_DAPM_ENUM("Stereo2 ADC1 right source", rt5651_sto2_adc_r1_enum); + +static const char * const rt5651_sto2_adc_r2_src[] = {"DMIC R", "DD MIXR"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_sto2_adc_r2_enum, RT5651_STO1_ADC_MIXER, +	RT5651_STO2_ADC_R2_SRC_SFT, rt5651_sto2_adc_r2_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_r2_mux = +	SOC_DAPM_ENUM("Stereo2 ADC2 right source", rt5651_sto2_adc_r2_enum); + +/* DAC2 channel source */ + +static const char * const rt5651_dac_src[] = {"IF1", "IF2"}; + +static SOC_ENUM_SINGLE_DECL(rt5651_dac_l2_enum, RT5651_DAC2_CTRL, +				RT5651_SEL_DAC_L2_SFT, rt5651_dac_src); + +static const struct snd_kcontrol_new rt5651_dac_l2_mux = +	SOC_DAPM_ENUM("DAC2 left channel source", rt5651_dac_l2_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5651_dac_r2_enum, RT5651_DAC2_CTRL, +	RT5651_SEL_DAC_R2_SFT, rt5651_dac_src); + +static const struct snd_kcontrol_new rt5651_dac_r2_mux = +	SOC_DAPM_ENUM("DAC2 right channel source", rt5651_dac_r2_enum); + +/* IF2_ADC channel source */ + +static const char * const rt5651_adc_src[] = {"IF1 ADC1", "IF1 ADC2"}; + +static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_src_enum, RT5651_DIG_INF_DATA, +				RT5651_IF2_ADC_SRC_SFT, rt5651_adc_src); + +static const struct snd_kcontrol_new rt5651_if2_adc_src_mux = +	SOC_DAPM_ENUM("IF2 ADC channel source", rt5651_if2_adc_src_enum); + +/* PDM select */ +static const char * const rt5651_pdm_sel[] = {"DD MIX", "Stereo DAC MIX"}; + +static SOC_ENUM_SINGLE_DECL( +	rt5651_pdm_l_sel_enum, RT5651_PDM_CTL, +	RT5651_PDM_L_SEL_SFT, rt5651_pdm_sel); + +static SOC_ENUM_SINGLE_DECL( +	rt5651_pdm_r_sel_enum, RT5651_PDM_CTL, +	RT5651_PDM_R_SEL_SFT, rt5651_pdm_sel); + +static const struct snd_kcontrol_new rt5651_pdm_l_mux = +	SOC_DAPM_ENUM("PDM L select", rt5651_pdm_l_sel_enum); + +static const struct snd_kcontrol_new rt5651_pdm_r_mux = +	SOC_DAPM_ENUM("PDM R select", rt5651_pdm_r_sel_enum); + +static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		/* depop parameters */ +		regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + +			RT5651_CHPUMP_INT_REG1, 0x0700, 0x0200); +		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2, +			RT5651_DEPOP_MASK, RT5651_DEPOP_MAN); +		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1, +			RT5651_HP_CP_MASK | RT5651_HP_SG_MASK | +			RT5651_HP_CB_MASK, RT5651_HP_CP_PU | +			RT5651_HP_SG_DIS | RT5651_HP_CB_PU); +		regmap_write(rt5651->regmap, RT5651_PR_BASE + +				RT5651_HP_DCC_INT1, 0x9f00); +		/* headphone amp power on */ +		regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1, +			RT5651_PWR_FV1 | RT5651_PWR_FV2, 0); +		regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1, +			RT5651_PWR_HA, +			RT5651_PWR_HA); +		usleep_range(10000, 15000); +		regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1, +			RT5651_PWR_FV1 | RT5651_PWR_FV2 , +			RT5651_PWR_FV1 | RT5651_PWR_FV2); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5651_hp_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		/* headphone unmute sequence */ +		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2, +			RT5651_DEPOP_MASK | RT5651_DIG_DP_MASK, +			RT5651_DEPOP_AUTO | RT5651_DIG_DP_EN); +		regmap_update_bits(rt5651->regmap, RT5651_CHARGE_PUMP, +			RT5651_PM_HP_MASK, RT5651_PM_HP_HV); + +		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M3, +			RT5651_CP_FQ1_MASK | RT5651_CP_FQ2_MASK | +			RT5651_CP_FQ3_MASK, +			(RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ1_SFT) | +			(RT5651_CP_FQ_12_KHZ << RT5651_CP_FQ2_SFT) | +			(RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ3_SFT)); + +		regmap_write(rt5651->regmap, RT5651_PR_BASE + +			RT5651_MAMP_INT_REG2, 0x1c00); +		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1, +			RT5651_HP_CP_MASK | RT5651_HP_SG_MASK, +			RT5651_HP_CP_PD | RT5651_HP_SG_EN); +		regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + +			RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400); +		rt5651->hp_mute = 0; +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		rt5651->hp_mute = 1; +		usleep_range(70000, 75000); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w, +			   struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		if (!rt5651->hp_mute) +			usleep_range(80000, 85000); + +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5651_bst1_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		snd_soc_update_bits(codec, RT5651_PWR_ANLG2, +			RT5651_PWR_BST1_OP2, RT5651_PWR_BST1_OP2); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, RT5651_PWR_ANLG2, +			RT5651_PWR_BST1_OP2, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5651_bst2_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		snd_soc_update_bits(codec, RT5651_PWR_ANLG2, +			RT5651_PWR_BST2_OP2, RT5651_PWR_BST2_OP2); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, RT5651_PWR_ANLG2, +			RT5651_PWR_BST2_OP2, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5651_bst3_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		snd_soc_update_bits(codec, RT5651_PWR_ANLG2, +			RT5651_PWR_BST3_OP2, RT5651_PWR_BST3_OP2); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, RT5651_PWR_ANLG2, +			RT5651_PWR_BST3_OP2, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { +	/* ASRC */ +	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5651_PLL_MODE_2, +			      15, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5651_PLL_MODE_2, +			      14, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("STO1 DAC ASRC", 1, RT5651_PLL_MODE_2, +			      13, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("STO2 DAC ASRC", 1, RT5651_PLL_MODE_2, +			      12, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("ADC ASRC", 1, RT5651_PLL_MODE_2, +			      11, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2, +			RT5651_PWR_PLL_BIT, 0, NULL, 0), +	/* Input Side */ +	/* micbias */ +	SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1, +			RT5651_PWR_LDO_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MICBIAS("micbias1", RT5651_PWR_ANLG2, +			RT5651_PWR_MB1_BIT, 0), +	/* Input Lines */ +	SND_SOC_DAPM_INPUT("MIC1"), +	SND_SOC_DAPM_INPUT("MIC2"), +	SND_SOC_DAPM_INPUT("MIC3"), + +	SND_SOC_DAPM_INPUT("IN1P"), +	SND_SOC_DAPM_INPUT("IN2P"), +	SND_SOC_DAPM_INPUT("IN2N"), +	SND_SOC_DAPM_INPUT("IN3P"), +	SND_SOC_DAPM_INPUT("DMIC L1"), +	SND_SOC_DAPM_INPUT("DMIC R1"), +	SND_SOC_DAPM_SUPPLY("DMIC CLK", RT5651_DMIC, RT5651_DMIC_1_EN_SFT, +			    0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU), +	/* Boost */ +	SND_SOC_DAPM_PGA_E("BST1", RT5651_PWR_ANLG2, +		RT5651_PWR_BST1_BIT, 0, NULL, 0, rt5651_bst1_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_PGA_E("BST2", RT5651_PWR_ANLG2, +		RT5651_PWR_BST2_BIT, 0, NULL, 0, rt5651_bst2_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_PGA_E("BST3", RT5651_PWR_ANLG2, +		RT5651_PWR_BST3_BIT, 0, NULL, 0, rt5651_bst3_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	/* Input Volume */ +	SND_SOC_DAPM_PGA("INL1 VOL", RT5651_PWR_VOL, +			 RT5651_PWR_IN1_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("INR1 VOL", RT5651_PWR_VOL, +			 RT5651_PWR_IN1_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("INL2 VOL", RT5651_PWR_VOL, +			 RT5651_PWR_IN2_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL, +			 RT5651_PWR_IN2_R_BIT, 0, NULL, 0), +	/* IN Mux */ +	SND_SOC_DAPM_MUX("INL1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl1_mux), +	SND_SOC_DAPM_MUX("INR1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr1_mux), +	SND_SOC_DAPM_MUX("INL2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl2_mux), +	SND_SOC_DAPM_MUX("INR2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr2_mux), +	/* REC Mixer */ +	SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0, +			   rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)), +	SND_SOC_DAPM_MIXER("RECMIXR", RT5651_PWR_MIXER, RT5651_PWR_RM_R_BIT, 0, +			   rt5651_rec_r_mix, ARRAY_SIZE(rt5651_rec_r_mix)), +	/* ADCs */ +	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_SUPPLY("ADC L Power", RT5651_PWR_DIG1, +			    RT5651_PWR_ADC_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC R Power", RT5651_PWR_DIG1, +			    RT5651_PWR_ADC_R_BIT, 0, NULL, 0), +	/* ADC Mux */ +	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto1_adc_l2_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto1_adc_r2_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto1_adc_l1_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto1_adc_r1_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto2_adc_l2_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto2_adc_l1_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto2_adc_r1_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0, +			 &rt5651_sto2_adc_r2_mux), +	/* ADC Mixer */ +	SND_SOC_DAPM_SUPPLY("Stereo1 Filter", RT5651_PWR_DIG2, +			    RT5651_PWR_ADC_STO1_F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Stereo2 Filter", RT5651_PWR_DIG2, +			    RT5651_PWR_ADC_STO2_F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, +			   rt5651_sto1_adc_l_mix, +			   ARRAY_SIZE(rt5651_sto1_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, +			   rt5651_sto1_adc_r_mix, +			   ARRAY_SIZE(rt5651_sto1_adc_r_mix)), +	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0, +			   rt5651_sto2_adc_l_mix, +			   ARRAY_SIZE(rt5651_sto2_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0, +			   rt5651_sto2_adc_r_mix, +			   ARRAY_SIZE(rt5651_sto2_adc_r_mix)), + +	/* Digital Interface */ +	SND_SOC_DAPM_SUPPLY("I2S1", RT5651_PWR_DIG1, +			    RT5651_PWR_I2S1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("I2S2", RT5651_PWR_DIG1, +			    RT5651_PWR_I2S2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MUX("IF2 ADC", SND_SOC_NOPM, 0, 0, +			 &rt5651_if2_adc_src_mux), + +	/* Digital Interface Select */ + +	SND_SOC_DAPM_MUX("PDM L Mux", RT5651_PDM_CTL, +			 RT5651_M_PDM_L_SFT, 1, &rt5651_pdm_l_mux), +	SND_SOC_DAPM_MUX("PDM R Mux", RT5651_PDM_CTL, +			 RT5651_M_PDM_R_SFT, 1, &rt5651_pdm_r_mux), +	/* Audio Interface */ +	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + +	/* Audio DSP */ +	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* Output Side */ +	/* DAC mixer before sound effect  */ +	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, +			   rt5651_dac_l_mix, ARRAY_SIZE(rt5651_dac_l_mix)), +	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, +			   rt5651_dac_r_mix, ARRAY_SIZE(rt5651_dac_r_mix)), + +	/* DAC2 channel Mux */ +	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_l2_mux), +	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_r2_mux), +	SND_SOC_DAPM_PGA("DAC L2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DAC R2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5651_PWR_DIG2, +			    RT5651_PWR_DAC_STO1_F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Stero2 DAC Power", RT5651_PWR_DIG2, +			    RT5651_PWR_DAC_STO2_F_BIT, 0, NULL, 0), +	/* DAC Mixer */ +	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, +			   rt5651_sto_dac_l_mix, +			   ARRAY_SIZE(rt5651_sto_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, +			   rt5651_sto_dac_r_mix, +			   ARRAY_SIZE(rt5651_sto_dac_r_mix)), +	SND_SOC_DAPM_MIXER("DD MIXL", SND_SOC_NOPM, 0, 0, +			   rt5651_dd_dac_l_mix, +			   ARRAY_SIZE(rt5651_dd_dac_l_mix)), +	SND_SOC_DAPM_MIXER("DD MIXR", SND_SOC_NOPM, 0, 0, +			   rt5651_dd_dac_r_mix, +			   ARRAY_SIZE(rt5651_dd_dac_r_mix)), + +	/* DACs */ +	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5651_PWR_DIG1, +			    RT5651_PWR_DAC_L1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5651_PWR_DIG1, +			    RT5651_PWR_DAC_R1_BIT, 0, NULL, 0), +	/* OUT Mixer */ +	SND_SOC_DAPM_MIXER("OUT MIXL", RT5651_PWR_MIXER, RT5651_PWR_OM_L_BIT, +			   0, rt5651_out_l_mix, ARRAY_SIZE(rt5651_out_l_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXR", RT5651_PWR_MIXER, RT5651_PWR_OM_R_BIT, +			   0, rt5651_out_r_mix, ARRAY_SIZE(rt5651_out_r_mix)), +	/* Ouput Volume */ +	SND_SOC_DAPM_SWITCH("OUTVOL L", RT5651_PWR_VOL, +			    RT5651_PWR_OV_L_BIT, 0, &outvol_l_control), +	SND_SOC_DAPM_SWITCH("OUTVOL R", RT5651_PWR_VOL, +			    RT5651_PWR_OV_R_BIT, 0, &outvol_r_control), +	SND_SOC_DAPM_SWITCH("HPOVOL L", RT5651_PWR_VOL, +			    RT5651_PWR_HV_L_BIT, 0, &hpovol_l_control), +	SND_SOC_DAPM_SWITCH("HPOVOL R", RT5651_PWR_VOL, +			    RT5651_PWR_HV_R_BIT, 0, &hpovol_r_control), +	SND_SOC_DAPM_PGA("INL1", RT5651_PWR_VOL, +			 RT5651_PWR_IN1_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("INR1", RT5651_PWR_VOL, +			 RT5651_PWR_IN1_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("INL2", RT5651_PWR_VOL, +			 RT5651_PWR_IN2_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("INR2", RT5651_PWR_VOL, +			 RT5651_PWR_IN2_R_BIT, 0, NULL, 0), +	/* HPO/LOUT/Mono Mixer */ +	SND_SOC_DAPM_MIXER("HPOL MIX", SND_SOC_NOPM, 0, 0, +			   rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)), +	SND_SOC_DAPM_MIXER("HPOR MIX", SND_SOC_NOPM, 0, 0, +			   rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)), +	SND_SOC_DAPM_SUPPLY("HP L Amp", RT5651_PWR_ANLG1, +			    RT5651_PWR_HP_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("HP R Amp", RT5651_PWR_ANLG1, +			    RT5651_PWR_HP_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("LOUT MIX", RT5651_PWR_ANLG1, RT5651_PWR_LM_BIT, 0, +			   rt5651_lout_mix, ARRAY_SIZE(rt5651_lout_mix)), + +	SND_SOC_DAPM_SUPPLY("Amp Power", RT5651_PWR_ANLG1, +			    RT5651_PWR_HA_BIT, 0, rt5651_amp_power_event, +			    SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5651_hp_event, +			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0, +			    &hpo_l_mute_control), +	SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0, +			    &hpo_r_mute_control), +	SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, +			    &lout_l_mute_control), +	SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, +			    &lout_r_mute_control), +	SND_SOC_DAPM_POST("HP Post", rt5651_hp_post_event), + +	/* Output Lines */ +	SND_SOC_DAPM_OUTPUT("HPOL"), +	SND_SOC_DAPM_OUTPUT("HPOR"), +	SND_SOC_DAPM_OUTPUT("LOUTL"), +	SND_SOC_DAPM_OUTPUT("LOUTR"), +	SND_SOC_DAPM_OUTPUT("PDML"), +	SND_SOC_DAPM_OUTPUT("PDMR"), +}; + +static const struct snd_soc_dapm_route rt5651_dapm_routes[] = { +	{"Stero1 DAC Power", NULL, "STO1 DAC ASRC"}, +	{"Stero2 DAC Power", NULL, "STO2 DAC ASRC"}, +	{"I2S1", NULL, "I2S1 ASRC"}, +	{"I2S2", NULL, "I2S2 ASRC"}, + +	{"IN1P", NULL, "LDO"}, +	{"IN2P", NULL, "LDO"}, +	{"IN3P", NULL, "LDO"}, + +	{"IN1P", NULL, "MIC1"}, +	{"IN2P", NULL, "MIC2"}, +	{"IN2N", NULL, "MIC2"}, +	{"IN3P", NULL, "MIC3"}, + +	{"BST1", NULL, "IN1P"}, +	{"BST2", NULL, "IN2P"}, +	{"BST2", NULL, "IN2N"}, +	{"BST3", NULL, "IN3P"}, + +	{"INL1 VOL", NULL, "IN2P"}, +	{"INR1 VOL", NULL, "IN2N"}, + +	{"RECMIXL", "INL1 Switch", "INL1 VOL"}, +	{"RECMIXL", "BST3 Switch", "BST3"}, +	{"RECMIXL", "BST2 Switch", "BST2"}, +	{"RECMIXL", "BST1 Switch", "BST1"}, + +	{"RECMIXR", "INR1 Switch", "INR1 VOL"}, +	{"RECMIXR", "BST3 Switch", "BST3"}, +	{"RECMIXR", "BST2 Switch", "BST2"}, +	{"RECMIXR", "BST1 Switch", "BST1"}, + +	{"ADC L", NULL, "RECMIXL"}, +	{"ADC L", NULL, "ADC L Power"}, +	{"ADC R", NULL, "RECMIXR"}, +	{"ADC R", NULL, "ADC R Power"}, + +	{"DMIC L1", NULL, "DMIC CLK"}, +	{"DMIC R1", NULL, "DMIC CLK"}, + +	{"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"}, +	{"Stereo1 ADC L2 Mux", "DD MIX", "DD MIXL"}, +	{"Stereo1 ADC L1 Mux", "ADC", "ADC L"}, +	{"Stereo1 ADC L1 Mux", "DD MIX", "DD MIXL"}, + +	{"Stereo1 ADC R1 Mux", "ADC", "ADC R"}, +	{"Stereo1 ADC R1 Mux", "DD MIX", "DD MIXR"}, +	{"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"}, +	{"Stereo1 ADC R2 Mux", "DD MIX", "DD MIXR"}, + +	{"Stereo2 ADC L2 Mux", "DMIC L", "DMIC L1"}, +	{"Stereo2 ADC L2 Mux", "DD MIXL", "DD MIXL"}, +	{"Stereo2 ADC L1 Mux", "DD MIXL", "DD MIXL"}, +	{"Stereo2 ADC L1 Mux", "ADCL", "ADC L"}, + +	{"Stereo2 ADC R1 Mux", "DD MIXR", "DD MIXR"}, +	{"Stereo2 ADC R1 Mux", "ADCR", "ADC R"}, +	{"Stereo2 ADC R2 Mux", "DMIC R", "DMIC R1"}, +	{"Stereo2 ADC R2 Mux", "DD MIXR", "DD MIXR"}, + +	{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"}, +	{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"}, +	{"Stereo1 ADC MIXL", NULL, "Stereo1 Filter"}, +	{"Stereo1 Filter", NULL, "PLL1", is_sysclk_from_pll}, +	{"Stereo1 Filter", NULL, "ADC ASRC"}, + +	{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"}, +	{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"}, +	{"Stereo1 ADC MIXR", NULL, "Stereo1 Filter"}, + +	{"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"}, +	{"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"}, +	{"Stereo2 ADC MIXL", NULL, "Stereo2 Filter"}, +	{"Stereo2 Filter", NULL, "PLL1", is_sysclk_from_pll}, +	{"Stereo2 Filter", NULL, "ADC ASRC"}, + +	{"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"}, +	{"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"}, +	{"Stereo2 ADC MIXR", NULL, "Stereo2 Filter"}, + +	{"IF1 ADC2", NULL, "Stereo2 ADC MIXL"}, +	{"IF1 ADC2", NULL, "Stereo2 ADC MIXR"}, +	{"IF1 ADC1", NULL, "Stereo1 ADC MIXL"}, +	{"IF1 ADC1", NULL, "Stereo1 ADC MIXR"}, + +	{"IF1 ADC1", NULL, "I2S1"}, + +	{"IF2 ADC", "IF1 ADC1", "IF1 ADC1"}, +	{"IF2 ADC", "IF1 ADC2", "IF1 ADC2"}, +	{"IF2 ADC", NULL, "I2S2"}, + +	{"AIF1TX", NULL, "IF1 ADC1"}, +	{"AIF1TX", NULL, "IF1 ADC2"}, +	{"AIF2TX", NULL, "IF2 ADC"}, + +	{"IF1 DAC", NULL, "AIF1RX"}, +	{"IF1 DAC", NULL, "I2S1"}, +	{"IF2 DAC", NULL, "AIF2RX"}, +	{"IF2 DAC", NULL, "I2S2"}, + +	{"IF1 DAC1 L", NULL, "IF1 DAC"}, +	{"IF1 DAC1 R", NULL, "IF1 DAC"}, +	{"IF1 DAC2 L", NULL, "IF1 DAC"}, +	{"IF1 DAC2 R", NULL, "IF1 DAC"}, +	{"IF2 DAC L", NULL, "IF2 DAC"}, +	{"IF2 DAC R", NULL, "IF2 DAC"}, + +	{"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, +	{"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"}, +	{"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, +	{"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"}, + +	{"Audio DSP", NULL, "DAC MIXL"}, +	{"Audio DSP", NULL, "DAC MIXR"}, + +	{"DAC L2 Mux", "IF1", "IF1 DAC2 L"}, +	{"DAC L2 Mux", "IF2", "IF2 DAC L"}, +	{"DAC L2 Volume", NULL, "DAC L2 Mux"}, + +	{"DAC R2 Mux", "IF1", "IF1 DAC2 R"}, +	{"DAC R2 Mux", "IF2", "IF2 DAC R"}, +	{"DAC R2 Volume", NULL, "DAC R2 Mux"}, + +	{"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"}, +	{"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume"}, +	{"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"}, +	{"Stereo DAC MIXL", NULL, "Stero1 DAC Power"}, +	{"Stereo DAC MIXL", NULL, "Stero2 DAC Power"}, +	{"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"}, +	{"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume"}, +	{"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"}, +	{"Stereo DAC MIXR", NULL, "Stero1 DAC Power"}, +	{"Stereo DAC MIXR", NULL, "Stero2 DAC Power"}, + +	{"PDM L Mux", "Stereo DAC MIX", "Stereo DAC MIXL"}, +	{"PDM L Mux", "DD MIX", "DAC MIXL"}, +	{"PDM R Mux", "Stereo DAC MIX", "Stereo DAC MIXR"}, +	{"PDM R Mux", "DD MIX", "DAC MIXR"}, + +	{"DAC L1", NULL, "Stereo DAC MIXL"}, +	{"DAC L1", NULL, "PLL1", is_sysclk_from_pll}, +	{"DAC L1", NULL, "DAC L1 Power"}, +	{"DAC R1", NULL, "Stereo DAC MIXR"}, +	{"DAC R1", NULL, "PLL1", is_sysclk_from_pll}, +	{"DAC R1", NULL, "DAC R1 Power"}, + +	{"DD MIXL", "DAC L1 Switch", "DAC MIXL"}, +	{"DD MIXL", "DAC L2 Switch", "DAC L2 Volume"}, +	{"DD MIXL", "DAC R2 Switch", "DAC R2 Volume"}, +	{"DD MIXL", NULL, "Stero2 DAC Power"}, + +	{"DD MIXR", "DAC R1 Switch", "DAC MIXR"}, +	{"DD MIXR", "DAC R2 Switch", "DAC R2 Volume"}, +	{"DD MIXR", "DAC L2 Switch", "DAC L2 Volume"}, +	{"DD MIXR", NULL, "Stero2 DAC Power"}, + +	{"OUT MIXL", "BST1 Switch", "BST1"}, +	{"OUT MIXL", "BST2 Switch", "BST2"}, +	{"OUT MIXL", "INL1 Switch", "INL1 VOL"}, +	{"OUT MIXL", "REC MIXL Switch", "RECMIXL"}, +	{"OUT MIXL", "DAC L1 Switch", "DAC L1"}, + +	{"OUT MIXR", "BST2 Switch", "BST2"}, +	{"OUT MIXR", "BST1 Switch", "BST1"}, +	{"OUT MIXR", "INR1 Switch", "INR1 VOL"}, +	{"OUT MIXR", "REC MIXR Switch", "RECMIXR"}, +	{"OUT MIXR", "DAC R1 Switch", "DAC R1"}, + +	{"HPOVOL L", "Switch", "OUT MIXL"}, +	{"HPOVOL R", "Switch", "OUT MIXR"}, +	{"OUTVOL L", "Switch", "OUT MIXL"}, +	{"OUTVOL R", "Switch", "OUT MIXR"}, + +	{"HPOL MIX", "HPO MIX DAC1 Switch", "DAC L1"}, +	{"HPOL MIX", "HPO MIX HPVOL Switch", "HPOVOL L"}, +	{"HPOL MIX", NULL, "HP L Amp"}, +	{"HPOR MIX", "HPO MIX DAC1 Switch", "DAC R1"}, +	{"HPOR MIX", "HPO MIX HPVOL Switch", "HPOVOL R"}, +	{"HPOR MIX", NULL, "HP R Amp"}, + +	{"LOUT MIX", "DAC L1 Switch", "DAC L1"}, +	{"LOUT MIX", "DAC R1 Switch", "DAC R1"}, +	{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"}, +	{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"}, + +	{"HP Amp", NULL, "HPOL MIX"}, +	{"HP Amp", NULL, "HPOR MIX"}, +	{"HP Amp", NULL, "Amp Power"}, +	{"HPO L Playback", "Switch", "HP Amp"}, +	{"HPO R Playback", "Switch", "HP Amp"}, +	{"HPOL", NULL, "HPO L Playback"}, +	{"HPOR", NULL, "HPO R Playback"}, + +	{"LOUT L Playback", "Switch", "LOUT MIX"}, +	{"LOUT R Playback", "Switch", "LOUT MIX"}, +	{"LOUTL", NULL, "LOUT L Playback"}, +	{"LOUTL", NULL, "Amp Power"}, +	{"LOUTR", NULL, "LOUT R Playback"}, +	{"LOUTR", NULL, "Amp Power"}, + +	{"PDML", NULL, "PDM L Mux"}, +	{"PDMR", NULL, "PDM R Mux"}, +}; + +static int rt5651_hw_params(struct snd_pcm_substream *substream, +	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); +	unsigned int val_len = 0, val_clk, mask_clk; +	int pre_div, bclk_ms, frame_size; + +	rt5651->lrck[dai->id] = params_rate(params); +	pre_div = rl6231_get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]); + +	if (pre_div < 0) { +		dev_err(codec->dev, "Unsupported clock setting\n"); +		return -EINVAL; +	} +	frame_size = snd_soc_params_to_frame_size(params); +	if (frame_size < 0) { +		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); +		return -EINVAL; +	} +	bclk_ms = frame_size > 32 ? 1 : 0; +	rt5651->bclk[dai->id] = rt5651->lrck[dai->id] * (32 << bclk_ms); + +	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", +		rt5651->bclk[dai->id], rt5651->lrck[dai->id]); +	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", +				bclk_ms, pre_div, dai->id); + +	switch (params_format(params)) { +	case SNDRV_PCM_FORMAT_S16_LE: +		break; +	case SNDRV_PCM_FORMAT_S20_3LE: +		val_len |= RT5651_I2S_DL_20; +		break; +	case SNDRV_PCM_FORMAT_S24_LE: +		val_len |= RT5651_I2S_DL_24; +		break; +	case SNDRV_PCM_FORMAT_S8: +		val_len |= RT5651_I2S_DL_8; +		break; +	default: +		return -EINVAL; +	} + +	switch (dai->id) { +	case RT5651_AIF1: +		mask_clk = RT5651_I2S_PD1_MASK; +		val_clk = pre_div << RT5651_I2S_PD1_SFT; +		snd_soc_update_bits(codec, RT5651_I2S1_SDP, +			RT5651_I2S_DL_MASK, val_len); +		snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk); +		break; +	case RT5651_AIF2: +		mask_clk = RT5651_I2S_BCLK_MS2_MASK | RT5651_I2S_PD2_MASK; +		val_clk = pre_div << RT5651_I2S_PD2_SFT; +		snd_soc_update_bits(codec, RT5651_I2S2_SDP, +			RT5651_I2S_DL_MASK, val_len); +		snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk); +		break; +	default: +		dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id); +		return -EINVAL; +	} + +	return 0; +} + +static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		rt5651->master[dai->id] = 1; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		reg_val |= RT5651_I2S_MS_S; +		rt5651->master[dai->id] = 0; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		break; +	case SND_SOC_DAIFMT_IB_NF: +		reg_val |= RT5651_I2S_BP_INV; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		reg_val |= RT5651_I2S_DF_LEFT; +		break; +	case SND_SOC_DAIFMT_DSP_A: +		reg_val |= RT5651_I2S_DF_PCM_A; +		break; +	case SND_SOC_DAIFMT_DSP_B: +		reg_val |= RT5651_I2S_DF_PCM_B; +		break; +	default: +		return -EINVAL; +	} + +	switch (dai->id) { +	case RT5651_AIF1: +		snd_soc_update_bits(codec, RT5651_I2S1_SDP, +			RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK | +			RT5651_I2S_DF_MASK, reg_val); +		break; +	case RT5651_AIF2: +		snd_soc_update_bits(codec, RT5651_I2S2_SDP, +			RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK | +			RT5651_I2S_DF_MASK, reg_val); +		break; +	default: +		dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id); +		return -EINVAL; +	} +	return 0; +} + +static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai, +		int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	if (freq == rt5651->sysclk && clk_id == rt5651->sysclk_src) +		return 0; + +	switch (clk_id) { +	case RT5651_SCLK_S_MCLK: +		reg_val |= RT5651_SCLK_SRC_MCLK; +		break; +	case RT5651_SCLK_S_PLL1: +		reg_val |= RT5651_SCLK_SRC_PLL1; +		break; +	case RT5651_SCLK_S_RCCLK: +		reg_val |= RT5651_SCLK_SRC_RCCLK; +		break; +	default: +		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); +		return -EINVAL; +	} +	snd_soc_update_bits(codec, RT5651_GLB_CLK, +		RT5651_SCLK_SRC_MASK, reg_val); +	rt5651->sysclk = freq; +	rt5651->sysclk_src = clk_id; + +	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + +	return 0; +} + +static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, +			unsigned int freq_in, unsigned int freq_out) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); +	struct rl6231_pll_code pll_code; +	int ret; + +	if (source == rt5651->pll_src && freq_in == rt5651->pll_in && +	    freq_out == rt5651->pll_out) +		return 0; + +	if (!freq_in || !freq_out) { +		dev_dbg(codec->dev, "PLL disabled\n"); + +		rt5651->pll_in = 0; +		rt5651->pll_out = 0; +		snd_soc_update_bits(codec, RT5651_GLB_CLK, +			RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_MCLK); +		return 0; +	} + +	switch (source) { +	case RT5651_PLL1_S_MCLK: +		snd_soc_update_bits(codec, RT5651_GLB_CLK, +			RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_MCLK); +		break; +	case RT5651_PLL1_S_BCLK1: +		snd_soc_update_bits(codec, RT5651_GLB_CLK, +				RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK1); +		break; +	case RT5651_PLL1_S_BCLK2: +			snd_soc_update_bits(codec, RT5651_GLB_CLK, +				RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK2); +		break; +	default: +		dev_err(codec->dev, "Unknown PLL source %d\n", source); +		return -EINVAL; +	} + +	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); +	if (ret < 0) { +		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); +		return ret; +	} + +	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", +		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), +		pll_code.n_code, pll_code.k_code); + +	snd_soc_write(codec, RT5651_PLL_CTRL1, +		pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code); +	snd_soc_write(codec, RT5651_PLL_CTRL2, +		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT | +		pll_code.m_bp << RT5651_PLL_M_BP_SFT); + +	rt5651->pll_in = freq_in; +	rt5651->pll_out = freq_out; +	rt5651->pll_src = source; + +	return 0; +} + +static int rt5651_set_bias_level(struct snd_soc_codec *codec, +			enum snd_soc_bias_level level) +{ +	switch (level) { +	case SND_SOC_BIAS_PREPARE: +		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { +			snd_soc_update_bits(codec, RT5651_PWR_ANLG1, +				RT5651_PWR_VREF1 | RT5651_PWR_MB | +				RT5651_PWR_BG | RT5651_PWR_VREF2, +				RT5651_PWR_VREF1 | RT5651_PWR_MB | +				RT5651_PWR_BG | RT5651_PWR_VREF2); +			usleep_range(10000, 15000); +			snd_soc_update_bits(codec, RT5651_PWR_ANLG1, +				RT5651_PWR_FV1 | RT5651_PWR_FV2, +				RT5651_PWR_FV1 | RT5651_PWR_FV2); +			snd_soc_update_bits(codec, RT5651_PWR_ANLG1, +				RT5651_PWR_LDO_DVO_MASK, +				RT5651_PWR_LDO_DVO_1_2V); +			snd_soc_update_bits(codec, RT5651_D_MISC, 0x1, 0x1); +			if (snd_soc_read(codec, RT5651_PLL_MODE_1) & 0x9200) +				snd_soc_update_bits(codec, RT5651_D_MISC, +						    0xc00, 0xc00); +		} +		break; + +	case SND_SOC_BIAS_STANDBY: +		snd_soc_write(codec, RT5651_D_MISC, 0x0010); +		snd_soc_write(codec, RT5651_PWR_DIG1, 0x0000); +		snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000); +		snd_soc_write(codec, RT5651_PWR_VOL, 0x0000); +		snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000); +		snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000); +		snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000); +		break; + +	default: +		break; +	} +	codec->dapm.bias_level = level; + +	return 0; +} + +static int rt5651_probe(struct snd_soc_codec *codec) +{ +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + +	rt5651->codec = codec; + +	snd_soc_update_bits(codec, RT5651_PWR_ANLG1, +		RT5651_PWR_VREF1 | RT5651_PWR_MB | +		RT5651_PWR_BG | RT5651_PWR_VREF2, +		RT5651_PWR_VREF1 | RT5651_PWR_MB | +		RT5651_PWR_BG | RT5651_PWR_VREF2); +	usleep_range(10000, 15000); +	snd_soc_update_bits(codec, RT5651_PWR_ANLG1, +		RT5651_PWR_FV1 | RT5651_PWR_FV2, +		RT5651_PWR_FV1 | RT5651_PWR_FV2); + +	rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF); + +	return 0; +} + +#ifdef CONFIG_PM +static int rt5651_suspend(struct snd_soc_codec *codec) +{ +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5651->regmap, true); +	regcache_mark_dirty(rt5651->regmap); +	return 0; +} + +static int rt5651_resume(struct snd_soc_codec *codec) +{ +	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5651->regmap, false); +	snd_soc_cache_sync(codec); + +	return 0; +} +#else +#define rt5651_suspend NULL +#define rt5651_resume NULL +#endif + +#define RT5651_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5651_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5651_aif_dai_ops = { +	.hw_params = rt5651_hw_params, +	.set_fmt = rt5651_set_dai_fmt, +	.set_sysclk = rt5651_set_dai_sysclk, +	.set_pll = rt5651_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5651_dai[] = { +	{ +		.name = "rt5651-aif1", +		.id = RT5651_AIF1, +		.playback = { +			.stream_name = "AIF1 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5651_STEREO_RATES, +			.formats = RT5651_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF1 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5651_STEREO_RATES, +			.formats = RT5651_FORMATS, +		}, +		.ops = &rt5651_aif_dai_ops, +	}, +	{ +		.name = "rt5651-aif2", +		.id = RT5651_AIF2, +		.playback = { +			.stream_name = "AIF2 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5651_STEREO_RATES, +			.formats = RT5651_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF2 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5651_STEREO_RATES, +			.formats = RT5651_FORMATS, +		}, +		.ops = &rt5651_aif_dai_ops, +	}, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5651 = { +	.probe = rt5651_probe, +	.suspend = rt5651_suspend, +	.resume = rt5651_resume, +	.set_bias_level = rt5651_set_bias_level, +	.idle_bias_off = true, +	.controls = rt5651_snd_controls, +	.num_controls = ARRAY_SIZE(rt5651_snd_controls), +	.dapm_widgets = rt5651_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets), +	.dapm_routes = rt5651_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes), +}; + +static const struct regmap_config rt5651_regmap = { +	.reg_bits = 8, +	.val_bits = 16, + +	.max_register = RT5651_DEVICE_ID + 1 + (ARRAY_SIZE(rt5651_ranges) * +					       RT5651_PR_SPACING), +	.volatile_reg = rt5651_volatile_register, +	.readable_reg = rt5651_readable_register, + +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults = rt5651_reg, +	.num_reg_defaults = ARRAY_SIZE(rt5651_reg), +	.ranges = rt5651_ranges, +	.num_ranges = ARRAY_SIZE(rt5651_ranges), +}; + +static const struct i2c_device_id rt5651_i2c_id[] = { +	{ "rt5651", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); + +static int rt5651_i2c_probe(struct i2c_client *i2c, +		    const struct i2c_device_id *id) +{ +	struct rt5651_platform_data *pdata = dev_get_platdata(&i2c->dev); +	struct rt5651_priv *rt5651; +	int ret; + +	rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651), +				GFP_KERNEL); +	if (NULL == rt5651) +		return -ENOMEM; + +	i2c_set_clientdata(i2c, rt5651); + +	if (pdata) +		rt5651->pdata = *pdata; + +	rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap); +	if (IS_ERR(rt5651->regmap)) { +		ret = PTR_ERR(rt5651->regmap); +		dev_err(&i2c->dev, "Failed to allocate register map: %d\n", +			ret); +		return ret; +	} + +	regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); +	if (ret != RT5651_DEVICE_ID_VALUE) { +		dev_err(&i2c->dev, +			"Device with ID register %x is not rt5651\n", ret); +		return -ENODEV; +	} + +	regmap_write(rt5651->regmap, RT5651_RESET, 0); + +	ret = regmap_register_patch(rt5651->regmap, init_list, +				    ARRAY_SIZE(init_list)); +	if (ret != 0) +		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + +	if (rt5651->pdata.in2_diff) +		regmap_update_bits(rt5651->regmap, RT5651_IN1_IN2, +					RT5651_IN_DF2, RT5651_IN_DF2); + +	if (rt5651->pdata.dmic_en) +		regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1, +				RT5651_GP2_PIN_MASK, RT5651_GP2_PIN_DMIC1_SCL); + +	rt5651->hp_mute = 1; + +	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651, +				rt5651_dai, ARRAY_SIZE(rt5651_dai)); + +	return ret; +} + +static int rt5651_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); + +	return 0; +} + +static struct i2c_driver rt5651_i2c_driver = { +	.driver = { +		.name = "rt5651", +		.owner = THIS_MODULE, +	}, +	.probe = rt5651_i2c_probe, +	.remove   = rt5651_i2c_remove, +	.id_table = rt5651_i2c_id, +}; +module_i2c_driver(rt5651_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5651 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h new file mode 100644 index 00000000000..1bd33cfa641 --- /dev/null +++ b/sound/soc/codecs/rt5651.h @@ -0,0 +1,2080 @@ +/* + * rt5651.h  --  RT5651 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu <johnnyhsu@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5651_H__ +#define __RT5651_H__ + +#include <sound/rt5651.h> + +/* Info */ +#define RT5651_RESET				0x00 +#define RT5651_VERSION_ID			0xfd +#define RT5651_VENDOR_ID			0xfe +#define RT5651_DEVICE_ID			0xff +/*  I/O - Output */ +#define RT5651_HP_VOL				0x02 +#define RT5651_LOUT_CTRL1			0x03 +#define RT5651_LOUT_CTRL2			0x05 +/* I/O - Input */ +#define RT5651_IN1_IN2				0x0d +#define RT5651_IN3				0x0e +#define RT5651_INL1_INR1_VOL			0x0f +#define RT5651_INL2_INR2_VOL			0x10 +/* I/O - ADC/DAC/DMIC */ +#define RT5651_DAC1_DIG_VOL			0x19 +#define RT5651_DAC2_DIG_VOL			0x1a +#define RT5651_DAC2_CTRL			0x1b +#define RT5651_ADC_DIG_VOL			0x1c +#define RT5651_ADC_DATA				0x1d +#define RT5651_ADC_BST_VOL			0x1e +/* Mixer - D-D */ +#define RT5651_STO1_ADC_MIXER			0x27 +#define RT5651_STO2_ADC_MIXER			0x28 +#define RT5651_AD_DA_MIXER			0x29 +#define RT5651_STO_DAC_MIXER			0x2a +#define RT5651_DD_MIXER				0x2b +#define RT5651_DIG_INF_DATA			0x2f +/* PDM */ +#define RT5651_PDM_CTL				0x30 +#define RT5651_PDM_I2C_CTL1			0x31 +#define RT5651_PDM_I2C_CTL2			0x32 +#define RT5651_PDM_I2C_DATA_W			0x33 +#define RT5651_PDM_I2C_DATA_R			0x34 +/* Mixer - ADC */ +#define RT5651_REC_L1_MIXER			0x3b +#define RT5651_REC_L2_MIXER			0x3c +#define RT5651_REC_R1_MIXER			0x3d +#define RT5651_REC_R2_MIXER			0x3e +/* Mixer - DAC */ +#define RT5651_HPO_MIXER			0x45 +#define RT5651_OUT_L1_MIXER			0x4d +#define RT5651_OUT_L2_MIXER			0x4e +#define RT5651_OUT_L3_MIXER			0x4f +#define RT5651_OUT_R1_MIXER			0x50 +#define RT5651_OUT_R2_MIXER			0x51 +#define RT5651_OUT_R3_MIXER			0x52 +#define RT5651_LOUT_MIXER			0x53 +/* Power */ +#define RT5651_PWR_DIG1				0x61 +#define RT5651_PWR_DIG2				0x62 +#define RT5651_PWR_ANLG1			0x63 +#define RT5651_PWR_ANLG2			0x64 +#define RT5651_PWR_MIXER			0x65 +#define RT5651_PWR_VOL				0x66 +/* Private Register Control */ +#define RT5651_PRIV_INDEX			0x6a +#define RT5651_PRIV_DATA			0x6c +/* Format - ADC/DAC */ +#define RT5651_I2S1_SDP				0x70 +#define RT5651_I2S2_SDP				0x71 +#define RT5651_ADDA_CLK1			0x73 +#define RT5651_ADDA_CLK2			0x74 +#define RT5651_DMIC				0x75 +/* TDM Control */ +#define RT5651_TDM_CTL_1			0x77 +#define RT5651_TDM_CTL_2			0x78 +#define RT5651_TDM_CTL_3			0x79 +/* Function - Analog */ +#define RT5651_GLB_CLK				0x80 +#define RT5651_PLL_CTRL1			0x81 +#define RT5651_PLL_CTRL2			0x82 +#define RT5651_PLL_MODE_1			0x83 +#define RT5651_PLL_MODE_2			0x84 +#define RT5651_PLL_MODE_3			0x85 +#define RT5651_PLL_MODE_4			0x86 +#define RT5651_PLL_MODE_5			0x87 +#define RT5651_PLL_MODE_6			0x89 +#define RT5651_PLL_MODE_7			0x8a +#define RT5651_DEPOP_M1				0x8e +#define RT5651_DEPOP_M2				0x8f +#define RT5651_DEPOP_M3				0x90 +#define RT5651_CHARGE_PUMP			0x91 +#define RT5651_MICBIAS				0x93 +#define RT5651_A_JD_CTL1			0x94 +/* Function - Digital */ +#define RT5651_EQ_CTRL1				0xb0 +#define RT5651_EQ_CTRL2				0xb1 +#define RT5651_ALC_1				0xb4 +#define RT5651_ALC_2				0xb5 +#define RT5651_ALC_3				0xb6 +#define RT5651_JD_CTRL1				0xbb +#define RT5651_JD_CTRL2				0xbc +#define RT5651_IRQ_CTRL1			0xbd +#define RT5651_IRQ_CTRL2			0xbe +#define RT5651_INT_IRQ_ST			0xbf +#define RT5651_GPIO_CTRL1			0xc0 +#define RT5651_GPIO_CTRL2			0xc1 +#define RT5651_GPIO_CTRL3			0xc2 +#define RT5651_PGM_REG_ARR1			0xc8 +#define RT5651_PGM_REG_ARR2			0xc9 +#define RT5651_PGM_REG_ARR3			0xca +#define RT5651_PGM_REG_ARR4			0xcb +#define RT5651_PGM_REG_ARR5			0xcc +#define RT5651_SCB_FUNC				0xcd +#define RT5651_SCB_CTRL				0xce +#define RT5651_BASE_BACK			0xcf +#define RT5651_MP3_PLUS1			0xd0 +#define RT5651_MP3_PLUS2			0xd1 +#define RT5651_ADJ_HPF_CTRL1			0xd3 +#define RT5651_ADJ_HPF_CTRL2			0xd4 +#define RT5651_HP_CALIB_AMP_DET			0xd6 +#define RT5651_HP_CALIB2			0xd7 +#define RT5651_SV_ZCD1				0xd9 +#define RT5651_SV_ZCD2				0xda +#define RT5651_D_MISC				0xfa +/* Dummy Register */ +#define RT5651_DUMMY2				0xfb +#define RT5651_DUMMY3				0xfc + + +/* Index of Codec Private Register definition */ +#define RT5651_BIAS_CUR1			0x12 +#define RT5651_BIAS_CUR3			0x14 +#define RT5651_CLSD_INT_REG1			0x1c +#define RT5651_CHPUMP_INT_REG1			0x24 +#define RT5651_MAMP_INT_REG2			0x37 +#define RT5651_CHOP_DAC_ADC			0x3d +#define RT5651_3D_SPK				0x63 +#define RT5651_WND_1				0x6c +#define RT5651_WND_2				0x6d +#define RT5651_WND_3				0x6e +#define RT5651_WND_4				0x6f +#define RT5651_WND_5				0x70 +#define RT5651_WND_8				0x73 +#define RT5651_DIP_SPK_INF			0x75 +#define RT5651_HP_DCC_INT1			0x77 +#define RT5651_EQ_BW_LOP			0xa0 +#define RT5651_EQ_GN_LOP			0xa1 +#define RT5651_EQ_FC_BP1			0xa2 +#define RT5651_EQ_BW_BP1			0xa3 +#define RT5651_EQ_GN_BP1			0xa4 +#define RT5651_EQ_FC_BP2			0xa5 +#define RT5651_EQ_BW_BP2			0xa6 +#define RT5651_EQ_GN_BP2			0xa7 +#define RT5651_EQ_FC_BP3			0xa8 +#define RT5651_EQ_BW_BP3			0xa9 +#define RT5651_EQ_GN_BP3			0xaa +#define RT5651_EQ_FC_BP4			0xab +#define RT5651_EQ_BW_BP4			0xac +#define RT5651_EQ_GN_BP4			0xad +#define RT5651_EQ_FC_HIP1			0xae +#define RT5651_EQ_GN_HIP1			0xaf +#define RT5651_EQ_FC_HIP2			0xb0 +#define RT5651_EQ_BW_HIP2			0xb1 +#define RT5651_EQ_GN_HIP2			0xb2 +#define RT5651_EQ_PRE_VOL			0xb3 +#define RT5651_EQ_PST_VOL			0xb4 + + +/* global definition */ +#define RT5651_L_MUTE				(0x1 << 15) +#define RT5651_L_MUTE_SFT			15 +#define RT5651_VOL_L_MUTE			(0x1 << 14) +#define RT5651_VOL_L_SFT			14 +#define RT5651_R_MUTE				(0x1 << 7) +#define RT5651_R_MUTE_SFT			7 +#define RT5651_VOL_R_MUTE			(0x1 << 6) +#define RT5651_VOL_R_SFT			6 +#define RT5651_L_VOL_MASK			(0x3f << 8) +#define RT5651_L_VOL_SFT			8 +#define RT5651_R_VOL_MASK			(0x3f) +#define RT5651_R_VOL_SFT			0 + +/* LOUT Control 2(0x05) */ +#define RT5651_EN_DFO				(0x1 << 15) + +/* IN1 and IN2 Control (0x0d) */ +/* IN3 and IN4 Control (0x0e) */ +#define RT5651_BST_MASK1			(0xf<<12) +#define RT5651_BST_SFT1				12 +#define RT5651_BST_MASK2			(0xf<<8) +#define RT5651_BST_SFT2				8 +#define RT5651_IN_DF1				(0x1 << 7) +#define RT5651_IN_SFT1				7 +#define RT5651_IN_DF2				(0x1 << 6) +#define RT5651_IN_SFT2				6 + +/* INL1 and INR1 Volume Control (0x0f) */ +/* INL2 and INR2 Volume Control (0x10) */ +#define RT5651_INL_SEL_MASK			(0x1 << 15) +#define RT5651_INL_SEL_SFT			15 +#define RT5651_INL_SEL_IN4P			(0x0 << 15) +#define RT5651_INL_SEL_MONOP			(0x1 << 15) +#define RT5651_INL_VOL_MASK			(0x1f << 8) +#define RT5651_INL_VOL_SFT			8 +#define RT5651_INR_SEL_MASK			(0x1 << 7) +#define RT5651_INR_SEL_SFT			7 +#define RT5651_INR_SEL_IN4N			(0x0 << 7) +#define RT5651_INR_SEL_MONON			(0x1 << 7) +#define RT5651_INR_VOL_MASK			(0x1f) +#define RT5651_INR_VOL_SFT			0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5651_DAC_L1_VOL_MASK			(0xff << 8) +#define RT5651_DAC_L1_VOL_SFT			8 +#define RT5651_DAC_R1_VOL_MASK			(0xff) +#define RT5651_DAC_R1_VOL_SFT			0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5651_DAC_L2_VOL_MASK			(0xff << 8) +#define RT5651_DAC_L2_VOL_SFT			8 +#define RT5651_DAC_R2_VOL_MASK			(0xff) +#define RT5651_DAC_R2_VOL_SFT			0 + +/* DAC2 Control (0x1b) */ +#define RT5651_M_DAC_L2_VOL			(0x1 << 13) +#define RT5651_M_DAC_L2_VOL_SFT			13 +#define RT5651_M_DAC_R2_VOL			(0x1 << 12) +#define RT5651_M_DAC_R2_VOL_SFT			12 +#define RT5651_SEL_DAC_L2			(0x1 << 11) +#define RT5651_IF2_DAC_L2			(0x1 << 11) +#define RT5651_IF1_DAC_L2			(0x0 << 11) +#define RT5651_SEL_DAC_L2_SFT			11 +#define RT5651_SEL_DAC_R2			(0x1 << 10) +#define RT5651_IF2_DAC_R2			(0x1 << 11) +#define RT5651_IF1_DAC_R2			(0x0 << 11) +#define RT5651_SEL_DAC_R2_SFT			10 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5651_ADC_L_VOL_MASK			(0x7f << 8) +#define RT5651_ADC_L_VOL_SFT			8 +#define RT5651_ADC_R_VOL_MASK			(0x7f) +#define RT5651_ADC_R_VOL_SFT			0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5651_M_MONO_ADC_L			(0x1 << 15) +#define RT5651_M_MONO_ADC_L_SFT			15 +#define RT5651_MONO_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5651_MONO_ADC_L_VOL_SFT		8 +#define RT5651_M_MONO_ADC_R			(0x1 << 7) +#define RT5651_M_MONO_ADC_R_SFT			7 +#define RT5651_MONO_ADC_R_VOL_MASK		(0x7f) +#define RT5651_MONO_ADC_R_VOL_SFT		0 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5651_ADC_L_BST_MASK			(0x3 << 14) +#define RT5651_ADC_L_BST_SFT			14 +#define RT5651_ADC_R_BST_MASK			(0x3 << 12) +#define RT5651_ADC_R_BST_SFT			12 +#define RT5651_ADC_COMP_MASK			(0x3 << 10) +#define RT5651_ADC_COMP_SFT			10 + +/* Stereo ADC1 Mixer Control (0x27) */ +#define RT5651_M_STO1_ADC_L1			(0x1 << 14) +#define RT5651_M_STO1_ADC_L1_SFT		14 +#define RT5651_M_STO1_ADC_L2			(0x1 << 13) +#define RT5651_M_STO1_ADC_L2_SFT		13 +#define RT5651_STO1_ADC_1_SRC_MASK		(0x1 << 12) +#define RT5651_STO1_ADC_1_SRC_SFT		12 +#define RT5651_STO1_ADC_1_SRC_ADC		(0x1 << 12) +#define RT5651_STO1_ADC_1_SRC_DACMIX		(0x0 << 12) +#define RT5651_STO1_ADC_2_SRC_MASK		(0x1 << 11) +#define RT5651_STO1_ADC_2_SRC_SFT		11 +#define RT5651_STO1_ADC_2_SRC_DMIC		(0x0 << 11) +#define RT5651_STO1_ADC_2_SRC_DACMIXR	(0x1 << 11) +#define RT5651_M_STO1_ADC_R1			(0x1 << 6) +#define RT5651_M_STO1_ADC_R1_SFT		6 +#define RT5651_M_STO1_ADC_R2			(0x1 << 5) +#define RT5651_M_STO1_ADC_R2_SFT		5 + +/* Stereo ADC2 Mixer Control (0x28) */ +#define RT5651_M_STO2_ADC_L1			(0x1 << 14) +#define RT5651_M_STO2_ADC_L1_SFT		14 +#define RT5651_M_STO2_ADC_L2			(0x1 << 13) +#define RT5651_M_STO2_ADC_L2_SFT		13 +#define RT5651_STO2_ADC_L1_SRC_MASK		(0x1 << 12) +#define RT5651_STO2_ADC_L1_SRC_SFT		12 +#define RT5651_STO2_ADC_L1_SRC_DACMIXL		(0x0 << 12) +#define RT5651_STO2_ADC_L1_SRC_ADCL		(0x1 << 12) +#define RT5651_STO2_ADC_L2_SRC_MASK		(0x1 << 11) +#define RT5651_STO2_ADC_L2_SRC_SFT		11 +#define RT5651_STO2_ADC_L2_SRC_DMIC		(0x0 << 11) +#define RT5651_STO2_ADC_L2_SRC_DACMIXR		(0x1 << 11) +#define RT5651_M_STO2_ADC_R1			(0x1 << 6) +#define RT5651_M_STO2_ADC_R1_SFT		6 +#define RT5651_M_STO2_ADC_R2			(0x1 << 5) +#define RT5651_M_STO2_ADC_R2_SFT		5 +#define RT5651_STO2_ADC_R1_SRC_MASK		(0x1 << 4) +#define RT5651_STO2_ADC_R1_SRC_SFT		4 +#define RT5651_STO2_ADC_R1_SRC_ADCR		(0x1 << 4) +#define RT5651_STO2_ADC_R1_SRC_DACMIXR		(0x0 << 4) +#define RT5651_STO2_ADC_R2_SRC_MASK		(0x1 << 3) +#define RT5651_STO2_ADC_R2_SRC_SFT		3 +#define RT5651_STO2_ADC_R2_SRC_DMIC		(0x0 << 3) +#define RT5651_STO2_ADC_R2_SRC_DACMIXR		(0x1 << 3) + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5651_M_ADCMIX_L			(0x1 << 15) +#define RT5651_M_ADCMIX_L_SFT			15 +#define RT5651_M_IF1_DAC_L			(0x1 << 14) +#define RT5651_M_IF1_DAC_L_SFT			14 +#define RT5651_M_ADCMIX_R			(0x1 << 7) +#define RT5651_M_ADCMIX_R_SFT			7 +#define RT5651_M_IF1_DAC_R			(0x1 << 6) +#define RT5651_M_IF1_DAC_R_SFT			6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5651_M_DAC_L1_MIXL			(0x1 << 14) +#define RT5651_M_DAC_L1_MIXL_SFT		14 +#define RT5651_DAC_L1_STO_L_VOL_MASK		(0x1 << 13) +#define RT5651_DAC_L1_STO_L_VOL_SFT		13 +#define RT5651_M_DAC_L2_MIXL			(0x1 << 12) +#define RT5651_M_DAC_L2_MIXL_SFT		12 +#define RT5651_DAC_L2_STO_L_VOL_MASK		(0x1 << 11) +#define RT5651_DAC_L2_STO_L_VOL_SFT		11 +#define RT5651_M_DAC_R1_MIXL			(0x1 << 9) +#define RT5651_M_DAC_R1_MIXL_SFT		9 +#define RT5651_DAC_R1_STO_L_VOL_MASK		(0x1 << 8) +#define RT5651_DAC_R1_STO_L_VOL_SFT		8 +#define RT5651_M_DAC_R1_MIXR			(0x1 << 6) +#define RT5651_M_DAC_R1_MIXR_SFT		6 +#define RT5651_DAC_R1_STO_R_VOL_MASK		(0x1 << 5) +#define RT5651_DAC_R1_STO_R_VOL_SFT		5 +#define RT5651_M_DAC_R2_MIXR			(0x1 << 4) +#define RT5651_M_DAC_R2_MIXR_SFT		4 +#define RT5651_DAC_R2_STO_R_VOL_MASK		(0x1 << 3) +#define RT5651_DAC_R2_STO_R_VOL_SFT		3 +#define RT5651_M_DAC_L1_MIXR			(0x1 << 1) +#define RT5651_M_DAC_L1_MIXR_SFT		1 +#define RT5651_DAC_L1_STO_R_VOL_MASK		(0x1) +#define RT5651_DAC_L1_STO_R_VOL_SFT		0 + +/* DD Mixer Control (0x2b) */ +#define RT5651_M_STO_DD_L1			(0x1 << 14) +#define RT5651_M_STO_DD_L1_SFT			14 +#define RT5651_STO_DD_L1_VOL_MASK		(0x1 << 13) +#define RT5651_DAC_DD_L1_VOL_SFT		13 +#define RT5651_M_STO_DD_L2			(0x1 << 12) +#define RT5651_M_STO_DD_L2_SFT			12 +#define RT5651_STO_DD_L2_VOL_MASK		(0x1 << 11) +#define RT5651_STO_DD_L2_VOL_SFT		11 +#define RT5651_M_STO_DD_R2_L			(0x1 << 10) +#define RT5651_M_STO_DD_R2_L_SFT		10 +#define RT5651_STO_DD_R2_L_VOL_MASK		(0x1 << 9) +#define RT5651_STO_DD_R2_L_VOL_SFT		9 +#define RT5651_M_STO_DD_R1			(0x1 << 6) +#define RT5651_M_STO_DD_R1_SFT			6 +#define RT5651_STO_DD_R1_VOL_MASK		(0x1 << 5) +#define RT5651_STO_DD_R1_VOL_SFT		5 +#define RT5651_M_STO_DD_R2			(0x1 << 4) +#define RT5651_M_STO_DD_R2_SFT			4 +#define RT5651_STO_DD_R2_VOL_MASK		(0x1 << 3) +#define RT5651_STO_DD_R2_VOL_SFT		3 +#define RT5651_M_STO_DD_L2_R			(0x1 << 2) +#define RT5651_M_STO_DD_L2_R_SFT		2 +#define RT5651_STO_DD_L2_R_VOL_MASK		(0x1 << 1) +#define RT5651_STO_DD_L2_R_VOL_SFT		1 + +/* Digital Mixer Control (0x2c) */ +#define RT5651_M_STO_L_DAC_L			(0x1 << 15) +#define RT5651_M_STO_L_DAC_L_SFT		15 +#define RT5651_STO_L_DAC_L_VOL_MASK		(0x1 << 14) +#define RT5651_STO_L_DAC_L_VOL_SFT		14 +#define RT5651_M_DAC_L2_DAC_L			(0x1 << 13) +#define RT5651_M_DAC_L2_DAC_L_SFT		13 +#define RT5651_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12) +#define RT5651_DAC_L2_DAC_L_VOL_SFT		12 +#define RT5651_M_STO_R_DAC_R			(0x1 << 11) +#define RT5651_M_STO_R_DAC_R_SFT		11 +#define RT5651_STO_R_DAC_R_VOL_MASK		(0x1 << 10) +#define RT5651_STO_R_DAC_R_VOL_SFT		10 +#define RT5651_M_DAC_R2_DAC_R			(0x1 << 9) +#define RT5651_M_DAC_R2_DAC_R_SFT		9 +#define RT5651_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8) +#define RT5651_DAC_R2_DAC_R_VOL_SFT		8 + +/* DSP Path Control 1 (0x2d) */ +#define RT5651_RXDP_SRC_MASK			(0x1 << 15) +#define RT5651_RXDP_SRC_SFT			15 +#define RT5651_RXDP_SRC_NOR			(0x0 << 15) +#define RT5651_RXDP_SRC_DIV3			(0x1 << 15) +#define RT5651_TXDP_SRC_MASK			(0x1 << 14) +#define RT5651_TXDP_SRC_SFT			14 +#define RT5651_TXDP_SRC_NOR			(0x0 << 14) +#define RT5651_TXDP_SRC_DIV3			(0x1 << 14) + +/* DSP Path Control 2 (0x2e) */ +#define RT5651_DAC_L2_SEL_MASK			(0x3 << 14) +#define RT5651_DAC_L2_SEL_SFT			14 +#define RT5651_DAC_L2_SEL_IF2			(0x0 << 14) +#define RT5651_DAC_L2_SEL_IF3			(0x1 << 14) +#define RT5651_DAC_L2_SEL_TXDC			(0x2 << 14) +#define RT5651_DAC_L2_SEL_BASS			(0x3 << 14) +#define RT5651_DAC_R2_SEL_MASK			(0x3 << 12) +#define RT5651_DAC_R2_SEL_SFT			12 +#define RT5651_DAC_R2_SEL_IF2			(0x0 << 12) +#define RT5651_DAC_R2_SEL_IF3			(0x1 << 12) +#define RT5651_DAC_R2_SEL_TXDC			(0x2 << 12) +#define RT5651_IF2_ADC_L_SEL_MASK		(0x1 << 11) +#define RT5651_IF2_ADC_L_SEL_SFT		11 +#define RT5651_IF2_ADC_L_SEL_TXDP		(0x0 << 11) +#define RT5651_IF2_ADC_L_SEL_PASS		(0x1 << 11) +#define RT5651_IF2_ADC_R_SEL_MASK		(0x1 << 10) +#define RT5651_IF2_ADC_R_SEL_SFT		10 +#define RT5651_IF2_ADC_R_SEL_TXDP		(0x0 << 10) +#define RT5651_IF2_ADC_R_SEL_PASS		(0x1 << 10) +#define RT5651_RXDC_SEL_MASK			(0x3 << 8) +#define RT5651_RXDC_SEL_SFT			8 +#define RT5651_RXDC_SEL_NOR			(0x0 << 8) +#define RT5651_RXDC_SEL_L2R			(0x1 << 8) +#define RT5651_RXDC_SEL_R2L			(0x2 << 8) +#define RT5651_RXDC_SEL_SWAP			(0x3 << 8) +#define RT5651_RXDP_SEL_MASK			(0x3 << 6) +#define RT5651_RXDP_SEL_SFT			6 +#define RT5651_RXDP_SEL_NOR			(0x0 << 6) +#define RT5651_RXDP_SEL_L2R			(0x1 << 6) +#define RT5651_RXDP_SEL_R2L			(0x2 << 6) +#define RT5651_RXDP_SEL_SWAP			(0x3 << 6) +#define RT5651_TXDC_SEL_MASK			(0x3 << 4) +#define RT5651_TXDC_SEL_SFT			4 +#define RT5651_TXDC_SEL_NOR			(0x0 << 4) +#define RT5651_TXDC_SEL_L2R			(0x1 << 4) +#define RT5651_TXDC_SEL_R2L			(0x2 << 4) +#define RT5651_TXDC_SEL_SWAP			(0x3 << 4) +#define RT5651_TXDP_SEL_MASK			(0x3 << 2) +#define RT5651_TXDP_SEL_SFT			2 +#define RT5651_TXDP_SEL_NOR			(0x0 << 2) +#define RT5651_TXDP_SEL_L2R			(0x1 << 2) +#define RT5651_TXDP_SEL_R2L			(0x2 << 2) +#define RT5651_TRXDP_SEL_SWAP			(0x3 << 2) + +/* Digital Interface Data Control (0x2f) */ +#define RT5651_IF2_DAC_SEL_MASK			(0x3 << 10) +#define RT5651_IF2_DAC_SEL_SFT			10 +#define RT5651_IF2_DAC_SEL_NOR			(0x0 << 10) +#define RT5651_IF2_DAC_SEL_SWAP			(0x1 << 10) +#define RT5651_IF2_DAC_SEL_L2R			(0x2 << 10) +#define RT5651_IF2_DAC_SEL_R2L			(0x3 << 10) +#define RT5651_IF2_ADC_SEL_MASK			(0x3 << 8) +#define RT5651_IF2_ADC_SEL_SFT			8 +#define RT5651_IF2_ADC_SEL_NOR			(0x0 << 8) +#define RT5651_IF2_ADC_SEL_SWAP			(0x1 << 8) +#define RT5651_IF2_ADC_SEL_L2R			(0x2 << 8) +#define RT5651_IF2_ADC_SEL_R2L			(0x3 << 8) +#define RT5651_IF2_ADC_SRC_MASK			(0x1 << 7) +#define RT5651_IF2_ADC_SRC_SFT			7 +#define RT5651_IF1_ADC1				(0x0 << 7) +#define RT5651_IF1_ADC2				(0x1 << 7) + +/* PDM Output Control (0x30) */ +#define RT5651_PDM_L_SEL_MASK			(0x1 << 15) +#define RT5651_PDM_L_SEL_SFT			15 +#define RT5651_PDM_L_SEL_DD_L			(0x0 << 15) +#define RT5651_PDM_L_SEL_STO_L			(0x1 << 15) +#define RT5651_M_PDM_L				(0x1 << 14) +#define RT5651_M_PDM_L_SFT			14 +#define RT5651_PDM_R_SEL_MASK			(0x1 << 13) +#define RT5651_PDM_R_SEL_SFT			13 +#define RT5651_PDM_R_SEL_DD_L			(0x0 << 13) +#define RT5651_PDM_R_SEL_STO_L			(0x1 << 13) +#define RT5651_M_PDM_R				(0x1 << 12) +#define RT5651_M_PDM_R_SFT			12 +#define RT5651_PDM_BUSY				(0x1 << 6) +#define RT5651_PDM_BUSY_SFT			6 +#define RT5651_PDM_PATTERN_SEL_MASK		(0x1 << 5) +#define RT5651_PDM_PATTERN_SEL_64		(0x0 << 5) +#define RT5651_PDM_PATTERN_SEL_128		(0x1 << 5) +#define RT5651_PDM_VOL_MASK			(0x1 << 4) +#define RT5651_PDM_VOL_SFT			4 +#define RT5651_PDM_DIV_MASK			(0x3) +#define RT5651_PDM_DIV_SFT			0 +#define RT5651_PDM_DIV_1			0 +#define RT5651_PDM_DIV_2			1 +#define RT5651_PDM_DIV_3			2 +#define RT5651_PDM_DIV_4			3 + +/* PDM I2C/Data Control 1 (0x31) */ +#define RT5651_PDM_I2C_ID_MASK			(0xf << 12) +#define PT5631_PDM_CMD_EXE			(0x1 << 11) +#define RT5651_PDM_I2C_CMD_MASK			(0x1 << 10) +#define RT5651_PDM_I2C_CMD_R			(0x0 << 10) +#define RT5651_PDM_I2C_CMD_W			(0x1 << 10) +#define RT5651_PDM_I2C_CMD_EXE			(0x1 << 9) +#define RT5651_PDM_I2C_NORMAL			(0x0 << 8) +#define RT5651_PDM_I2C_BUSY			(0x1 << 8) + +/* PDM I2C/Data Control 2 (0x32) */ +#define RT5651_PDM_I2C_ADDR			(0xff << 8) +#define RT5651_PDM_I2C_CMD_PATTERN		(0xff) + + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5651_G_LN_L2_RM_L_MASK		(0x7 << 13) +#define RT5651_G_IN_L2_RM_L_SFT			13 +#define RT5651_G_LN_L1_RM_L_MASK		(0x7 << 10) +#define RT5651_G_IN_L1_RM_L_SFT			10 +#define RT5651_G_BST3_RM_L_MASK			(0x7 << 4) +#define RT5651_G_BST3_RM_L_SFT			4 +#define RT5651_G_BST2_RM_L_MASK			(0x7 << 1) +#define RT5651_G_BST2_RM_L_SFT			1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5651_G_BST1_RM_L_MASK			(0x7 << 13) +#define RT5651_G_BST1_RM_L_SFT			13 +#define RT5651_G_OM_L_RM_L_MASK			(0x7 << 10) +#define RT5651_G_OM_L_RM_L_SFT			10 +#define RT5651_M_IN2_L_RM_L			(0x1 << 6) +#define RT5651_M_IN2_L_RM_L_SFT			6 +#define RT5651_M_IN1_L_RM_L			(0x1 << 5) +#define RT5651_M_IN1_L_RM_L_SFT			5 +#define RT5651_M_BST3_RM_L			(0x1 << 3) +#define RT5651_M_BST3_RM_L_SFT			3 +#define RT5651_M_BST2_RM_L			(0x1 << 2) +#define RT5651_M_BST2_RM_L_SFT			2 +#define RT5651_M_BST1_RM_L			(0x1 << 1) +#define RT5651_M_BST1_RM_L_SFT			1 +#define RT5651_M_OM_L_RM_L			(0x1) +#define RT5651_M_OM_L_RM_L_SFT			0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5651_G_IN2_R_RM_R_MASK		(0x7 << 13) +#define RT5651_G_IN2_R_RM_R_SFT			13 +#define RT5651_G_IN1_R_RM_R_MASK		(0x7 << 10) +#define RT5651_G_IN1_R_RM_R_SFT			10 +#define RT5651_G_BST3_RM_R_MASK			(0x7 << 4) +#define RT5651_G_BST3_RM_R_SFT			4 +#define RT5651_G_BST2_RM_R_MASK			(0x7 << 1) +#define RT5651_G_BST2_RM_R_SFT			1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5651_G_BST1_RM_R_MASK			(0x7 << 13) +#define RT5651_G_BST1_RM_R_SFT			13 +#define RT5651_G_OM_R_RM_R_MASK			(0x7 << 10) +#define RT5651_G_OM_R_RM_R_SFT			10 +#define RT5651_M_IN2_R_RM_R			(0x1 << 6) +#define RT5651_M_IN2_R_RM_R_SFT			6 +#define RT5651_M_IN1_R_RM_R			(0x1 << 5) +#define RT5651_M_IN1_R_RM_R_SFT			5 +#define RT5651_M_BST3_RM_R			(0x1 << 3) +#define RT5651_M_BST3_RM_R_SFT			3 +#define RT5651_M_BST2_RM_R			(0x1 << 2) +#define RT5651_M_BST2_RM_R_SFT			2 +#define RT5651_M_BST1_RM_R			(0x1 << 1) +#define RT5651_M_BST1_RM_R_SFT			1 +#define RT5651_M_OM_R_RM_R			(0x1) +#define RT5651_M_OM_R_RM_R_SFT			0 + +/* HPMIX Control (0x45) */ +#define RT5651_M_DAC1_HM			(0x1 << 14) +#define RT5651_M_DAC1_HM_SFT			14 +#define RT5651_M_HPVOL_HM			(0x1 << 13) +#define RT5651_M_HPVOL_HM_SFT			13 +#define RT5651_G_HPOMIX_MASK			(0x1 << 12) +#define RT5651_G_HPOMIX_SFT			12 + +/* SPK Left Mixer Control (0x46) */ +#define RT5651_G_RM_L_SM_L_MASK			(0x3 << 14) +#define RT5651_G_RM_L_SM_L_SFT			14 +#define RT5651_G_IN_L_SM_L_MASK			(0x3 << 12) +#define RT5651_G_IN_L_SM_L_SFT			12 +#define RT5651_G_DAC_L1_SM_L_MASK		(0x3 << 10) +#define RT5651_G_DAC_L1_SM_L_SFT		10 +#define RT5651_G_DAC_L2_SM_L_MASK		(0x3 << 8) +#define RT5651_G_DAC_L2_SM_L_SFT		8 +#define RT5651_G_OM_L_SM_L_MASK			(0x3 << 6) +#define RT5651_G_OM_L_SM_L_SFT			6 +#define RT5651_M_RM_L_SM_L			(0x1 << 5) +#define RT5651_M_RM_L_SM_L_SFT			5 +#define RT5651_M_IN_L_SM_L			(0x1 << 4) +#define RT5651_M_IN_L_SM_L_SFT			4 +#define RT5651_M_DAC_L1_SM_L			(0x1 << 3) +#define RT5651_M_DAC_L1_SM_L_SFT		3 +#define RT5651_M_DAC_L2_SM_L			(0x1 << 2) +#define RT5651_M_DAC_L2_SM_L_SFT		2 +#define RT5651_M_OM_L_SM_L			(0x1 << 1) +#define RT5651_M_OM_L_SM_L_SFT			1 + +/* SPK Right Mixer Control (0x47) */ +#define RT5651_G_RM_R_SM_R_MASK			(0x3 << 14) +#define RT5651_G_RM_R_SM_R_SFT			14 +#define RT5651_G_IN_R_SM_R_MASK			(0x3 << 12) +#define RT5651_G_IN_R_SM_R_SFT			12 +#define RT5651_G_DAC_R1_SM_R_MASK		(0x3 << 10) +#define RT5651_G_DAC_R1_SM_R_SFT		10 +#define RT5651_G_DAC_R2_SM_R_MASK		(0x3 << 8) +#define RT5651_G_DAC_R2_SM_R_SFT		8 +#define RT5651_G_OM_R_SM_R_MASK			(0x3 << 6) +#define RT5651_G_OM_R_SM_R_SFT			6 +#define RT5651_M_RM_R_SM_R			(0x1 << 5) +#define RT5651_M_RM_R_SM_R_SFT			5 +#define RT5651_M_IN_R_SM_R			(0x1 << 4) +#define RT5651_M_IN_R_SM_R_SFT			4 +#define RT5651_M_DAC_R1_SM_R			(0x1 << 3) +#define RT5651_M_DAC_R1_SM_R_SFT		3 +#define RT5651_M_DAC_R2_SM_R			(0x1 << 2) +#define RT5651_M_DAC_R2_SM_R_SFT		2 +#define RT5651_M_OM_R_SM_R			(0x1 << 1) +#define RT5651_M_OM_R_SM_R_SFT			1 + +/* SPOLMIX Control (0x48) */ +#define RT5651_M_DAC_R1_SPM_L			(0x1 << 15) +#define RT5651_M_DAC_R1_SPM_L_SFT		15 +#define RT5651_M_DAC_L1_SPM_L			(0x1 << 14) +#define RT5651_M_DAC_L1_SPM_L_SFT		14 +#define RT5651_M_SV_R_SPM_L			(0x1 << 13) +#define RT5651_M_SV_R_SPM_L_SFT			13 +#define RT5651_M_SV_L_SPM_L			(0x1 << 12) +#define RT5651_M_SV_L_SPM_L_SFT			12 +#define RT5651_M_BST1_SPM_L			(0x1 << 11) +#define RT5651_M_BST1_SPM_L_SFT			11 + +/* SPORMIX Control (0x49) */ +#define RT5651_M_DAC_R1_SPM_R			(0x1 << 13) +#define RT5651_M_DAC_R1_SPM_R_SFT		13 +#define RT5651_M_SV_R_SPM_R			(0x1 << 12) +#define RT5651_M_SV_R_SPM_R_SFT			12 +#define RT5651_M_BST1_SPM_R			(0x1 << 11) +#define RT5651_M_BST1_SPM_R_SFT			11 + +/* SPOLMIX / SPORMIX Ratio Control (0x4a) */ +#define RT5651_SPO_CLSD_RATIO_MASK		(0x7) +#define RT5651_SPO_CLSD_RATIO_SFT		0 + +/* Mono Output Mixer Control (0x4c) */ +#define RT5651_M_DAC_R2_MM			(0x1 << 15) +#define RT5651_M_DAC_R2_MM_SFT			15 +#define RT5651_M_DAC_L2_MM			(0x1 << 14) +#define RT5651_M_DAC_L2_MM_SFT			14 +#define RT5651_M_OV_R_MM			(0x1 << 13) +#define RT5651_M_OV_R_MM_SFT			13 +#define RT5651_M_OV_L_MM			(0x1 << 12) +#define RT5651_M_OV_L_MM_SFT			12 +#define RT5651_M_BST1_MM			(0x1 << 11) +#define RT5651_M_BST1_MM_SFT			11 +#define RT5651_G_MONOMIX_MASK			(0x1 << 10) +#define RT5651_G_MONOMIX_SFT			10 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5651_G_BST2_OM_L_MASK			(0x7 << 10) +#define RT5651_G_BST2_OM_L_SFT			10 +#define RT5651_G_BST1_OM_L_MASK			(0x7 << 7) +#define RT5651_G_BST1_OM_L_SFT			7 +#define RT5651_G_IN1_L_OM_L_MASK		(0x7 << 4) +#define RT5651_G_IN1_L_OM_L_SFT			4 +#define RT5651_G_RM_L_OM_L_MASK			(0x7 << 1) +#define RT5651_G_RM_L_OM_L_SFT			1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5651_G_DAC_L1_OM_L_MASK		(0x7 << 7) +#define RT5651_G_DAC_L1_OM_L_SFT		7 +#define RT5651_G_IN2_L_OM_L_MASK		(0x7 << 4) +#define RT5651_G_IN2_L_OM_L_SFT			4 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5651_M_IN2_L_OM_L			(0x1 << 9) +#define RT5651_M_IN2_L_OM_L_SFT			9 +#define RT5651_M_BST2_OM_L			(0x1 << 6) +#define RT5651_M_BST2_OM_L_SFT			6 +#define RT5651_M_BST1_OM_L			(0x1 << 5) +#define RT5651_M_BST1_OM_L_SFT			5 +#define RT5651_M_IN1_L_OM_L			(0x1 << 4) +#define RT5651_M_IN1_L_OM_L_SFT			4 +#define RT5651_M_RM_L_OM_L			(0x1 << 3) +#define RT5651_M_RM_L_OM_L_SFT			3 +#define RT5651_M_DAC_L1_OM_L			(0x1) +#define RT5651_M_DAC_L1_OM_L_SFT		0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5651_G_BST2_OM_R_MASK			(0x7 << 10) +#define RT5651_G_BST2_OM_R_SFT			10 +#define RT5651_G_BST1_OM_R_MASK			(0x7 << 7) +#define RT5651_G_BST1_OM_R_SFT			7 +#define RT5651_G_IN1_R_OM_R_MASK		(0x7 << 4) +#define RT5651_G_IN1_R_OM_R_SFT			4 +#define RT5651_G_RM_R_OM_R_MASK			(0x7 << 1) +#define RT5651_G_RM_R_OM_R_SFT			1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5651_G_DAC_R1_OM_R_MASK		(0x7 << 7) +#define RT5651_G_DAC_R1_OM_R_SFT		7 +#define RT5651_G_IN2_R_OM_R_MASK		(0x7 << 4) +#define RT5651_G_IN2_R_OM_R_SFT			4 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5651_M_IN2_R_OM_R			(0x1 << 9) +#define RT5651_M_IN2_R_OM_R_SFT			9 +#define RT5651_M_BST2_OM_R			(0x1 << 6) +#define RT5651_M_BST2_OM_R_SFT			6 +#define RT5651_M_BST1_OM_R			(0x1 << 5) +#define RT5651_M_BST1_OM_R_SFT			5 +#define RT5651_M_IN1_R_OM_R			(0x1 << 4) +#define RT5651_M_IN1_R_OM_R_SFT			4 +#define RT5651_M_RM_R_OM_R			(0x1 << 3) +#define RT5651_M_RM_R_OM_R_SFT			3 +#define RT5651_M_DAC_R1_OM_R			(0x1) +#define RT5651_M_DAC_R1_OM_R_SFT		0 + +/* LOUT Mixer Control (0x53) */ +#define RT5651_M_DAC_L1_LM			(0x1 << 15) +#define RT5651_M_DAC_L1_LM_SFT			15 +#define RT5651_M_DAC_R1_LM			(0x1 << 14) +#define RT5651_M_DAC_R1_LM_SFT			14 +#define RT5651_M_OV_L_LM			(0x1 << 13) +#define RT5651_M_OV_L_LM_SFT			13 +#define RT5651_M_OV_R_LM			(0x1 << 12) +#define RT5651_M_OV_R_LM_SFT			12 +#define RT5651_G_LOUTMIX_MASK			(0x1 << 11) +#define RT5651_G_LOUTMIX_SFT			11 + +/* Power Management for Digital 1 (0x61) */ +#define RT5651_PWR_I2S1				(0x1 << 15) +#define RT5651_PWR_I2S1_BIT			15 +#define RT5651_PWR_I2S2				(0x1 << 14) +#define RT5651_PWR_I2S2_BIT			14 +#define RT5651_PWR_DAC_L1			(0x1 << 12) +#define RT5651_PWR_DAC_L1_BIT			12 +#define RT5651_PWR_DAC_R1			(0x1 << 11) +#define RT5651_PWR_DAC_R1_BIT			11 +#define RT5651_PWR_ADC_L			(0x1 << 2) +#define RT5651_PWR_ADC_L_BIT			2 +#define RT5651_PWR_ADC_R			(0x1 << 1) +#define RT5651_PWR_ADC_R_BIT			1 + +/* Power Management for Digital 2 (0x62) */ +#define RT5651_PWR_ADC_STO1_F			(0x1 << 15) +#define RT5651_PWR_ADC_STO1_F_BIT			15 +#define RT5651_PWR_ADC_STO2_F			(0x1 << 14) +#define RT5651_PWR_ADC_STO2_F_BIT		14 +#define RT5651_PWR_DAC_STO1_F			(0x1 << 11) +#define RT5651_PWR_DAC_STO1_F_BIT			11 +#define RT5651_PWR_DAC_STO2_F			(0x1 << 10) +#define RT5651_PWR_DAC_STO2_F_BIT		10 +#define RT5651_PWR_PDM				(0x1 << 9) +#define RT5651_PWR_PDM_BIT			9 + +/* Power Management for Analog 1 (0x63) */ +#define RT5651_PWR_VREF1			(0x1 << 15) +#define RT5651_PWR_VREF1_BIT			15 +#define RT5651_PWR_FV1				(0x1 << 14) +#define RT5651_PWR_FV1_BIT			14 +#define RT5651_PWR_MB				(0x1 << 13) +#define RT5651_PWR_MB_BIT			13 +#define RT5651_PWR_LM				(0x1 << 12) +#define RT5651_PWR_LM_BIT			12 +#define RT5651_PWR_BG				(0x1 << 11) +#define RT5651_PWR_BG_BIT			11 +#define RT5651_PWR_HP_L				(0x1 << 7) +#define RT5651_PWR_HP_L_BIT			7 +#define RT5651_PWR_HP_R				(0x1 << 6) +#define RT5651_PWR_HP_R_BIT			6 +#define RT5651_PWR_HA				(0x1 << 5) +#define RT5651_PWR_HA_BIT			5 +#define RT5651_PWR_VREF2			(0x1 << 4) +#define RT5651_PWR_VREF2_BIT			4 +#define RT5651_PWR_FV2				(0x1 << 3) +#define RT5651_PWR_FV2_BIT			3 +#define RT5651_PWR_LDO				(0x1 << 2) +#define RT5651_PWR_LDO_BIT			2 +#define RT5651_PWR_LDO_DVO_MASK			(0x3) +#define RT5651_PWR_LDO_DVO_1_0V			0 +#define RT5651_PWR_LDO_DVO_1_1V			1 +#define RT5651_PWR_LDO_DVO_1_2V			2 +#define RT5651_PWR_LDO_DVO_1_3V			3 + +/* Power Management for Analog 2 (0x64) */ +#define RT5651_PWR_BST1				(0x1 << 15) +#define RT5651_PWR_BST1_BIT			15 +#define RT5651_PWR_BST2				(0x1 << 14) +#define RT5651_PWR_BST2_BIT			14 +#define RT5651_PWR_BST3				(0x1 << 13) +#define RT5651_PWR_BST3_BIT			13 +#define RT5651_PWR_MB1				(0x1 << 11) +#define RT5651_PWR_MB1_BIT			11 +#define RT5651_PWR_PLL				(0x1 << 9) +#define RT5651_PWR_PLL_BIT			9 +#define RT5651_PWR_BST1_OP2			(0x1 << 5) +#define RT5651_PWR_BST1_OP2_BIT			5 +#define RT5651_PWR_BST2_OP2			(0x1 << 4) +#define RT5651_PWR_BST2_OP2_BIT			4 +#define RT5651_PWR_BST3_OP2			(0x1 << 3) +#define RT5651_PWR_BST3_OP2_BIT			3 +#define RT5651_PWR_JD_M				(0x1 << 2) +#define RT5651_PWM_JD_M_BIT			2 +#define RT5651_PWR_JD2				(0x1 << 1) +#define RT5651_PWM_JD2_BIT			1 +#define RT5651_PWR_JD3				(0x1) +#define RT5651_PWM_JD3_BIT			0 + +/* Power Management for Mixer (0x65) */ +#define RT5651_PWR_OM_L				(0x1 << 15) +#define RT5651_PWR_OM_L_BIT			15 +#define RT5651_PWR_OM_R				(0x1 << 14) +#define RT5651_PWR_OM_R_BIT			14 +#define RT5651_PWR_RM_L				(0x1 << 11) +#define RT5651_PWR_RM_L_BIT			11 +#define RT5651_PWR_RM_R				(0x1 << 10) +#define RT5651_PWR_RM_R_BIT			10 + +/* Power Management for Volume (0x66) */ +#define RT5651_PWR_OV_L				(0x1 << 13) +#define RT5651_PWR_OV_L_BIT			13 +#define RT5651_PWR_OV_R				(0x1 << 12) +#define RT5651_PWR_OV_R_BIT			12 +#define RT5651_PWR_HV_L				(0x1 << 11) +#define RT5651_PWR_HV_L_BIT			11 +#define RT5651_PWR_HV_R				(0x1 << 10) +#define RT5651_PWR_HV_R_BIT			10 +#define RT5651_PWR_IN1_L			(0x1 << 9) +#define RT5651_PWR_IN1_L_BIT			9 +#define RT5651_PWR_IN1_R			(0x1 << 8) +#define RT5651_PWR_IN1_R_BIT			8 +#define RT5651_PWR_IN2_L			(0x1 << 7) +#define RT5651_PWR_IN2_L_BIT			7 +#define RT5651_PWR_IN2_R			(0x1 << 6) +#define RT5651_PWR_IN2_R_BIT			6 + +/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */ +#define RT5651_I2S_MS_MASK			(0x1 << 15) +#define RT5651_I2S_MS_SFT			15 +#define RT5651_I2S_MS_M				(0x0 << 15) +#define RT5651_I2S_MS_S				(0x1 << 15) +#define RT5651_I2S_O_CP_MASK			(0x3 << 10) +#define RT5651_I2S_O_CP_SFT			10 +#define RT5651_I2S_O_CP_OFF			(0x0 << 10) +#define RT5651_I2S_O_CP_U_LAW			(0x1 << 10) +#define RT5651_I2S_O_CP_A_LAW			(0x2 << 10) +#define RT5651_I2S_I_CP_MASK			(0x3 << 8) +#define RT5651_I2S_I_CP_SFT			8 +#define RT5651_I2S_I_CP_OFF			(0x0 << 8) +#define RT5651_I2S_I_CP_U_LAW			(0x1 << 8) +#define RT5651_I2S_I_CP_A_LAW			(0x2 << 8) +#define RT5651_I2S_BP_MASK			(0x1 << 7) +#define RT5651_I2S_BP_SFT			7 +#define RT5651_I2S_BP_NOR			(0x0 << 7) +#define RT5651_I2S_BP_INV			(0x1 << 7) +#define RT5651_I2S_DL_MASK			(0x3 << 2) +#define RT5651_I2S_DL_SFT			2 +#define RT5651_I2S_DL_16			(0x0 << 2) +#define RT5651_I2S_DL_20			(0x1 << 2) +#define RT5651_I2S_DL_24			(0x2 << 2) +#define RT5651_I2S_DL_8				(0x3 << 2) +#define RT5651_I2S_DF_MASK			(0x3) +#define RT5651_I2S_DF_SFT			0 +#define RT5651_I2S_DF_I2S			(0x0) +#define RT5651_I2S_DF_LEFT			(0x1) +#define RT5651_I2S_DF_PCM_A			(0x2) +#define RT5651_I2S_DF_PCM_B			(0x3) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5651_I2S_PD1_MASK			(0x7 << 12) +#define RT5651_I2S_PD1_SFT			12 +#define RT5651_I2S_PD1_1			(0x0 << 12) +#define RT5651_I2S_PD1_2			(0x1 << 12) +#define RT5651_I2S_PD1_3			(0x2 << 12) +#define RT5651_I2S_PD1_4			(0x3 << 12) +#define RT5651_I2S_PD1_6			(0x4 << 12) +#define RT5651_I2S_PD1_8			(0x5 << 12) +#define RT5651_I2S_PD1_12			(0x6 << 12) +#define RT5651_I2S_PD1_16			(0x7 << 12) +#define RT5651_I2S_BCLK_MS2_MASK		(0x1 << 11) +#define RT5651_I2S_BCLK_MS2_SFT			11 +#define RT5651_I2S_BCLK_MS2_32			(0x0 << 11) +#define RT5651_I2S_BCLK_MS2_64			(0x1 << 11) +#define RT5651_I2S_PD2_MASK			(0x7 << 8) +#define RT5651_I2S_PD2_SFT			8 +#define RT5651_I2S_PD2_1			(0x0 << 8) +#define RT5651_I2S_PD2_2			(0x1 << 8) +#define RT5651_I2S_PD2_3			(0x2 << 8) +#define RT5651_I2S_PD2_4			(0x3 << 8) +#define RT5651_I2S_PD2_6			(0x4 << 8) +#define RT5651_I2S_PD2_8			(0x5 << 8) +#define RT5651_I2S_PD2_12			(0x6 << 8) +#define RT5651_I2S_PD2_16			(0x7 << 8) +#define RT5651_DAC_OSR_MASK			(0x3 << 2) +#define RT5651_DAC_OSR_SFT			2 +#define RT5651_DAC_OSR_128			(0x0 << 2) +#define RT5651_DAC_OSR_64			(0x1 << 2) +#define RT5651_DAC_OSR_32			(0x2 << 2) +#define RT5651_DAC_OSR_128_3			(0x3 << 2) +#define RT5651_ADC_OSR_MASK			(0x3) +#define RT5651_ADC_OSR_SFT			0 +#define RT5651_ADC_OSR_128			(0x0) +#define RT5651_ADC_OSR_64			(0x1) +#define RT5651_ADC_OSR_32			(0x2) +#define RT5651_ADC_OSR_128_3			(0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5651_DAHPF_EN				(0x1 << 11) +#define RT5651_DAHPF_EN_SFT			11 +#define RT5651_ADHPF_EN				(0x1 << 10) +#define RT5651_ADHPF_EN_SFT			10 + +/* Digital Microphone Control (0x75) */ +#define RT5651_DMIC_1_EN_MASK			(0x1 << 15) +#define RT5651_DMIC_1_EN_SFT			15 +#define RT5651_DMIC_1_DIS			(0x0 << 15) +#define RT5651_DMIC_1_EN			(0x1 << 15) +#define RT5651_DMIC_1L_LH_MASK			(0x1 << 13) +#define RT5651_DMIC_1L_LH_SFT			13 +#define RT5651_DMIC_1L_LH_FALLING		(0x0 << 13) +#define RT5651_DMIC_1L_LH_RISING		(0x1 << 13) +#define RT5651_DMIC_1R_LH_MASK			(0x1 << 12) +#define RT5651_DMIC_1R_LH_SFT			12 +#define RT5651_DMIC_1R_LH_FALLING		(0x0 << 12) +#define RT5651_DMIC_1R_LH_RISING		(0x1 << 12) +#define RT5651_DMIC_1_DP_MASK			(0x3 << 10) +#define RT5651_DMIC_1_DP_SFT			10 +#define RT5651_DMIC_1_DP_GPIO6			(0x0 << 10) +#define RT5651_DMIC_1_DP_IN1P			(0x1 << 10) +#define RT5651_DMIC_2_DP_GPIO8			(0x2 << 10) +#define RT5651_DMIC_CLK_MASK			(0x7 << 5) +#define RT5651_DMIC_CLK_SFT			5 + +/* TDM Control 1 (0x77) */ +#define RT5651_TDM_INTEL_SEL_MASK		(0x1 << 15) +#define RT5651_TDM_INTEL_SEL_SFT		15 +#define RT5651_TDM_INTEL_SEL_64			(0x0 << 15) +#define RT5651_TDM_INTEL_SEL_50			(0x1 << 15) +#define RT5651_TDM_MODE_SEL_MASK		(0x1 << 14) +#define RT5651_TDM_MODE_SEL_SFT			14 +#define RT5651_TDM_MODE_SEL_NOR			(0x0 << 14) +#define RT5651_TDM_MODE_SEL_TDM			(0x1 << 14) +#define RT5651_TDM_CH_NUM_SEL_MASK		(0x3 << 12) +#define RT5651_TDM_CH_NUM_SEL_SFT		12 +#define RT5651_TDM_CH_NUM_SEL_2			(0x0 << 12) +#define RT5651_TDM_CH_NUM_SEL_4			(0x1 << 12) +#define RT5651_TDM_CH_NUM_SEL_6			(0x2 << 12) +#define RT5651_TDM_CH_NUM_SEL_8			(0x3 << 12) +#define RT5651_TDM_CH_LEN_SEL_MASK		(0x3 << 10) +#define RT5651_TDM_CH_LEN_SEL_SFT		10 +#define RT5651_TDM_CH_LEN_SEL_16		(0x0 << 10) +#define RT5651_TDM_CH_LEN_SEL_20		(0x1 << 10) +#define RT5651_TDM_CH_LEN_SEL_24		(0x2 << 10) +#define RT5651_TDM_CH_LEN_SEL_32		(0x3 << 10) +#define RT5651_TDM_ADC_SEL_MASK			(0x1 << 9) +#define RT5651_TDM_ADC_SEL_SFT			9 +#define RT5651_TDM_ADC_SEL_NOR			(0x0 << 9) +#define RT5651_TDM_ADC_SEL_SWAP			(0x1 << 9) +#define RT5651_TDM_ADC_START_SEL_MASK		(0x1 << 8) +#define RT5651_TDM_ADC_START_SEL_SFT		8 +#define RT5651_TDM_ADC_START_SEL_SL0		(0x0 << 8) +#define RT5651_TDM_ADC_START_SEL_SL4		(0x1 << 8) +#define RT5651_TDM_I2S_CH2_SEL_MASK		(0x3 << 6) +#define RT5651_TDM_I2S_CH2_SEL_SFT		6 +#define RT5651_TDM_I2S_CH2_SEL_LR		(0x0 << 6) +#define RT5651_TDM_I2S_CH2_SEL_RL		(0x1 << 6) +#define RT5651_TDM_I2S_CH2_SEL_LL		(0x2 << 6) +#define RT5651_TDM_I2S_CH2_SEL_RR		(0x3 << 6) +#define RT5651_TDM_I2S_CH4_SEL_MASK		(0x3 << 4) +#define RT5651_TDM_I2S_CH4_SEL_SFT		4 +#define RT5651_TDM_I2S_CH4_SEL_LR		(0x0 << 4) +#define RT5651_TDM_I2S_CH4_SEL_RL		(0x1 << 4) +#define RT5651_TDM_I2S_CH4_SEL_LL		(0x2 << 4) +#define RT5651_TDM_I2S_CH4_SEL_RR		(0x3 << 4) +#define RT5651_TDM_I2S_CH6_SEL_MASK		(0x3 << 2) +#define RT5651_TDM_I2S_CH6_SEL_SFT		2 +#define RT5651_TDM_I2S_CH6_SEL_LR		(0x0 << 2) +#define RT5651_TDM_I2S_CH6_SEL_RL		(0x1 << 2) +#define RT5651_TDM_I2S_CH6_SEL_LL		(0x2 << 2) +#define RT5651_TDM_I2S_CH6_SEL_RR		(0x3 << 2) +#define RT5651_TDM_I2S_CH8_SEL_MASK		(0x3) +#define RT5651_TDM_I2S_CH8_SEL_SFT		0 +#define RT5651_TDM_I2S_CH8_SEL_LR		(0x0) +#define RT5651_TDM_I2S_CH8_SEL_RL		(0x1) +#define RT5651_TDM_I2S_CH8_SEL_LL		(0x2) +#define RT5651_TDM_I2S_CH8_SEL_RR		(0x3) + +/* TDM Control 2 (0x78) */ +#define RT5651_TDM_LRCK_POL_SEL_MASK		(0x1 << 15) +#define RT5651_TDM_LRCK_POL_SEL_SFT		15 +#define RT5651_TDM_LRCK_POL_SEL_NOR		(0x0 << 15) +#define RT5651_TDM_LRCK_POL_SEL_INV		(0x1 << 15) +#define RT5651_TDM_CH_VAL_SEL_MASK		(0x1 << 14) +#define RT5651_TDM_CH_VAL_SEL_SFT		14 +#define RT5651_TDM_CH_VAL_SEL_CH01		(0x0 << 14) +#define RT5651_TDM_CH_VAL_SEL_CH0123		(0x1 << 14) +#define RT5651_TDM_CH_VAL_EN			(0x1 << 13) +#define RT5651_TDM_CH_VAL_SFT			13 +#define RT5651_TDM_LPBK_EN			(0x1 << 12) +#define RT5651_TDM_LPBK_SFT			12 +#define RT5651_TDM_LRCK_PULSE_SEL_MASK		(0x1 << 11) +#define RT5651_TDM_LRCK_PULSE_SEL_SFT		11 +#define RT5651_TDM_LRCK_PULSE_SEL_BCLK		(0x0 << 11) +#define RT5651_TDM_LRCK_PULSE_SEL_CH		(0x1 << 11) +#define RT5651_TDM_END_EDGE_SEL_MASK		(0x1 << 10) +#define RT5651_TDM_END_EDGE_SEL_SFT		10 +#define RT5651_TDM_END_EDGE_SEL_POS		(0x0 << 10) +#define RT5651_TDM_END_EDGE_SEL_NEG		(0x1 << 10) +#define RT5651_TDM_END_EDGE_EN			(0x1 << 9) +#define RT5651_TDM_END_EDGE_EN_SFT		9 +#define RT5651_TDM_TRAN_EDGE_SEL_MASK		(0x1 << 8) +#define RT5651_TDM_TRAN_EDGE_SEL_SFT		8 +#define RT5651_TDM_TRAN_EDGE_SEL_POS		(0x0 << 8) +#define RT5651_TDM_TRAN_EDGE_SEL_NEG		(0x1 << 8) +#define RT5651_M_TDM2_L				(0x1 << 7) +#define RT5651_M_TDM2_L_SFT			7 +#define RT5651_M_TDM2_R				(0x1 << 6) +#define RT5651_M_TDM2_R_SFT			6 +#define RT5651_M_TDM4_L				(0x1 << 5) +#define RT5651_M_TDM4_L_SFT			5 +#define RT5651_M_TDM4_R				(0x1 << 4) +#define RT5651_M_TDM4_R_SFT			4 + +/* TDM Control 3 (0x79) */ +#define RT5651_CH2_L_SEL_MASK			(0x7 << 12) +#define RT5651_CH2_L_SEL_SFT			12 +#define RT5651_CH2_L_SEL_SL0			(0x0 << 12) +#define RT5651_CH2_L_SEL_SL1			(0x1 << 12) +#define RT5651_CH2_L_SEL_SL2			(0x2 << 12) +#define RT5651_CH2_L_SEL_SL3			(0x3 << 12) +#define RT5651_CH2_L_SEL_SL4			(0x4 << 12) +#define RT5651_CH2_L_SEL_SL5			(0x5 << 12) +#define RT5651_CH2_L_SEL_SL6			(0x6 << 12) +#define RT5651_CH2_L_SEL_SL7			(0x7 << 12) +#define RT5651_CH2_R_SEL_MASK			(0x7 << 8) +#define RT5651_CH2_R_SEL_SFT			8 +#define RT5651_CH2_R_SEL_SL0			(0x0 << 8) +#define RT5651_CH2_R_SEL_SL1			(0x1 << 8) +#define RT5651_CH2_R_SEL_SL2			(0x2 << 8) +#define RT5651_CH2_R_SEL_SL3			(0x3 << 8) +#define RT5651_CH2_R_SEL_SL4			(0x4 << 8) +#define RT5651_CH2_R_SEL_SL5			(0x5 << 8) +#define RT5651_CH2_R_SEL_SL6			(0x6 << 8) +#define RT5651_CH2_R_SEL_SL7			(0x7 << 8) +#define RT5651_CH4_L_SEL_MASK			(0x7 << 4) +#define RT5651_CH4_L_SEL_SFT			4 +#define RT5651_CH4_L_SEL_SL0			(0x0 << 4) +#define RT5651_CH4_L_SEL_SL1			(0x1 << 4) +#define RT5651_CH4_L_SEL_SL2			(0x2 << 4) +#define RT5651_CH4_L_SEL_SL3			(0x3 << 4) +#define RT5651_CH4_L_SEL_SL4			(0x4 << 4) +#define RT5651_CH4_L_SEL_SL5			(0x5 << 4) +#define RT5651_CH4_L_SEL_SL6			(0x6 << 4) +#define RT5651_CH4_L_SEL_SL7			(0x7 << 4) +#define RT5651_CH4_R_SEL_MASK			(0x7) +#define RT5651_CH4_R_SEL_SFT			0 +#define RT5651_CH4_R_SEL_SL0			(0x0) +#define RT5651_CH4_R_SEL_SL1			(0x1) +#define RT5651_CH4_R_SEL_SL2			(0x2) +#define RT5651_CH4_R_SEL_SL3			(0x3) +#define RT5651_CH4_R_SEL_SL4			(0x4) +#define RT5651_CH4_R_SEL_SL5			(0x5) +#define RT5651_CH4_R_SEL_SL6			(0x6) +#define RT5651_CH4_R_SEL_SL7			(0x7) + +/* Global Clock Control (0x80) */ +#define RT5651_SCLK_SRC_MASK			(0x3 << 14) +#define RT5651_SCLK_SRC_SFT			14 +#define RT5651_SCLK_SRC_MCLK			(0x0 << 14) +#define RT5651_SCLK_SRC_PLL1			(0x1 << 14) +#define RT5651_SCLK_SRC_RCCLK			(0x2 << 14) +#define RT5651_PLL1_SRC_MASK			(0x3 << 12) +#define RT5651_PLL1_SRC_SFT			12 +#define RT5651_PLL1_SRC_MCLK			(0x0 << 12) +#define RT5651_PLL1_SRC_BCLK1			(0x1 << 12) +#define RT5651_PLL1_SRC_BCLK2			(0x2 << 12) +#define RT5651_PLL1_PD_MASK			(0x1 << 3) +#define RT5651_PLL1_PD_SFT			3 +#define RT5651_PLL1_PD_1			(0x0 << 3) +#define RT5651_PLL1_PD_2			(0x1 << 3) + +#define RT5651_PLL_INP_MAX			40000000 +#define RT5651_PLL_INP_MIN			256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5651_PLL_N_MAX			0x1ff +#define RT5651_PLL_N_MASK			(RT5651_PLL_N_MAX << 7) +#define RT5651_PLL_N_SFT			7 +#define RT5651_PLL_K_MAX			0x1f +#define RT5651_PLL_K_MASK			(RT5651_PLL_K_MAX) +#define RT5651_PLL_K_SFT			0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5651_PLL_M_MAX			0xf +#define RT5651_PLL_M_MASK			(RT5651_PLL_M_MAX << 12) +#define RT5651_PLL_M_SFT			12 +#define RT5651_PLL_M_BP				(0x1 << 11) +#define RT5651_PLL_M_BP_SFT			11 + +/* PLL tracking mode 1 (0x83) */ +#define RT5651_STO1_T_MASK			(0x1 << 15) +#define RT5651_STO1_T_SFT			15 +#define RT5651_STO1_T_SCLK			(0x0 << 15) +#define RT5651_STO1_T_LRCK1			(0x1 << 15) +#define RT5651_STO2_T_MASK			(0x1 << 12) +#define RT5651_STO2_T_SFT			12 +#define RT5651_STO2_T_I2S2			(0x0 << 12) +#define RT5651_STO2_T_LRCK2			(0x1 << 12) +#define RT5651_ASRC2_REF_MASK			(0x1 << 11) +#define RT5651_ASRC2_REF_SFT			11 +#define RT5651_ASRC2_REF_LRCK2			(0x0 << 11) +#define RT5651_ASRC2_REF_LRCK1			(0x1 << 11) +#define RT5651_DMIC_1_M_MASK			(0x1 << 9) +#define RT5651_DMIC_1_M_SFT			9 +#define RT5651_DMIC_1_M_NOR			(0x0 << 9) +#define RT5651_DMIC_1_M_ASYN			(0x1 << 9) + +/* PLL tracking mode 2 (0x84) */ +#define RT5651_STO1_ASRC_EN			(0x1 << 15) +#define RT5651_STO1_ASRC_EN_SFT			15 +#define RT5651_STO2_ASRC_EN			(0x1 << 14) +#define RT5651_STO2_ASRC_EN_SFT			14 +#define RT5651_STO1_DAC_M_MASK			(0x1 << 13) +#define RT5651_STO1_DAC_M_SFT			13 +#define RT5651_STO1_DAC_M_NOR			(0x0 << 13) +#define RT5651_STO1_DAC_M_ASRC			(0x1 << 13) +#define RT5651_STO2_DAC_M_MASK			(0x1 << 12) +#define RT5651_STO2_DAC_M_SFT			12 +#define RT5651_STO2_DAC_M_NOR			(0x0 << 12) +#define RT5651_STO2_DAC_M_ASRC			(0x1 << 12) +#define RT5651_ADC_M_MASK			(0x1 << 11) +#define RT5651_ADC_M_SFT			11 +#define RT5651_ADC_M_NOR			(0x0 << 11) +#define RT5651_ADC_M_ASRC			(0x1 << 11) +#define RT5651_I2S1_R_D_MASK			(0x1 << 4) +#define RT5651_I2S1_R_D_SFT			4 +#define RT5651_I2S1_R_D_DIS			(0x0 << 4) +#define RT5651_I2S1_R_D_EN			(0x1 << 4) +#define RT5651_I2S2_R_D_MASK			(0x1 << 3) +#define RT5651_I2S2_R_D_SFT			3 +#define RT5651_I2S2_R_D_DIS			(0x0 << 3) +#define RT5651_I2S2_R_D_EN			(0x1 << 3) +#define RT5651_PRE_SCLK_MASK			(0x3) +#define RT5651_PRE_SCLK_SFT			0 +#define RT5651_PRE_SCLK_512			(0x0) +#define RT5651_PRE_SCLK_1024			(0x1) +#define RT5651_PRE_SCLK_2048			(0x2) + +/* PLL tracking mode 3 (0x85) */ +#define RT5651_I2S1_RATE_MASK			(0xf << 12) +#define RT5651_I2S1_RATE_SFT			12 +#define RT5651_I2S2_RATE_MASK			(0xf << 8) +#define RT5651_I2S2_RATE_SFT			8 +#define RT5651_G_ASRC_LP_MASK			(0x1 << 3) +#define RT5651_G_ASRC_LP_SFT			3 +#define RT5651_ASRC_LP_F_M			(0x1 << 2) +#define RT5651_ASRC_LP_F_SFT			2 +#define RT5651_ASRC_LP_F_NOR			(0x0 << 2) +#define RT5651_ASRC_LP_F_SB			(0x1 << 2) +#define RT5651_FTK_PH_DET_MASK			(0x3) +#define RT5651_FTK_PH_DET_SFT			0 +#define RT5651_FTK_PH_DET_DIV1			(0x0) +#define RT5651_FTK_PH_DET_DIV2			(0x1) +#define RT5651_FTK_PH_DET_DIV4			(0x2) +#define RT5651_FTK_PH_DET_DIV8			(0x3) + +/*PLL tracking mode 6 (0x89) */ +#define RT5651_I2S1_PD_MASK			(0x7 << 12) +#define RT5651_I2S1_PD_SFT			12 +#define RT5651_I2S2_PD_MASK			(0x7 << 8) +#define RT5651_I2S2_PD_SFT			8 + +/*PLL tracking mode 7 (0x8a) */ +#define RT5651_FSI1_RATE_MASK			(0xf << 12) +#define RT5651_FSI1_RATE_SFT			12 +#define RT5651_FSI2_RATE_MASK			(0xf << 8) +#define RT5651_FSI2_RATE_SFT			8 + +/* HPOUT Over Current Detection (0x8b) */ +#define RT5651_HP_OVCD_MASK			(0x1 << 10) +#define RT5651_HP_OVCD_SFT			10 +#define RT5651_HP_OVCD_DIS			(0x0 << 10) +#define RT5651_HP_OVCD_EN			(0x1 << 10) +#define RT5651_HP_OC_TH_MASK			(0x3 << 8) +#define RT5651_HP_OC_TH_SFT			8 +#define RT5651_HP_OC_TH_90			(0x0 << 8) +#define RT5651_HP_OC_TH_105			(0x1 << 8) +#define RT5651_HP_OC_TH_120			(0x2 << 8) +#define RT5651_HP_OC_TH_135			(0x3 << 8) + +/* Depop Mode Control 1 (0x8e) */ +#define RT5651_SMT_TRIG_MASK			(0x1 << 15) +#define RT5651_SMT_TRIG_SFT			15 +#define RT5651_SMT_TRIG_DIS			(0x0 << 15) +#define RT5651_SMT_TRIG_EN			(0x1 << 15) +#define RT5651_HP_L_SMT_MASK			(0x1 << 9) +#define RT5651_HP_L_SMT_SFT			9 +#define RT5651_HP_L_SMT_DIS			(0x0 << 9) +#define RT5651_HP_L_SMT_EN			(0x1 << 9) +#define RT5651_HP_R_SMT_MASK			(0x1 << 8) +#define RT5651_HP_R_SMT_SFT			8 +#define RT5651_HP_R_SMT_DIS			(0x0 << 8) +#define RT5651_HP_R_SMT_EN			(0x1 << 8) +#define RT5651_HP_CD_PD_MASK			(0x1 << 7) +#define RT5651_HP_CD_PD_SFT			7 +#define RT5651_HP_CD_PD_DIS			(0x0 << 7) +#define RT5651_HP_CD_PD_EN			(0x1 << 7) +#define RT5651_RSTN_MASK			(0x1 << 6) +#define RT5651_RSTN_SFT				6 +#define RT5651_RSTN_DIS				(0x0 << 6) +#define RT5651_RSTN_EN				(0x1 << 6) +#define RT5651_RSTP_MASK			(0x1 << 5) +#define RT5651_RSTP_SFT				5 +#define RT5651_RSTP_DIS				(0x0 << 5) +#define RT5651_RSTP_EN				(0x1 << 5) +#define RT5651_HP_CO_MASK			(0x1 << 4) +#define RT5651_HP_CO_SFT			4 +#define RT5651_HP_CO_DIS			(0x0 << 4) +#define RT5651_HP_CO_EN				(0x1 << 4) +#define RT5651_HP_CP_MASK			(0x1 << 3) +#define RT5651_HP_CP_SFT			3 +#define RT5651_HP_CP_PD				(0x0 << 3) +#define RT5651_HP_CP_PU				(0x1 << 3) +#define RT5651_HP_SG_MASK			(0x1 << 2) +#define RT5651_HP_SG_SFT			2 +#define RT5651_HP_SG_DIS			(0x0 << 2) +#define RT5651_HP_SG_EN				(0x1 << 2) +#define RT5651_HP_DP_MASK			(0x1 << 1) +#define RT5651_HP_DP_SFT			1 +#define RT5651_HP_DP_PD				(0x0 << 1) +#define RT5651_HP_DP_PU				(0x1 << 1) +#define RT5651_HP_CB_MASK			(0x1) +#define RT5651_HP_CB_SFT			0 +#define RT5651_HP_CB_PD				(0x0) +#define RT5651_HP_CB_PU				(0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5651_DEPOP_MASK			(0x1 << 13) +#define RT5651_DEPOP_SFT			13 +#define RT5651_DEPOP_AUTO			(0x0 << 13) +#define RT5651_DEPOP_MAN			(0x1 << 13) +#define RT5651_RAMP_MASK			(0x1 << 12) +#define RT5651_RAMP_SFT				12 +#define RT5651_RAMP_DIS				(0x0 << 12) +#define RT5651_RAMP_EN				(0x1 << 12) +#define RT5651_BPS_MASK				(0x1 << 11) +#define RT5651_BPS_SFT				11 +#define RT5651_BPS_DIS				(0x0 << 11) +#define RT5651_BPS_EN				(0x1 << 11) +#define RT5651_FAST_UPDN_MASK			(0x1 << 10) +#define RT5651_FAST_UPDN_SFT			10 +#define RT5651_FAST_UPDN_DIS			(0x0 << 10) +#define RT5651_FAST_UPDN_EN			(0x1 << 10) +#define RT5651_MRES_MASK			(0x3 << 8) +#define RT5651_MRES_SFT				8 +#define RT5651_MRES_15MO			(0x0 << 8) +#define RT5651_MRES_25MO			(0x1 << 8) +#define RT5651_MRES_35MO			(0x2 << 8) +#define RT5651_MRES_45MO			(0x3 << 8) +#define RT5651_VLO_MASK				(0x1 << 7) +#define RT5651_VLO_SFT				7 +#define RT5651_VLO_3V				(0x0 << 7) +#define RT5651_VLO_32V				(0x1 << 7) +#define RT5651_DIG_DP_MASK			(0x1 << 6) +#define RT5651_DIG_DP_SFT			6 +#define RT5651_DIG_DP_DIS			(0x0 << 6) +#define RT5651_DIG_DP_EN			(0x1 << 6) +#define RT5651_DP_TH_MASK			(0x3 << 4) +#define RT5651_DP_TH_SFT			4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5651_CP_SYS_MASK			(0x7 << 12) +#define RT5651_CP_SYS_SFT			12 +#define RT5651_CP_FQ1_MASK			(0x7 << 8) +#define RT5651_CP_FQ1_SFT			8 +#define RT5651_CP_FQ2_MASK			(0x7 << 4) +#define RT5651_CP_FQ2_SFT			4 +#define RT5651_CP_FQ3_MASK			(0x7) +#define RT5651_CP_FQ3_SFT			0 +#define RT5651_CP_FQ_1_5_KHZ			0 +#define RT5651_CP_FQ_3_KHZ			1 +#define RT5651_CP_FQ_6_KHZ			2 +#define RT5651_CP_FQ_12_KHZ			3 +#define RT5651_CP_FQ_24_KHZ			4 +#define RT5651_CP_FQ_48_KHZ			5 +#define RT5651_CP_FQ_96_KHZ			6 +#define RT5651_CP_FQ_192_KHZ			7 + +/* HPOUT charge pump (0x91) */ +#define RT5651_OSW_L_MASK			(0x1 << 11) +#define RT5651_OSW_L_SFT			11 +#define RT5651_OSW_L_DIS			(0x0 << 11) +#define RT5651_OSW_L_EN				(0x1 << 11) +#define RT5651_OSW_R_MASK			(0x1 << 10) +#define RT5651_OSW_R_SFT			10 +#define RT5651_OSW_R_DIS			(0x0 << 10) +#define RT5651_OSW_R_EN				(0x1 << 10) +#define RT5651_PM_HP_MASK			(0x3 << 8) +#define RT5651_PM_HP_SFT			8 +#define RT5651_PM_HP_LV				(0x0 << 8) +#define RT5651_PM_HP_MV				(0x1 << 8) +#define RT5651_PM_HP_HV				(0x2 << 8) +#define RT5651_IB_HP_MASK			(0x3 << 6) +#define RT5651_IB_HP_SFT			6 +#define RT5651_IB_HP_125IL			(0x0 << 6) +#define RT5651_IB_HP_25IL			(0x1 << 6) +#define RT5651_IB_HP_5IL			(0x2 << 6) +#define RT5651_IB_HP_1IL			(0x3 << 6) + +/* Micbias Control (0x93) */ +#define RT5651_MIC1_BS_MASK			(0x1 << 15) +#define RT5651_MIC1_BS_SFT			15 +#define RT5651_MIC1_BS_9AV			(0x0 << 15) +#define RT5651_MIC1_BS_75AV			(0x1 << 15) +#define RT5651_MIC1_CLK_MASK			(0x1 << 13) +#define RT5651_MIC1_CLK_SFT			13 +#define RT5651_MIC1_CLK_DIS			(0x0 << 13) +#define RT5651_MIC1_CLK_EN			(0x1 << 13) +#define RT5651_MIC1_OVCD_MASK			(0x1 << 11) +#define RT5651_MIC1_OVCD_SFT			11 +#define RT5651_MIC1_OVCD_DIS			(0x0 << 11) +#define RT5651_MIC1_OVCD_EN			(0x1 << 11) +#define RT5651_MIC1_OVTH_MASK			(0x3 << 9) +#define RT5651_MIC1_OVTH_SFT			9 +#define RT5651_MIC1_OVTH_600UA			(0x0 << 9) +#define RT5651_MIC1_OVTH_1500UA			(0x1 << 9) +#define RT5651_MIC1_OVTH_2000UA			(0x2 << 9) +#define RT5651_PWR_MB_MASK			(0x1 << 5) +#define RT5651_PWR_MB_SFT			5 +#define RT5651_PWR_MB_PD			(0x0 << 5) +#define RT5651_PWR_MB_PU			(0x1 << 5) +#define RT5651_PWR_CLK12M_MASK			(0x1 << 4) +#define RT5651_PWR_CLK12M_SFT			4 +#define RT5651_PWR_CLK12M_PD			(0x0 << 4) +#define RT5651_PWR_CLK12M_PU			(0x1 << 4) + +/* Analog JD Control 1 (0x94) */ +#define RT5651_JD2_CMP_MASK			(0x7 << 12) +#define RT5651_JD2_CMP_SFT			12 +#define RT5651_JD_PU				(0x1 << 11) +#define RT5651_JD_PU_SFT			11 +#define RT5651_JD_PD				(0x1 << 10) +#define RT5651_JD_PD_SFT			10 +#define RT5651_JD_MODE_SEL_MASK			(0x3 << 8) +#define RT5651_JD_MODE_SEL_SFT			8 +#define RT5651_JD_MODE_SEL_M0			(0x0 << 8) +#define RT5651_JD_MODE_SEL_M1			(0x1 << 8) +#define RT5651_JD_MODE_SEL_M2			(0x2 << 8) +#define RT5651_JD_M_CMP				(0x7 << 4) +#define RT5651_JD_M_CMP_SFT			4 +#define RT5651_JD_M_PU				(0x1 << 3) +#define RT5651_JD_M_PU_SFT			3 +#define RT5651_JD_M_PD				(0x1 << 2) +#define RT5651_JD_M_PD_SFT			2 +#define RT5651_JD_M_MODE_SEL_MASK		(0x3) +#define RT5651_JD_M_MODE_SEL_SFT		0 +#define RT5651_JD_M_MODE_SEL_M0			(0x0) +#define RT5651_JD_M_MODE_SEL_M1			(0x1) +#define RT5651_JD_M_MODE_SEL_M2			(0x2) + +/* Analog JD Control 2 (0x95) */ +#define RT5651_JD3_CMP_MASK			(0x7 << 12) +#define RT5651_JD3_CMP_SFT			12 + +/* EQ Control 1 (0xb0) */ +#define RT5651_EQ_SRC_MASK			(0x1 << 15) +#define RT5651_EQ_SRC_SFT			15 +#define RT5651_EQ_SRC_DAC			(0x0 << 15) +#define RT5651_EQ_SRC_ADC			(0x1 << 15) +#define RT5651_EQ_UPD				(0x1 << 14) +#define RT5651_EQ_UPD_BIT			14 +#define RT5651_EQ_CD_MASK			(0x1 << 13) +#define RT5651_EQ_CD_SFT			13 +#define RT5651_EQ_CD_DIS			(0x0 << 13) +#define RT5651_EQ_CD_EN				(0x1 << 13) +#define RT5651_EQ_DITH_MASK			(0x3 << 8) +#define RT5651_EQ_DITH_SFT			8 +#define RT5651_EQ_DITH_NOR			(0x0 << 8) +#define RT5651_EQ_DITH_LSB			(0x1 << 8) +#define RT5651_EQ_DITH_LSB_1			(0x2 << 8) +#define RT5651_EQ_DITH_LSB_2			(0x3 << 8) +#define RT5651_EQ_CD_F				(0x1 << 7) +#define RT5651_EQ_CD_F_BIT			7 +#define RT5651_EQ_STA_HP2			(0x1 << 6) +#define RT5651_EQ_STA_HP2_BIT			6 +#define RT5651_EQ_STA_HP1			(0x1 << 5) +#define RT5651_EQ_STA_HP1_BIT			5 +#define RT5651_EQ_STA_BP4			(0x1 << 4) +#define RT5651_EQ_STA_BP4_BIT			4 +#define RT5651_EQ_STA_BP3			(0x1 << 3) +#define RT5651_EQ_STA_BP3_BIT			3 +#define RT5651_EQ_STA_BP2			(0x1 << 2) +#define RT5651_EQ_STA_BP2_BIT			2 +#define RT5651_EQ_STA_BP1			(0x1 << 1) +#define RT5651_EQ_STA_BP1_BIT			1 +#define RT5651_EQ_STA_LP			(0x1) +#define RT5651_EQ_STA_LP_BIT			0 + +/* EQ Control 2 (0xb1) */ +#define RT5651_EQ_HPF1_M_MASK			(0x1 << 8) +#define RT5651_EQ_HPF1_M_SFT			8 +#define RT5651_EQ_HPF1_M_HI			(0x0 << 8) +#define RT5651_EQ_HPF1_M_1ST			(0x1 << 8) +#define RT5651_EQ_LPF1_M_MASK			(0x1 << 7) +#define RT5651_EQ_LPF1_M_SFT			7 +#define RT5651_EQ_LPF1_M_LO			(0x0 << 7) +#define RT5651_EQ_LPF1_M_1ST			(0x1 << 7) +#define RT5651_EQ_HPF2_MASK			(0x1 << 6) +#define RT5651_EQ_HPF2_SFT			6 +#define RT5651_EQ_HPF2_DIS			(0x0 << 6) +#define RT5651_EQ_HPF2_EN			(0x1 << 6) +#define RT5651_EQ_HPF1_MASK			(0x1 << 5) +#define RT5651_EQ_HPF1_SFT			5 +#define RT5651_EQ_HPF1_DIS			(0x0 << 5) +#define RT5651_EQ_HPF1_EN			(0x1 << 5) +#define RT5651_EQ_BPF4_MASK			(0x1 << 4) +#define RT5651_EQ_BPF4_SFT			4 +#define RT5651_EQ_BPF4_DIS			(0x0 << 4) +#define RT5651_EQ_BPF4_EN			(0x1 << 4) +#define RT5651_EQ_BPF3_MASK			(0x1 << 3) +#define RT5651_EQ_BPF3_SFT			3 +#define RT5651_EQ_BPF3_DIS			(0x0 << 3) +#define RT5651_EQ_BPF3_EN			(0x1 << 3) +#define RT5651_EQ_BPF2_MASK			(0x1 << 2) +#define RT5651_EQ_BPF2_SFT			2 +#define RT5651_EQ_BPF2_DIS			(0x0 << 2) +#define RT5651_EQ_BPF2_EN			(0x1 << 2) +#define RT5651_EQ_BPF1_MASK			(0x1 << 1) +#define RT5651_EQ_BPF1_SFT			1 +#define RT5651_EQ_BPF1_DIS			(0x0 << 1) +#define RT5651_EQ_BPF1_EN			(0x1 << 1) +#define RT5651_EQ_LPF_MASK			(0x1) +#define RT5651_EQ_LPF_SFT			0 +#define RT5651_EQ_LPF_DIS			(0x0) +#define RT5651_EQ_LPF_EN			(0x1) +#define RT5651_EQ_CTRL_MASK			(0x7f) + +/* Memory Test (0xb2) */ +#define RT5651_MT_MASK				(0x1 << 15) +#define RT5651_MT_SFT				15 +#define RT5651_MT_DIS				(0x0 << 15) +#define RT5651_MT_EN				(0x1 << 15) + +/* ALC Control 1 (0xb4) */ +#define RT5651_ALC_P_MASK			(0x1 << 15) +#define RT5651_ALC_P_SFT			15 +#define RT5651_ALC_P_DAC			(0x0 << 15) +#define RT5651_ALC_P_ADC			(0x1 << 15) +#define RT5651_ALC_MASK				(0x1 << 14) +#define RT5651_ALC_SFT				14 +#define RT5651_ALC_DIS				(0x0 << 14) +#define RT5651_ALC_EN				(0x1 << 14) +#define RT5651_ALC_UPD				(0x1 << 13) +#define RT5651_ALC_UPD_BIT			13 +#define RT5651_ALC_AR_MASK			(0x1f << 8) +#define RT5651_ALC_AR_SFT			8 +#define RT5651_ALC_R_MASK			(0x7 << 5) +#define RT5651_ALC_R_SFT			5 +#define RT5651_ALC_R_48K			(0x1 << 5) +#define RT5651_ALC_R_96K			(0x2 << 5) +#define RT5651_ALC_R_192K			(0x3 << 5) +#define RT5651_ALC_R_441K			(0x5 << 5) +#define RT5651_ALC_R_882K			(0x6 << 5) +#define RT5651_ALC_R_1764K			(0x7 << 5) +#define RT5651_ALC_RC_MASK			(0x1f) +#define RT5651_ALC_RC_SFT			0 + +/* ALC Control 2 (0xb5) */ +#define RT5651_ALC_POB_MASK			(0x3f << 8) +#define RT5651_ALC_POB_SFT			8 +#define RT5651_ALC_DRC_MASK			(0x1 << 7) +#define RT5651_ALC_DRC_SFT			7 +#define RT5651_ALC_DRC_DIS			(0x0 << 7) +#define RT5651_ALC_DRC_EN			(0x1 << 7) +#define RT5651_ALC_CPR_MASK			(0x3 << 5) +#define RT5651_ALC_CPR_SFT			5 +#define RT5651_ALC_CPR_1_1			(0x0 << 5) +#define RT5651_ALC_CPR_1_2			(0x1 << 5) +#define RT5651_ALC_CPR_1_4			(0x2 << 5) +#define RT5651_ALC_CPR_1_8			(0x3 << 5) +#define RT5651_ALC_PRB_MASK			(0x1f) +#define RT5651_ALC_PRB_SFT			0 + +/* ALC Control 3 (0xb6) */ +#define RT5651_ALC_NGB_MASK			(0xf << 12) +#define RT5651_ALC_NGB_SFT			12 +#define RT5651_ALC_TAR_MASK			(0x1f << 7) +#define RT5651_ALC_TAR_SFT			7 +#define RT5651_ALC_NG_MASK			(0x1 << 6) +#define RT5651_ALC_NG_SFT			6 +#define RT5651_ALC_NG_DIS			(0x0 << 6) +#define RT5651_ALC_NG_EN			(0x1 << 6) +#define RT5651_ALC_NGH_MASK			(0x1 << 5) +#define RT5651_ALC_NGH_SFT			5 +#define RT5651_ALC_NGH_DIS			(0x0 << 5) +#define RT5651_ALC_NGH_EN			(0x1 << 5) +#define RT5651_ALC_NGT_MASK			(0x1f) +#define RT5651_ALC_NGT_SFT			0 + +/* Jack Detect Control 1 (0xbb) */ +#define RT5651_JD_MASK				(0x7 << 13) +#define RT5651_JD_SFT				13 +#define RT5651_JD_DIS				(0x0 << 13) +#define RT5651_JD_GPIO1				(0x1 << 13) +#define RT5651_JD_GPIO2				(0x2 << 13) +#define RT5651_JD_GPIO3				(0x3 << 13) +#define RT5651_JD_GPIO4				(0x4 << 13) +#define RT5651_JD_GPIO5				(0x5 << 13) +#define RT5651_JD_GPIO6				(0x6 << 13) +#define RT5651_JD_HP_MASK			(0x1 << 11) +#define RT5651_JD_HP_SFT			11 +#define RT5651_JD_HP_DIS			(0x0 << 11) +#define RT5651_JD_HP_EN				(0x1 << 11) +#define RT5651_JD_HP_TRG_MASK			(0x1 << 10) +#define RT5651_JD_HP_TRG_SFT			10 +#define RT5651_JD_HP_TRG_LO			(0x0 << 10) +#define RT5651_JD_HP_TRG_HI			(0x1 << 10) +#define RT5651_JD_SPL_MASK			(0x1 << 9) +#define RT5651_JD_SPL_SFT			9 +#define RT5651_JD_SPL_DIS			(0x0 << 9) +#define RT5651_JD_SPL_EN			(0x1 << 9) +#define RT5651_JD_SPL_TRG_MASK			(0x1 << 8) +#define RT5651_JD_SPL_TRG_SFT			8 +#define RT5651_JD_SPL_TRG_LO			(0x0 << 8) +#define RT5651_JD_SPL_TRG_HI			(0x1 << 8) +#define RT5651_JD_SPR_MASK			(0x1 << 7) +#define RT5651_JD_SPR_SFT			7 +#define RT5651_JD_SPR_DIS			(0x0 << 7) +#define RT5651_JD_SPR_EN			(0x1 << 7) +#define RT5651_JD_SPR_TRG_MASK			(0x1 << 6) +#define RT5651_JD_SPR_TRG_SFT			6 +#define RT5651_JD_SPR_TRG_LO			(0x0 << 6) +#define RT5651_JD_SPR_TRG_HI			(0x1 << 6) +#define RT5651_JD_LO_MASK			(0x1 << 3) +#define RT5651_JD_LO_SFT			3 +#define RT5651_JD_LO_DIS			(0x0 << 3) +#define RT5651_JD_LO_EN				(0x1 << 3) +#define RT5651_JD_LO_TRG_MASK			(0x1 << 2) +#define RT5651_JD_LO_TRG_SFT			2 +#define RT5651_JD_LO_TRG_LO			(0x0 << 2) +#define RT5651_JD_LO_TRG_HI			(0x1 << 2) + +/* Jack Detect Control 2 (0xbc) */ +#define RT5651_JD_TRG_SEL_MASK			(0x7 << 9) +#define RT5651_JD_TRG_SEL_SFT			9 +#define RT5651_JD_TRG_SEL_GPIO			(0x0 << 9) +#define RT5651_JD_TRG_SEL_JD1_1			(0x1 << 9) +#define RT5651_JD_TRG_SEL_JD1_2			(0x2 << 9) +#define RT5651_JD_TRG_SEL_JD2			(0x3 << 9) +#define RT5651_JD_TRG_SEL_JD3			(0x4 << 9) +#define RT5651_JD3_IRQ_EN			(0x1 << 8) +#define RT5651_JD3_IRQ_EN_SFT			8 +#define RT5651_JD3_EN_STKY			(0x1 << 7) +#define RT5651_JD3_EN_STKY_SFT			7 +#define RT5651_JD3_INV				(0x1 << 6) +#define RT5651_JD3_INV_SFT			6 + +/* IRQ Control 1 (0xbd) */ +#define RT5651_IRQ_JD_MASK			(0x1 << 15) +#define RT5651_IRQ_JD_SFT			15 +#define RT5651_IRQ_JD_BP			(0x0 << 15) +#define RT5651_IRQ_JD_NOR			(0x1 << 15) +#define RT5651_JD_STKY_MASK			(0x1 << 13) +#define RT5651_JD_STKY_SFT			13 +#define RT5651_JD_STKY_DIS			(0x0 << 13) +#define RT5651_JD_STKY_EN			(0x1 << 13) +#define RT5651_JD_P_MASK			(0x1 << 11) +#define RT5651_JD_P_SFT				11 +#define RT5651_JD_P_NOR				(0x0 << 11) +#define RT5651_JD_P_INV				(0x1 << 11) +#define RT5651_JD1_1_IRQ_EN			(0x1 << 9) +#define RT5651_JD1_1_IRQ_EN_SFT			9 +#define RT5651_JD1_1_EN_STKY			(0x1 << 8) +#define RT5651_JD1_1_EN_STKY_SFT			8 +#define RT5651_JD1_1_INV			(0x1 << 7) +#define RT5651_JD1_1_INV_SFT			7 +#define RT5651_JD1_2_IRQ_EN			(0x1 << 6) +#define RT5651_JD1_2_IRQ_EN_SFT			6 +#define RT5651_JD1_2_EN_STKY			(0x1 << 5) +#define RT5651_JD1_2_EN_STKY_SFT			5 +#define RT5651_JD1_2_INV			(0x1 << 4) +#define RT5651_JD1_2_INV_SFT			4 +#define RT5651_JD2_IRQ_EN			(0x1 << 3) +#define RT5651_JD2_IRQ_EN_SFT			3 +#define RT5651_JD2_EN_STKY			(0x1 << 2) +#define RT5651_JD2_EN_STKY_SFT			2 +#define RT5651_JD2_INV				(0x1 << 1) +#define RT5651_JD2_INV_SFT			1 + +/* IRQ Control 2 (0xbe) */ +#define RT5651_IRQ_MB1_OC_MASK			(0x1 << 15) +#define RT5651_IRQ_MB1_OC_SFT			15 +#define RT5651_IRQ_MB1_OC_BP			(0x0 << 15) +#define RT5651_IRQ_MB1_OC_NOR			(0x1 << 15) +#define RT5651_MB1_OC_STKY_MASK			(0x1 << 11) +#define RT5651_MB1_OC_STKY_SFT			11 +#define RT5651_MB1_OC_STKY_DIS			(0x0 << 11) +#define RT5651_MB1_OC_STKY_EN			(0x1 << 11) +#define RT5651_MB1_OC_P_MASK			(0x1 << 7) +#define RT5651_MB1_OC_P_SFT			7 +#define RT5651_MB1_OC_P_NOR			(0x0 << 7) +#define RT5651_MB1_OC_P_INV			(0x1 << 7) +#define RT5651_MB2_OC_P_MASK			(0x1 << 6) +#define RT5651_MB1_OC_CLR			(0x1 << 3) +#define RT5651_MB1_OC_CLR_SFT			3 +#define RT5651_STA_GPIO8			(0x1) +#define RT5651_STA_GPIO8_BIT			0 + +/* Internal Status and GPIO status (0xbf) */ +#define RT5651_STA_JD3				(0x1 << 15) +#define RT5651_STA_JD3_BIT			15 +#define RT5651_STA_JD2				(0x1 << 14) +#define RT5651_STA_JD2_BIT			14 +#define RT5651_STA_JD1_2			(0x1 << 13) +#define RT5651_STA_JD1_2_BIT			13 +#define RT5651_STA_JD1_1			(0x1 << 12) +#define RT5651_STA_JD1_1_BIT			12 +#define RT5651_STA_GP7				(0x1 << 11) +#define RT5651_STA_GP7_BIT			11 +#define RT5651_STA_GP6				(0x1 << 10) +#define RT5651_STA_GP6_BIT			10 +#define RT5651_STA_GP5				(0x1 << 9) +#define RT5651_STA_GP5_BIT			9 +#define RT5651_STA_GP1				(0x1 << 8) +#define RT5651_STA_GP1_BIT			8 +#define RT5651_STA_GP2				(0x1 << 7) +#define RT5651_STA_GP2_BIT			7 +#define RT5651_STA_GP3				(0x1 << 6) +#define RT5651_STA_GP3_BIT			6 +#define RT5651_STA_GP4				(0x1 << 5) +#define RT5651_STA_GP4_BIT			5 +#define RT5651_STA_GP_JD			(0x1 << 4) +#define RT5651_STA_GP_JD_BIT			4 + +/* GPIO Control 1 (0xc0) */ +#define RT5651_GP1_PIN_MASK			(0x1 << 15) +#define RT5651_GP1_PIN_SFT			15 +#define RT5651_GP1_PIN_GPIO1			(0x0 << 15) +#define RT5651_GP1_PIN_IRQ			(0x1 << 15) +#define RT5651_GP2_PIN_MASK			(0x1 << 14) +#define RT5651_GP2_PIN_SFT			14 +#define RT5651_GP2_PIN_GPIO2			(0x0 << 14) +#define RT5651_GP2_PIN_DMIC1_SCL		(0x1 << 14) +#define RT5651_GPIO_M_MASK			(0x1 << 9) +#define RT5651_GPIO_M_SFT			9 +#define RT5651_GPIO_M_FLT			(0x0 << 9) +#define RT5651_GPIO_M_PH			(0x1 << 9) +#define RT5651_I2S2_SEL_MASK			(0x1 << 8) +#define RT5651_I2S2_SEL_SFT			8 +#define RT5651_I2S2_SEL_I2S			(0x0 << 8) +#define RT5651_I2S2_SEL_GPIO			(0x1 << 8) +#define RT5651_GP5_PIN_MASK			(0x1 << 7) +#define RT5651_GP5_PIN_SFT			7 +#define RT5651_GP5_PIN_GPIO5			(0x0 << 7) +#define RT5651_GP5_PIN_IRQ			(0x1 << 7) +#define RT5651_GP6_PIN_MASK			(0x1 << 6) +#define RT5651_GP6_PIN_SFT			6 +#define RT5651_GP6_PIN_GPIO6			(0x0 << 6) +#define RT5651_GP6_PIN_DMIC_SDA			(0x1 << 6) +#define RT5651_GP7_PIN_MASK			(0x1 << 5) +#define RT5651_GP7_PIN_SFT			5 +#define RT5651_GP7_PIN_GPIO7			(0x0 << 5) +#define RT5651_GP7_PIN_IRQ			(0x1 << 5) +#define RT5651_GP8_PIN_MASK			(0x1 << 4) +#define RT5651_GP8_PIN_SFT			4 +#define RT5651_GP8_PIN_GPIO8			(0x0 << 4) +#define RT5651_GP8_PIN_DMIC_SDA			(0x1 << 4) +#define RT5651_GPIO_PDM_SEL_MASK		(0x1 << 3) +#define RT5651_GPIO_PDM_SEL_SFT			3 +#define RT5651_GPIO_PDM_SEL_GPIO		(0x0 << 3) +#define RT5651_GPIO_PDM_SEL_PDM			(0x1 << 3) + +/* GPIO Control 2 (0xc1) */ +#define RT5651_GP5_DR_MASK			(0x1 << 14) +#define RT5651_GP5_DR_SFT			14 +#define RT5651_GP5_DR_IN			(0x0 << 14) +#define RT5651_GP5_DR_OUT			(0x1 << 14) +#define RT5651_GP5_OUT_MASK			(0x1 << 13) +#define RT5651_GP5_OUT_SFT			13 +#define RT5651_GP5_OUT_LO			(0x0 << 13) +#define RT5651_GP5_OUT_HI			(0x1 << 13) +#define RT5651_GP5_P_MASK			(0x1 << 12) +#define RT5651_GP5_P_SFT			12 +#define RT5651_GP5_P_NOR			(0x0 << 12) +#define RT5651_GP5_P_INV			(0x1 << 12) +#define RT5651_GP4_DR_MASK			(0x1 << 11) +#define RT5651_GP4_DR_SFT			11 +#define RT5651_GP4_DR_IN			(0x0 << 11) +#define RT5651_GP4_DR_OUT			(0x1 << 11) +#define RT5651_GP4_OUT_MASK			(0x1 << 10) +#define RT5651_GP4_OUT_SFT			10 +#define RT5651_GP4_OUT_LO			(0x0 << 10) +#define RT5651_GP4_OUT_HI			(0x1 << 10) +#define RT5651_GP4_P_MASK			(0x1 << 9) +#define RT5651_GP4_P_SFT			9 +#define RT5651_GP4_P_NOR			(0x0 << 9) +#define RT5651_GP4_P_INV			(0x1 << 9) +#define RT5651_GP3_DR_MASK			(0x1 << 8) +#define RT5651_GP3_DR_SFT			8 +#define RT5651_GP3_DR_IN			(0x0 << 8) +#define RT5651_GP3_DR_OUT			(0x1 << 8) +#define RT5651_GP3_OUT_MASK			(0x1 << 7) +#define RT5651_GP3_OUT_SFT			7 +#define RT5651_GP3_OUT_LO			(0x0 << 7) +#define RT5651_GP3_OUT_HI			(0x1 << 7) +#define RT5651_GP3_P_MASK			(0x1 << 6) +#define RT5651_GP3_P_SFT			6 +#define RT5651_GP3_P_NOR			(0x0 << 6) +#define RT5651_GP3_P_INV			(0x1 << 6) +#define RT5651_GP2_DR_MASK			(0x1 << 5) +#define RT5651_GP2_DR_SFT			5 +#define RT5651_GP2_DR_IN			(0x0 << 5) +#define RT5651_GP2_DR_OUT			(0x1 << 5) +#define RT5651_GP2_OUT_MASK			(0x1 << 4) +#define RT5651_GP2_OUT_SFT			4 +#define RT5651_GP2_OUT_LO			(0x0 << 4) +#define RT5651_GP2_OUT_HI			(0x1 << 4) +#define RT5651_GP2_P_MASK			(0x1 << 3) +#define RT5651_GP2_P_SFT			3 +#define RT5651_GP2_P_NOR			(0x0 << 3) +#define RT5651_GP2_P_INV			(0x1 << 3) +#define RT5651_GP1_DR_MASK			(0x1 << 2) +#define RT5651_GP1_DR_SFT			2 +#define RT5651_GP1_DR_IN			(0x0 << 2) +#define RT5651_GP1_DR_OUT			(0x1 << 2) +#define RT5651_GP1_OUT_MASK			(0x1 << 1) +#define RT5651_GP1_OUT_SFT			1 +#define RT5651_GP1_OUT_LO			(0x0 << 1) +#define RT5651_GP1_OUT_HI			(0x1 << 1) +#define RT5651_GP1_P_MASK			(0x1) +#define RT5651_GP1_P_SFT			0 +#define RT5651_GP1_P_NOR			(0x0) +#define RT5651_GP1_P_INV			(0x1) + +/* GPIO Control 3 (0xc2) */ +#define RT5651_GP8_DR_MASK			(0x1 << 8) +#define RT5651_GP8_DR_SFT			8 +#define RT5651_GP8_DR_IN			(0x0 << 8) +#define RT5651_GP8_DR_OUT			(0x1 << 8) +#define RT5651_GP8_OUT_MASK			(0x1 << 7) +#define RT5651_GP8_OUT_SFT			7 +#define RT5651_GP8_OUT_LO			(0x0 << 7) +#define RT5651_GP8_OUT_HI			(0x1 << 7) +#define RT5651_GP8_P_MASK			(0x1 << 6) +#define RT5651_GP8_P_SFT			6 +#define RT5651_GP8_P_NOR			(0x0 << 6) +#define RT5651_GP8_P_INV			(0x1 << 6) +#define RT5651_GP7_DR_MASK			(0x1 << 5) +#define RT5651_GP7_DR_SFT			5 +#define RT5651_GP7_DR_IN			(0x0 << 5) +#define RT5651_GP7_DR_OUT			(0x1 << 5) +#define RT5651_GP7_OUT_MASK			(0x1 << 4) +#define RT5651_GP7_OUT_SFT			4 +#define RT5651_GP7_OUT_LO			(0x0 << 4) +#define RT5651_GP7_OUT_HI			(0x1 << 4) +#define RT5651_GP7_P_MASK			(0x1 << 3) +#define RT5651_GP7_P_SFT			3 +#define RT5651_GP7_P_NOR			(0x0 << 3) +#define RT5651_GP7_P_INV			(0x1 << 3) +#define RT5651_GP6_DR_MASK			(0x1 << 2) +#define RT5651_GP6_DR_SFT			2 +#define RT5651_GP6_DR_IN			(0x0 << 2) +#define RT5651_GP6_DR_OUT			(0x1 << 2) +#define RT5651_GP6_OUT_MASK			(0x1 << 1) +#define RT5651_GP6_OUT_SFT			1 +#define RT5651_GP6_OUT_LO			(0x0 << 1) +#define RT5651_GP6_OUT_HI			(0x1 << 1) +#define RT5651_GP6_P_MASK			(0x1) +#define RT5651_GP6_P_SFT			0 +#define RT5651_GP6_P_NOR			(0x0) +#define RT5651_GP6_P_INV			(0x1) + +/* Scramble Control (0xce) */ +#define RT5651_SCB_SWAP_MASK			(0x1 << 15) +#define RT5651_SCB_SWAP_SFT			15 +#define RT5651_SCB_SWAP_DIS			(0x0 << 15) +#define RT5651_SCB_SWAP_EN			(0x1 << 15) +#define RT5651_SCB_MASK				(0x1 << 14) +#define RT5651_SCB_SFT				14 +#define RT5651_SCB_DIS				(0x0 << 14) +#define RT5651_SCB_EN				(0x1 << 14) + +/* Baseback Control (0xcf) */ +#define RT5651_BB_MASK				(0x1 << 15) +#define RT5651_BB_SFT				15 +#define RT5651_BB_DIS				(0x0 << 15) +#define RT5651_BB_EN				(0x1 << 15) +#define RT5651_BB_CT_MASK			(0x7 << 12) +#define RT5651_BB_CT_SFT			12 +#define RT5651_BB_CT_A				(0x0 << 12) +#define RT5651_BB_CT_B				(0x1 << 12) +#define RT5651_BB_CT_C				(0x2 << 12) +#define RT5651_BB_CT_D				(0x3 << 12) +#define RT5651_M_BB_L_MASK			(0x1 << 9) +#define RT5651_M_BB_L_SFT			9 +#define RT5651_M_BB_R_MASK			(0x1 << 8) +#define RT5651_M_BB_R_SFT			8 +#define RT5651_M_BB_HPF_L_MASK			(0x1 << 7) +#define RT5651_M_BB_HPF_L_SFT			7 +#define RT5651_M_BB_HPF_R_MASK			(0x1 << 6) +#define RT5651_M_BB_HPF_R_SFT			6 +#define RT5651_G_BB_BST_MASK			(0x3f) +#define RT5651_G_BB_BST_SFT			0 + +/* MP3 Plus Control 1 (0xd0) */ +#define RT5651_M_MP3_L_MASK			(0x1 << 15) +#define RT5651_M_MP3_L_SFT			15 +#define RT5651_M_MP3_R_MASK			(0x1 << 14) +#define RT5651_M_MP3_R_SFT			14 +#define RT5651_M_MP3_MASK			(0x1 << 13) +#define RT5651_M_MP3_SFT			13 +#define RT5651_M_MP3_DIS			(0x0 << 13) +#define RT5651_M_MP3_EN				(0x1 << 13) +#define RT5651_EG_MP3_MASK			(0x1f << 8) +#define RT5651_EG_MP3_SFT			8 +#define RT5651_MP3_HLP_MASK			(0x1 << 7) +#define RT5651_MP3_HLP_SFT			7 +#define RT5651_MP3_HLP_DIS			(0x0 << 7) +#define RT5651_MP3_HLP_EN			(0x1 << 7) +#define RT5651_M_MP3_ORG_L_MASK			(0x1 << 6) +#define RT5651_M_MP3_ORG_L_SFT			6 +#define RT5651_M_MP3_ORG_R_MASK			(0x1 << 5) +#define RT5651_M_MP3_ORG_R_SFT			5 + +/* MP3 Plus Control 2 (0xd1) */ +#define RT5651_MP3_WT_MASK			(0x1 << 13) +#define RT5651_MP3_WT_SFT			13 +#define RT5651_MP3_WT_1_4			(0x0 << 13) +#define RT5651_MP3_WT_1_2			(0x1 << 13) +#define RT5651_OG_MP3_MASK			(0x1f << 8) +#define RT5651_OG_MP3_SFT			8 +#define RT5651_HG_MP3_MASK			(0x3f) +#define RT5651_HG_MP3_SFT			0 + +/* 3D HP Control 1 (0xd2) */ +#define RT5651_3D_CF_MASK			(0x1 << 15) +#define RT5651_3D_CF_SFT			15 +#define RT5651_3D_CF_DIS			(0x0 << 15) +#define RT5651_3D_CF_EN				(0x1 << 15) +#define RT5651_3D_HP_MASK			(0x1 << 14) +#define RT5651_3D_HP_SFT			14 +#define RT5651_3D_HP_DIS			(0x0 << 14) +#define RT5651_3D_HP_EN				(0x1 << 14) +#define RT5651_3D_BT_MASK			(0x1 << 13) +#define RT5651_3D_BT_SFT			13 +#define RT5651_3D_BT_DIS			(0x0 << 13) +#define RT5651_3D_BT_EN				(0x1 << 13) +#define RT5651_3D_1F_MIX_MASK			(0x3 << 11) +#define RT5651_3D_1F_MIX_SFT			11 +#define RT5651_3D_HP_M_MASK			(0x1 << 10) +#define RT5651_3D_HP_M_SFT			10 +#define RT5651_3D_HP_M_SUR			(0x0 << 10) +#define RT5651_3D_HP_M_FRO			(0x1 << 10) +#define RT5651_M_3D_HRTF_MASK			(0x1 << 9) +#define RT5651_M_3D_HRTF_SFT			9 +#define RT5651_M_3D_D2H_MASK			(0x1 << 8) +#define RT5651_M_3D_D2H_SFT			8 +#define RT5651_M_3D_D2R_MASK			(0x1 << 7) +#define RT5651_M_3D_D2R_SFT			7 +#define RT5651_M_3D_REVB_MASK			(0x1 << 6) +#define RT5651_M_3D_REVB_SFT			6 + +/* Adjustable high pass filter control 1 (0xd3) */ +#define RT5651_2ND_HPF_MASK			(0x1 << 15) +#define RT5651_2ND_HPF_SFT			15 +#define RT5651_2ND_HPF_DIS			(0x0 << 15) +#define RT5651_2ND_HPF_EN			(0x1 << 15) +#define RT5651_HPF_CF_L_MASK			(0x7 << 12) +#define RT5651_HPF_CF_L_SFT			12 +#define RT5651_HPF_CF_R_MASK			(0x7 << 8) +#define RT5651_HPF_CF_R_SFT			8 +#define RT5651_ZD_T_MASK			(0x3 << 6) +#define RT5651_ZD_T_SFT				6 +#define RT5651_ZD_F_MASK			(0x3 << 4) +#define RT5651_ZD_F_SFT				4 +#define RT5651_ZD_F_IM				(0x0 << 4) +#define RT5651_ZD_F_ZC_IM			(0x1 << 4) +#define RT5651_ZD_F_ZC_IOD			(0x2 << 4) +#define RT5651_ZD_F_UN				(0x3 << 4) + +/* Adjustable high pass filter control 2 (0xd4) */ +#define RT5651_HPF_CF_L_NUM_MASK		(0x3f << 8) +#define RT5651_HPF_CF_L_NUM_SFT			8 +#define RT5651_HPF_CF_R_NUM_MASK		(0x3f) +#define RT5651_HPF_CF_R_NUM_SFT			0 + +/* HP calibration control and Amp detection (0xd6) */ +#define RT5651_SI_DAC_MASK			(0x1 << 11) +#define RT5651_SI_DAC_SFT			11 +#define RT5651_SI_DAC_AUTO			(0x0 << 11) +#define RT5651_SI_DAC_TEST			(0x1 << 11) +#define RT5651_DC_CAL_M_MASK			(0x1 << 10) +#define RT5651_DC_CAL_M_SFT			10 +#define RT5651_DC_CAL_M_NOR			(0x0 << 10) +#define RT5651_DC_CAL_M_CAL			(0x1 << 10) +#define RT5651_DC_CAL_MASK			(0x1 << 9) +#define RT5651_DC_CAL_SFT			9 +#define RT5651_DC_CAL_DIS			(0x0 << 9) +#define RT5651_DC_CAL_EN			(0x1 << 9) +#define RT5651_HPD_RCV_MASK			(0x7 << 6) +#define RT5651_HPD_RCV_SFT			6 +#define RT5651_HPD_PS_MASK			(0x1 << 5) +#define RT5651_HPD_PS_SFT			5 +#define RT5651_HPD_PS_DIS			(0x0 << 5) +#define RT5651_HPD_PS_EN			(0x1 << 5) +#define RT5651_CAL_M_MASK			(0x1 << 4) +#define RT5651_CAL_M_SFT			4 +#define RT5651_CAL_M_DEP			(0x0 << 4) +#define RT5651_CAL_M_CAL			(0x1 << 4) +#define RT5651_CAL_MASK				(0x1 << 3) +#define RT5651_CAL_SFT				3 +#define RT5651_CAL_DIS				(0x0 << 3) +#define RT5651_CAL_EN				(0x1 << 3) +#define RT5651_CAL_TEST_MASK			(0x1 << 2) +#define RT5651_CAL_TEST_SFT			2 +#define RT5651_CAL_TEST_DIS			(0x0 << 2) +#define RT5651_CAL_TEST_EN			(0x1 << 2) +#define RT5651_CAL_P_MASK			(0x3) +#define RT5651_CAL_P_SFT			0 +#define RT5651_CAL_P_NONE			(0x0) +#define RT5651_CAL_P_CAL			(0x1) +#define RT5651_CAL_P_DAC_CAL			(0x2) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5651_SV_MASK				(0x1 << 15) +#define RT5651_SV_SFT				15 +#define RT5651_SV_DIS				(0x0 << 15) +#define RT5651_SV_EN				(0x1 << 15) +#define RT5651_OUT_SV_MASK			(0x1 << 13) +#define RT5651_OUT_SV_SFT			13 +#define RT5651_OUT_SV_DIS			(0x0 << 13) +#define RT5651_OUT_SV_EN			(0x1 << 13) +#define RT5651_HP_SV_MASK			(0x1 << 12) +#define RT5651_HP_SV_SFT			12 +#define RT5651_HP_SV_DIS			(0x0 << 12) +#define RT5651_HP_SV_EN				(0x1 << 12) +#define RT5651_ZCD_DIG_MASK			(0x1 << 11) +#define RT5651_ZCD_DIG_SFT			11 +#define RT5651_ZCD_DIG_DIS			(0x0 << 11) +#define RT5651_ZCD_DIG_EN			(0x1 << 11) +#define RT5651_ZCD_MASK				(0x1 << 10) +#define RT5651_ZCD_SFT				10 +#define RT5651_ZCD_PD				(0x0 << 10) +#define RT5651_ZCD_PU				(0x1 << 10) +#define RT5651_M_ZCD_MASK			(0x3f << 4) +#define RT5651_M_ZCD_SFT			4 +#define RT5651_M_ZCD_OM_L			(0x1 << 7) +#define RT5651_M_ZCD_OM_R			(0x1 << 6) +#define RT5651_M_ZCD_RM_L			(0x1 << 5) +#define RT5651_M_ZCD_RM_R			(0x1 << 4) +#define RT5651_SV_DLY_MASK			(0xf) +#define RT5651_SV_DLY_SFT			0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5651_ZCD_HP_MASK			(0x1 << 15) +#define RT5651_ZCD_HP_SFT			15 +#define RT5651_ZCD_HP_DIS			(0x0 << 15) +#define RT5651_ZCD_HP_EN			(0x1 << 15) + +/* Digital Misc Control (0xfa) */ +#define RT5651_I2S2_MS_SP_MASK			(0x1 << 8) +#define RT5651_I2S2_MS_SP_SEL			8 +#define RT5651_I2S2_MS_SP_64			(0x0 << 8) +#define RT5651_I2S2_MS_SP_50			(0x1 << 8) +#define RT5651_CLK_DET_EN			(0x1 << 3) +#define RT5651_CLK_DET_EN_SFT			3 +#define RT5651_AMP_DET_EN			(0x1 << 1) +#define RT5651_AMP_DET_EN_SFT			1 +#define RT5651_D_GATE_EN			(0x1) +#define RT5651_D_GATE_EN_SFT			0 + +/* Codec Private Register definition */ +/* 3D Speaker Control (0x63) */ +#define RT5651_3D_SPK_MASK			(0x1 << 15) +#define RT5651_3D_SPK_SFT			15 +#define RT5651_3D_SPK_DIS			(0x0 << 15) +#define RT5651_3D_SPK_EN			(0x1 << 15) +#define RT5651_3D_SPK_M_MASK			(0x3 << 13) +#define RT5651_3D_SPK_M_SFT			13 +#define RT5651_3D_SPK_CG_MASK			(0x1f << 8) +#define RT5651_3D_SPK_CG_SFT			8 +#define RT5651_3D_SPK_SG_MASK			(0x1f) +#define RT5651_3D_SPK_SG_SFT			0 + +/* Wind Noise Detection Control 1 (0x6c) */ +#define RT5651_WND_MASK				(0x1 << 15) +#define RT5651_WND_SFT				15 +#define RT5651_WND_DIS				(0x0 << 15) +#define RT5651_WND_EN				(0x1 << 15) + +/* Wind Noise Detection Control 2 (0x6d) */ +#define RT5651_WND_FC_NW_MASK			(0x3f << 10) +#define RT5651_WND_FC_NW_SFT			10 +#define RT5651_WND_FC_WK_MASK			(0x3f << 4) +#define RT5651_WND_FC_WK_SFT			4 + +/* Wind Noise Detection Control 3 (0x6e) */ +#define RT5651_HPF_FC_MASK			(0x3f << 6) +#define RT5651_HPF_FC_SFT			6 +#define RT5651_WND_FC_ST_MASK			(0x3f) +#define RT5651_WND_FC_ST_SFT			0 + +/* Wind Noise Detection Control 4 (0x6f) */ +#define RT5651_WND_TH_LO_MASK			(0x3ff) +#define RT5651_WND_TH_LO_SFT			0 + +/* Wind Noise Detection Control 5 (0x70) */ +#define RT5651_WND_TH_HI_MASK			(0x3ff) +#define RT5651_WND_TH_HI_SFT			0 + +/* Wind Noise Detection Control 8 (0x73) */ +#define RT5651_WND_WIND_MASK			(0x1 << 13) /* Read-Only */ +#define RT5651_WND_WIND_SFT			13 +#define RT5651_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */ +#define RT5651_WND_STRONG_SFT			12 +enum { +	RT5651_NO_WIND, +	RT5651_BREEZE, +	RT5651_STORM, +}; + +/* Dipole Speaker Interface (0x75) */ +#define RT5651_DP_ATT_MASK			(0x3 << 14) +#define RT5651_DP_ATT_SFT			14 +#define RT5651_DP_SPK_MASK			(0x1 << 10) +#define RT5651_DP_SPK_SFT			10 +#define RT5651_DP_SPK_DIS			(0x0 << 10) +#define RT5651_DP_SPK_EN			(0x1 << 10) + +/* EQ Pre Volume Control (0xb3) */ +#define RT5651_EQ_PRE_VOL_MASK			(0xffff) +#define RT5651_EQ_PRE_VOL_SFT			0 + +/* EQ Post Volume Control (0xb4) */ +#define RT5651_EQ_PST_VOL_MASK			(0xffff) +#define RT5651_EQ_PST_VOL_SFT			0 + +/* System Clock Source */ +enum { +	RT5651_SCLK_S_MCLK, +	RT5651_SCLK_S_PLL1, +	RT5651_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { +	RT5651_PLL1_S_MCLK, +	RT5651_PLL1_S_BCLK1, +	RT5651_PLL1_S_BCLK2, +}; + +enum { +	RT5651_AIF1, +	RT5651_AIF2, +	RT5651_AIFS, +}; + +struct rt5651_pll_code { +	bool m_bp; /* Indicates bypass m code or not. */ +	int m_code; +	int n_code; +	int k_code; +}; + +struct rt5651_priv { +	struct snd_soc_codec *codec; +	struct rt5651_platform_data pdata; +	struct regmap *regmap; + +	int sysclk; +	int sysclk_src; +	int lrck[RT5651_AIFS]; +	int bclk[RT5651_AIFS]; +	int master[RT5651_AIFS]; + +	int pll_src; +	int pll_in; +	int pll_out; + +	int dmic_en; +	bool hp_mute; +}; + +#endif /* __RT5651_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c new file mode 100644 index 00000000000..833231e2734 --- /dev/null +++ b/sound/soc/codecs/rt5677.c @@ -0,0 +1,3498 @@ +/* + * rt5677.c  --  RT5677 ALSA SoC audio codec driver + * + * Copyright 2013 Realtek Semiconductor Corp. + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rt5677.h" + +#define RT5677_DEVICE_ID 0x6327 + +#define RT5677_PR_RANGE_BASE (0xff + 1) +#define RT5677_PR_SPACING 0x100 + +#define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING)) + +static const struct regmap_range_cfg rt5677_ranges[] = { +	{ +		.name = "PR", +		.range_min = RT5677_PR_BASE, +		.range_max = RT5677_PR_BASE + 0xfd, +		.selector_reg = RT5677_PRIV_INDEX, +		.selector_mask = 0xff, +		.selector_shift = 0x0, +		.window_start = RT5677_PRIV_DATA, +		.window_len = 0x1, +	}, +}; + +static const struct reg_default init_list[] = { +	{RT5677_PR_BASE + 0x3d,	0x364d}, +	{RT5677_PR_BASE + 0x17, 0x4fc0}, +	{RT5677_PR_BASE + 0x13, 0x0312}, +	{RT5677_PR_BASE + 0x1e, 0x0000}, +	{RT5677_PR_BASE + 0x12, 0x0eaa}, +	{RT5677_PR_BASE + 0x14, 0x018a}, +}; +#define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt5677_reg[] = { +	{RT5677_RESET			, 0x0000}, +	{RT5677_LOUT1			, 0xa800}, +	{RT5677_IN1			, 0x0000}, +	{RT5677_MICBIAS			, 0x0000}, +	{RT5677_SLIMBUS_PARAM		, 0x0000}, +	{RT5677_SLIMBUS_RX		, 0x0000}, +	{RT5677_SLIMBUS_CTRL		, 0x0000}, +	{RT5677_SIDETONE_CTRL		, 0x000b}, +	{RT5677_ANA_DAC1_2_3_SRC	, 0x0000}, +	{RT5677_IF_DSP_DAC3_4_MIXER	, 0x1111}, +	{RT5677_DAC4_DIG_VOL		, 0xafaf}, +	{RT5677_DAC3_DIG_VOL		, 0xafaf}, +	{RT5677_DAC1_DIG_VOL		, 0xafaf}, +	{RT5677_DAC2_DIG_VOL		, 0xafaf}, +	{RT5677_IF_DSP_DAC2_MIXER	, 0x0011}, +	{RT5677_STO1_ADC_DIG_VOL	, 0x2f2f}, +	{RT5677_MONO_ADC_DIG_VOL	, 0x2f2f}, +	{RT5677_STO1_2_ADC_BST		, 0x0000}, +	{RT5677_STO2_ADC_DIG_VOL	, 0x2f2f}, +	{RT5677_ADC_BST_CTRL2		, 0x0000}, +	{RT5677_STO3_4_ADC_BST		, 0x0000}, +	{RT5677_STO3_ADC_DIG_VOL	, 0x2f2f}, +	{RT5677_STO4_ADC_DIG_VOL	, 0x2f2f}, +	{RT5677_STO4_ADC_MIXER		, 0xd4c0}, +	{RT5677_STO3_ADC_MIXER		, 0xd4c0}, +	{RT5677_STO2_ADC_MIXER		, 0xd4c0}, +	{RT5677_STO1_ADC_MIXER		, 0xd4c0}, +	{RT5677_MONO_ADC_MIXER		, 0xd4d1}, +	{RT5677_ADC_IF_DSP_DAC1_MIXER	, 0x8080}, +	{RT5677_STO1_DAC_MIXER		, 0xaaaa}, +	{RT5677_MONO_DAC_MIXER		, 0xaaaa}, +	{RT5677_DD1_MIXER		, 0xaaaa}, +	{RT5677_DD2_MIXER		, 0xaaaa}, +	{RT5677_IF3_DATA		, 0x0000}, +	{RT5677_IF4_DATA		, 0x0000}, +	{RT5677_PDM_OUT_CTRL		, 0x8888}, +	{RT5677_PDM_DATA_CTRL1		, 0x0000}, +	{RT5677_PDM_DATA_CTRL2		, 0x0000}, +	{RT5677_PDM1_DATA_CTRL2		, 0x0000}, +	{RT5677_PDM1_DATA_CTRL3		, 0x0000}, +	{RT5677_PDM1_DATA_CTRL4		, 0x0000}, +	{RT5677_PDM2_DATA_CTRL2		, 0x0000}, +	{RT5677_PDM2_DATA_CTRL3		, 0x0000}, +	{RT5677_PDM2_DATA_CTRL4		, 0x0000}, +	{RT5677_TDM1_CTRL1		, 0x0300}, +	{RT5677_TDM1_CTRL2		, 0x0000}, +	{RT5677_TDM1_CTRL3		, 0x4000}, +	{RT5677_TDM1_CTRL4		, 0x0123}, +	{RT5677_TDM1_CTRL5		, 0x4567}, +	{RT5677_TDM2_CTRL1		, 0x0300}, +	{RT5677_TDM2_CTRL2		, 0x0000}, +	{RT5677_TDM2_CTRL3		, 0x4000}, +	{RT5677_TDM2_CTRL4		, 0x0123}, +	{RT5677_TDM2_CTRL5		, 0x4567}, +	{RT5677_I2C_MASTER_CTRL1	, 0x0001}, +	{RT5677_I2C_MASTER_CTRL2	, 0x0000}, +	{RT5677_I2C_MASTER_CTRL3	, 0x0000}, +	{RT5677_I2C_MASTER_CTRL4	, 0x0000}, +	{RT5677_I2C_MASTER_CTRL5	, 0x0000}, +	{RT5677_I2C_MASTER_CTRL6	, 0x0000}, +	{RT5677_I2C_MASTER_CTRL7	, 0x0000}, +	{RT5677_I2C_MASTER_CTRL8	, 0x0000}, +	{RT5677_DMIC_CTRL1		, 0x1505}, +	{RT5677_DMIC_CTRL2		, 0x0055}, +	{RT5677_HAP_GENE_CTRL1		, 0x0111}, +	{RT5677_HAP_GENE_CTRL2		, 0x0064}, +	{RT5677_HAP_GENE_CTRL3		, 0xef0e}, +	{RT5677_HAP_GENE_CTRL4		, 0xf0f0}, +	{RT5677_HAP_GENE_CTRL5		, 0xef0e}, +	{RT5677_HAP_GENE_CTRL6		, 0xf0f0}, +	{RT5677_HAP_GENE_CTRL7		, 0xef0e}, +	{RT5677_HAP_GENE_CTRL8		, 0xf0f0}, +	{RT5677_HAP_GENE_CTRL9		, 0xf000}, +	{RT5677_HAP_GENE_CTRL10		, 0x0000}, +	{RT5677_PWR_DIG1		, 0x0000}, +	{RT5677_PWR_DIG2		, 0x0000}, +	{RT5677_PWR_ANLG1		, 0x0055}, +	{RT5677_PWR_ANLG2		, 0x0000}, +	{RT5677_PWR_DSP1		, 0x0001}, +	{RT5677_PWR_DSP_ST		, 0x0000}, +	{RT5677_PWR_DSP2		, 0x0000}, +	{RT5677_ADC_DAC_HPF_CTRL1	, 0x0e00}, +	{RT5677_PRIV_INDEX		, 0x0000}, +	{RT5677_PRIV_DATA		, 0x0000}, +	{RT5677_I2S4_SDP		, 0x8000}, +	{RT5677_I2S1_SDP		, 0x8000}, +	{RT5677_I2S2_SDP		, 0x8000}, +	{RT5677_I2S3_SDP		, 0x8000}, +	{RT5677_CLK_TREE_CTRL1		, 0x1111}, +	{RT5677_CLK_TREE_CTRL2		, 0x1111}, +	{RT5677_CLK_TREE_CTRL3		, 0x0000}, +	{RT5677_PLL1_CTRL1		, 0x0000}, +	{RT5677_PLL1_CTRL2		, 0x0000}, +	{RT5677_PLL2_CTRL1		, 0x0c60}, +	{RT5677_PLL2_CTRL2		, 0x2000}, +	{RT5677_GLB_CLK1		, 0x0000}, +	{RT5677_GLB_CLK2		, 0x0000}, +	{RT5677_ASRC_1			, 0x0000}, +	{RT5677_ASRC_2			, 0x0000}, +	{RT5677_ASRC_3			, 0x0000}, +	{RT5677_ASRC_4			, 0x0000}, +	{RT5677_ASRC_5			, 0x0000}, +	{RT5677_ASRC_6			, 0x0000}, +	{RT5677_ASRC_7			, 0x0000}, +	{RT5677_ASRC_8			, 0x0000}, +	{RT5677_ASRC_9			, 0x0000}, +	{RT5677_ASRC_10			, 0x0000}, +	{RT5677_ASRC_11			, 0x0000}, +	{RT5677_ASRC_12			, 0x0008}, +	{RT5677_ASRC_13			, 0x0000}, +	{RT5677_ASRC_14			, 0x0000}, +	{RT5677_ASRC_15			, 0x0000}, +	{RT5677_ASRC_16			, 0x0000}, +	{RT5677_ASRC_17			, 0x0000}, +	{RT5677_ASRC_18			, 0x0000}, +	{RT5677_ASRC_19			, 0x0000}, +	{RT5677_ASRC_20			, 0x0000}, +	{RT5677_ASRC_21			, 0x000c}, +	{RT5677_ASRC_22			, 0x0000}, +	{RT5677_ASRC_23			, 0x0000}, +	{RT5677_VAD_CTRL1		, 0x2184}, +	{RT5677_VAD_CTRL2		, 0x010a}, +	{RT5677_VAD_CTRL3		, 0x0aea}, +	{RT5677_VAD_CTRL4		, 0x000c}, +	{RT5677_VAD_CTRL5		, 0x0000}, +	{RT5677_DSP_INB_CTRL1		, 0x0000}, +	{RT5677_DSP_INB_CTRL2		, 0x0000}, +	{RT5677_DSP_IN_OUTB_CTRL	, 0x0000}, +	{RT5677_DSP_OUTB0_1_DIG_VOL	, 0x2f2f}, +	{RT5677_DSP_OUTB2_3_DIG_VOL	, 0x2f2f}, +	{RT5677_DSP_OUTB4_5_DIG_VOL	, 0x2f2f}, +	{RT5677_DSP_OUTB6_7_DIG_VOL	, 0x2f2f}, +	{RT5677_ADC_EQ_CTRL1		, 0x6000}, +	{RT5677_ADC_EQ_CTRL2		, 0x0000}, +	{RT5677_EQ_CTRL1		, 0xc000}, +	{RT5677_EQ_CTRL2		, 0x0000}, +	{RT5677_EQ_CTRL3		, 0x0000}, +	{RT5677_SOFT_VOL_ZERO_CROSS1	, 0x0009}, +	{RT5677_JD_CTRL1		, 0x0000}, +	{RT5677_JD_CTRL2		, 0x0000}, +	{RT5677_JD_CTRL3		, 0x0000}, +	{RT5677_IRQ_CTRL1		, 0x0000}, +	{RT5677_IRQ_CTRL2		, 0x0000}, +	{RT5677_GPIO_ST			, 0x0000}, +	{RT5677_GPIO_CTRL1		, 0x0000}, +	{RT5677_GPIO_CTRL2		, 0x0000}, +	{RT5677_GPIO_CTRL3		, 0x0000}, +	{RT5677_STO1_ADC_HI_FILTER1	, 0xb320}, +	{RT5677_STO1_ADC_HI_FILTER2	, 0x0000}, +	{RT5677_MONO_ADC_HI_FILTER1	, 0xb300}, +	{RT5677_MONO_ADC_HI_FILTER2	, 0x0000}, +	{RT5677_STO2_ADC_HI_FILTER1	, 0xb300}, +	{RT5677_STO2_ADC_HI_FILTER2	, 0x0000}, +	{RT5677_STO3_ADC_HI_FILTER1	, 0xb300}, +	{RT5677_STO3_ADC_HI_FILTER2	, 0x0000}, +	{RT5677_STO4_ADC_HI_FILTER1	, 0xb300}, +	{RT5677_STO4_ADC_HI_FILTER2	, 0x0000}, +	{RT5677_MB_DRC_CTRL1		, 0x0f20}, +	{RT5677_DRC1_CTRL1		, 0x001f}, +	{RT5677_DRC1_CTRL2		, 0x020c}, +	{RT5677_DRC1_CTRL3		, 0x1f00}, +	{RT5677_DRC1_CTRL4		, 0x0000}, +	{RT5677_DRC1_CTRL5		, 0x0000}, +	{RT5677_DRC1_CTRL6		, 0x0029}, +	{RT5677_DRC2_CTRL1		, 0x001f}, +	{RT5677_DRC2_CTRL2		, 0x020c}, +	{RT5677_DRC2_CTRL3		, 0x1f00}, +	{RT5677_DRC2_CTRL4		, 0x0000}, +	{RT5677_DRC2_CTRL5		, 0x0000}, +	{RT5677_DRC2_CTRL6		, 0x0029}, +	{RT5677_DRC1_HL_CTRL1		, 0x8000}, +	{RT5677_DRC1_HL_CTRL2		, 0x0200}, +	{RT5677_DRC2_HL_CTRL1		, 0x8000}, +	{RT5677_DRC2_HL_CTRL2		, 0x0200}, +	{RT5677_DSP_INB1_SRC_CTRL1	, 0x5800}, +	{RT5677_DSP_INB1_SRC_CTRL2	, 0x0000}, +	{RT5677_DSP_INB1_SRC_CTRL3	, 0x0000}, +	{RT5677_DSP_INB1_SRC_CTRL4	, 0x0800}, +	{RT5677_DSP_INB2_SRC_CTRL1	, 0x5800}, +	{RT5677_DSP_INB2_SRC_CTRL2	, 0x0000}, +	{RT5677_DSP_INB2_SRC_CTRL3	, 0x0000}, +	{RT5677_DSP_INB2_SRC_CTRL4	, 0x0800}, +	{RT5677_DSP_INB3_SRC_CTRL1	, 0x5800}, +	{RT5677_DSP_INB3_SRC_CTRL2	, 0x0000}, +	{RT5677_DSP_INB3_SRC_CTRL3	, 0x0000}, +	{RT5677_DSP_INB3_SRC_CTRL4	, 0x0800}, +	{RT5677_DSP_OUTB1_SRC_CTRL1	, 0x5800}, +	{RT5677_DSP_OUTB1_SRC_CTRL2	, 0x0000}, +	{RT5677_DSP_OUTB1_SRC_CTRL3	, 0x0000}, +	{RT5677_DSP_OUTB1_SRC_CTRL4	, 0x0800}, +	{RT5677_DSP_OUTB2_SRC_CTRL1	, 0x5800}, +	{RT5677_DSP_OUTB2_SRC_CTRL2	, 0x0000}, +	{RT5677_DSP_OUTB2_SRC_CTRL3	, 0x0000}, +	{RT5677_DSP_OUTB2_SRC_CTRL4	, 0x0800}, +	{RT5677_DSP_OUTB_0123_MIXER_CTRL, 0xfefe}, +	{RT5677_DSP_OUTB_45_MIXER_CTRL	, 0xfefe}, +	{RT5677_DSP_OUTB_67_MIXER_CTRL	, 0xfefe}, +	{RT5677_DIG_MISC		, 0x0000}, +	{RT5677_GEN_CTRL1		, 0x0000}, +	{RT5677_GEN_CTRL2		, 0x0000}, +	{RT5677_VENDOR_ID		, 0x0000}, +	{RT5677_VENDOR_ID1		, 0x10ec}, +	{RT5677_VENDOR_ID2		, 0x6327}, +}; + +static bool rt5677_volatile_register(struct device *dev, unsigned int reg) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(rt5677_ranges); i++) { +		if (reg >= rt5677_ranges[i].range_min && +			reg <= rt5677_ranges[i].range_max) { +			return true; +		} +	} + +	switch (reg) { +	case RT5677_RESET: +	case RT5677_SLIMBUS_PARAM: +	case RT5677_PDM_DATA_CTRL1: +	case RT5677_PDM_DATA_CTRL2: +	case RT5677_PDM1_DATA_CTRL4: +	case RT5677_PDM2_DATA_CTRL4: +	case RT5677_I2C_MASTER_CTRL1: +	case RT5677_I2C_MASTER_CTRL7: +	case RT5677_I2C_MASTER_CTRL8: +	case RT5677_HAP_GENE_CTRL2: +	case RT5677_PWR_DSP_ST: +	case RT5677_PRIV_DATA: +	case RT5677_PLL1_CTRL2: +	case RT5677_PLL2_CTRL2: +	case RT5677_ASRC_22: +	case RT5677_ASRC_23: +	case RT5677_VAD_CTRL5: +	case RT5677_ADC_EQ_CTRL1: +	case RT5677_EQ_CTRL1: +	case RT5677_IRQ_CTRL1: +	case RT5677_IRQ_CTRL2: +	case RT5677_GPIO_ST: +	case RT5677_DSP_INB1_SRC_CTRL4: +	case RT5677_DSP_INB2_SRC_CTRL4: +	case RT5677_DSP_INB3_SRC_CTRL4: +	case RT5677_DSP_OUTB1_SRC_CTRL4: +	case RT5677_DSP_OUTB2_SRC_CTRL4: +	case RT5677_VENDOR_ID: +	case RT5677_VENDOR_ID1: +	case RT5677_VENDOR_ID2: +		return true; +	default: +		return false; +	} +} + +static bool rt5677_readable_register(struct device *dev, unsigned int reg) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(rt5677_ranges); i++) { +		if (reg >= rt5677_ranges[i].range_min && +			reg <= rt5677_ranges[i].range_max) { +			return true; +		} +	} + +	switch (reg) { +	case RT5677_RESET: +	case RT5677_LOUT1: +	case RT5677_IN1: +	case RT5677_MICBIAS: +	case RT5677_SLIMBUS_PARAM: +	case RT5677_SLIMBUS_RX: +	case RT5677_SLIMBUS_CTRL: +	case RT5677_SIDETONE_CTRL: +	case RT5677_ANA_DAC1_2_3_SRC: +	case RT5677_IF_DSP_DAC3_4_MIXER: +	case RT5677_DAC4_DIG_VOL: +	case RT5677_DAC3_DIG_VOL: +	case RT5677_DAC1_DIG_VOL: +	case RT5677_DAC2_DIG_VOL: +	case RT5677_IF_DSP_DAC2_MIXER: +	case RT5677_STO1_ADC_DIG_VOL: +	case RT5677_MONO_ADC_DIG_VOL: +	case RT5677_STO1_2_ADC_BST: +	case RT5677_STO2_ADC_DIG_VOL: +	case RT5677_ADC_BST_CTRL2: +	case RT5677_STO3_4_ADC_BST: +	case RT5677_STO3_ADC_DIG_VOL: +	case RT5677_STO4_ADC_DIG_VOL: +	case RT5677_STO4_ADC_MIXER: +	case RT5677_STO3_ADC_MIXER: +	case RT5677_STO2_ADC_MIXER: +	case RT5677_STO1_ADC_MIXER: +	case RT5677_MONO_ADC_MIXER: +	case RT5677_ADC_IF_DSP_DAC1_MIXER: +	case RT5677_STO1_DAC_MIXER: +	case RT5677_MONO_DAC_MIXER: +	case RT5677_DD1_MIXER: +	case RT5677_DD2_MIXER: +	case RT5677_IF3_DATA: +	case RT5677_IF4_DATA: +	case RT5677_PDM_OUT_CTRL: +	case RT5677_PDM_DATA_CTRL1: +	case RT5677_PDM_DATA_CTRL2: +	case RT5677_PDM1_DATA_CTRL2: +	case RT5677_PDM1_DATA_CTRL3: +	case RT5677_PDM1_DATA_CTRL4: +	case RT5677_PDM2_DATA_CTRL2: +	case RT5677_PDM2_DATA_CTRL3: +	case RT5677_PDM2_DATA_CTRL4: +	case RT5677_TDM1_CTRL1: +	case RT5677_TDM1_CTRL2: +	case RT5677_TDM1_CTRL3: +	case RT5677_TDM1_CTRL4: +	case RT5677_TDM1_CTRL5: +	case RT5677_TDM2_CTRL1: +	case RT5677_TDM2_CTRL2: +	case RT5677_TDM2_CTRL3: +	case RT5677_TDM2_CTRL4: +	case RT5677_TDM2_CTRL5: +	case RT5677_I2C_MASTER_CTRL1: +	case RT5677_I2C_MASTER_CTRL2: +	case RT5677_I2C_MASTER_CTRL3: +	case RT5677_I2C_MASTER_CTRL4: +	case RT5677_I2C_MASTER_CTRL5: +	case RT5677_I2C_MASTER_CTRL6: +	case RT5677_I2C_MASTER_CTRL7: +	case RT5677_I2C_MASTER_CTRL8: +	case RT5677_DMIC_CTRL1: +	case RT5677_DMIC_CTRL2: +	case RT5677_HAP_GENE_CTRL1: +	case RT5677_HAP_GENE_CTRL2: +	case RT5677_HAP_GENE_CTRL3: +	case RT5677_HAP_GENE_CTRL4: +	case RT5677_HAP_GENE_CTRL5: +	case RT5677_HAP_GENE_CTRL6: +	case RT5677_HAP_GENE_CTRL7: +	case RT5677_HAP_GENE_CTRL8: +	case RT5677_HAP_GENE_CTRL9: +	case RT5677_HAP_GENE_CTRL10: +	case RT5677_PWR_DIG1: +	case RT5677_PWR_DIG2: +	case RT5677_PWR_ANLG1: +	case RT5677_PWR_ANLG2: +	case RT5677_PWR_DSP1: +	case RT5677_PWR_DSP_ST: +	case RT5677_PWR_DSP2: +	case RT5677_ADC_DAC_HPF_CTRL1: +	case RT5677_PRIV_INDEX: +	case RT5677_PRIV_DATA: +	case RT5677_I2S4_SDP: +	case RT5677_I2S1_SDP: +	case RT5677_I2S2_SDP: +	case RT5677_I2S3_SDP: +	case RT5677_CLK_TREE_CTRL1: +	case RT5677_CLK_TREE_CTRL2: +	case RT5677_CLK_TREE_CTRL3: +	case RT5677_PLL1_CTRL1: +	case RT5677_PLL1_CTRL2: +	case RT5677_PLL2_CTRL1: +	case RT5677_PLL2_CTRL2: +	case RT5677_GLB_CLK1: +	case RT5677_GLB_CLK2: +	case RT5677_ASRC_1: +	case RT5677_ASRC_2: +	case RT5677_ASRC_3: +	case RT5677_ASRC_4: +	case RT5677_ASRC_5: +	case RT5677_ASRC_6: +	case RT5677_ASRC_7: +	case RT5677_ASRC_8: +	case RT5677_ASRC_9: +	case RT5677_ASRC_10: +	case RT5677_ASRC_11: +	case RT5677_ASRC_12: +	case RT5677_ASRC_13: +	case RT5677_ASRC_14: +	case RT5677_ASRC_15: +	case RT5677_ASRC_16: +	case RT5677_ASRC_17: +	case RT5677_ASRC_18: +	case RT5677_ASRC_19: +	case RT5677_ASRC_20: +	case RT5677_ASRC_21: +	case RT5677_ASRC_22: +	case RT5677_ASRC_23: +	case RT5677_VAD_CTRL1: +	case RT5677_VAD_CTRL2: +	case RT5677_VAD_CTRL3: +	case RT5677_VAD_CTRL4: +	case RT5677_VAD_CTRL5: +	case RT5677_DSP_INB_CTRL1: +	case RT5677_DSP_INB_CTRL2: +	case RT5677_DSP_IN_OUTB_CTRL: +	case RT5677_DSP_OUTB0_1_DIG_VOL: +	case RT5677_DSP_OUTB2_3_DIG_VOL: +	case RT5677_DSP_OUTB4_5_DIG_VOL: +	case RT5677_DSP_OUTB6_7_DIG_VOL: +	case RT5677_ADC_EQ_CTRL1: +	case RT5677_ADC_EQ_CTRL2: +	case RT5677_EQ_CTRL1: +	case RT5677_EQ_CTRL2: +	case RT5677_EQ_CTRL3: +	case RT5677_SOFT_VOL_ZERO_CROSS1: +	case RT5677_JD_CTRL1: +	case RT5677_JD_CTRL2: +	case RT5677_JD_CTRL3: +	case RT5677_IRQ_CTRL1: +	case RT5677_IRQ_CTRL2: +	case RT5677_GPIO_ST: +	case RT5677_GPIO_CTRL1: +	case RT5677_GPIO_CTRL2: +	case RT5677_GPIO_CTRL3: +	case RT5677_STO1_ADC_HI_FILTER1: +	case RT5677_STO1_ADC_HI_FILTER2: +	case RT5677_MONO_ADC_HI_FILTER1: +	case RT5677_MONO_ADC_HI_FILTER2: +	case RT5677_STO2_ADC_HI_FILTER1: +	case RT5677_STO2_ADC_HI_FILTER2: +	case RT5677_STO3_ADC_HI_FILTER1: +	case RT5677_STO3_ADC_HI_FILTER2: +	case RT5677_STO4_ADC_HI_FILTER1: +	case RT5677_STO4_ADC_HI_FILTER2: +	case RT5677_MB_DRC_CTRL1: +	case RT5677_DRC1_CTRL1: +	case RT5677_DRC1_CTRL2: +	case RT5677_DRC1_CTRL3: +	case RT5677_DRC1_CTRL4: +	case RT5677_DRC1_CTRL5: +	case RT5677_DRC1_CTRL6: +	case RT5677_DRC2_CTRL1: +	case RT5677_DRC2_CTRL2: +	case RT5677_DRC2_CTRL3: +	case RT5677_DRC2_CTRL4: +	case RT5677_DRC2_CTRL5: +	case RT5677_DRC2_CTRL6: +	case RT5677_DRC1_HL_CTRL1: +	case RT5677_DRC1_HL_CTRL2: +	case RT5677_DRC2_HL_CTRL1: +	case RT5677_DRC2_HL_CTRL2: +	case RT5677_DSP_INB1_SRC_CTRL1: +	case RT5677_DSP_INB1_SRC_CTRL2: +	case RT5677_DSP_INB1_SRC_CTRL3: +	case RT5677_DSP_INB1_SRC_CTRL4: +	case RT5677_DSP_INB2_SRC_CTRL1: +	case RT5677_DSP_INB2_SRC_CTRL2: +	case RT5677_DSP_INB2_SRC_CTRL3: +	case RT5677_DSP_INB2_SRC_CTRL4: +	case RT5677_DSP_INB3_SRC_CTRL1: +	case RT5677_DSP_INB3_SRC_CTRL2: +	case RT5677_DSP_INB3_SRC_CTRL3: +	case RT5677_DSP_INB3_SRC_CTRL4: +	case RT5677_DSP_OUTB1_SRC_CTRL1: +	case RT5677_DSP_OUTB1_SRC_CTRL2: +	case RT5677_DSP_OUTB1_SRC_CTRL3: +	case RT5677_DSP_OUTB1_SRC_CTRL4: +	case RT5677_DSP_OUTB2_SRC_CTRL1: +	case RT5677_DSP_OUTB2_SRC_CTRL2: +	case RT5677_DSP_OUTB2_SRC_CTRL3: +	case RT5677_DSP_OUTB2_SRC_CTRL4: +	case RT5677_DSP_OUTB_0123_MIXER_CTRL: +	case RT5677_DSP_OUTB_45_MIXER_CTRL: +	case RT5677_DSP_OUTB_67_MIXER_CTRL: +	case RT5677_DIG_MISC: +	case RT5677_GEN_CTRL1: +	case RT5677_GEN_CTRL2: +	case RT5677_VENDOR_ID: +	case RT5677_VENDOR_ID1: +	case RT5677_VENDOR_ID2: +		return true; +	default: +		return false; +	} +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { +	TLV_DB_RANGE_HEAD(7), +	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), +	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), +	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), +	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), +	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), +	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), +	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +static const struct snd_kcontrol_new rt5677_snd_controls[] = { +	/* OUTPUT Control */ +	SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, +		RT5677_LOUT1_L_MUTE_SFT, 1, 1), +	SOC_SINGLE("OUT2 Playback Switch", RT5677_LOUT1, +		RT5677_LOUT2_L_MUTE_SFT, 1, 1), +	SOC_SINGLE("OUT3 Playback Switch", RT5677_LOUT1, +		RT5677_LOUT3_L_MUTE_SFT, 1, 1), + +	/* DAC Digital Volume */ +	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL, +		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), +	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL, +		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), +	SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL, +		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), +	SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL, +		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), + +	/* IN1/IN2 Control */ +	SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv), +	SOC_SINGLE_TLV("IN2 Boost", RT5677_IN1, RT5677_BST_SFT2, 8, 0, bst_tlv), + +	/* ADC Digital Volume Control */ +	SOC_DOUBLE("ADC1 Capture Switch", RT5677_STO1_ADC_DIG_VOL, +		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE("ADC2 Capture Switch", RT5677_STO2_ADC_DIG_VOL, +		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE("ADC3 Capture Switch", RT5677_STO3_ADC_DIG_VOL, +		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE("ADC4 Capture Switch", RT5677_STO4_ADC_DIG_VOL, +		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE("Mono ADC Capture Switch", RT5677_MONO_ADC_DIG_VOL, +		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), + +	SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL, +		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, +		adc_vol_tlv), +	SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL, +		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, +		adc_vol_tlv), +	SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL, +		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, +		adc_vol_tlv), +	SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL, +		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, +		adc_vol_tlv), +	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL, +		RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0, +		adc_vol_tlv), + +	/* ADC Boost Volume Control */ +	SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5677_STO1_2_ADC_BST, +		RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0, +		adc_bst_tlv), +	SOC_DOUBLE_TLV("STO2 ADC Boost Gain", RT5677_STO1_2_ADC_BST, +		RT5677_STO2_ADC_L_BST_SFT, RT5677_STO2_ADC_R_BST_SFT, 3, 0, +		adc_bst_tlv), +	SOC_DOUBLE_TLV("STO3 ADC Boost Gain", RT5677_STO3_4_ADC_BST, +		RT5677_STO3_ADC_L_BST_SFT, RT5677_STO3_ADC_R_BST_SFT, 3, 0, +		adc_bst_tlv), +	SOC_DOUBLE_TLV("STO4 ADC Boost Gain", RT5677_STO3_4_ADC_BST, +		RT5677_STO4_ADC_L_BST_SFT, RT5677_STO4_ADC_R_BST_SFT, 3, 0, +		adc_bst_tlv), +	SOC_DOUBLE_TLV("Mono ADC Boost Gain", RT5677_ADC_BST_CTRL2, +		RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, +		adc_bst_tlv), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); +	int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL, i; +	int rate, red, bound, temp; + +	rate = rt5677->sysclk; +	red = 3000000 * 12; +	for (i = 0; i < ARRAY_SIZE(div); i++) { +		bound = div[i] * 3000000; +		if (rate > bound) +			continue; +		temp = bound - rate; +		if (temp < red) { +			red = temp; +			idx = i; +		} +	} + +	if (idx < 0) +		dev_err(codec->dev, "Failed to set DMIC clock\n"); +	else +		regmap_update_bits(rt5677->regmap, RT5677_DMIC_CTRL1, +			RT5677_DMIC_CLK_MASK, idx << RT5677_DMIC_CLK_SFT); +	return idx; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, +			 struct snd_soc_dapm_widget *sink) +{ +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(source->codec); +	unsigned int val; + +	regmap_read(rt5677->regmap, RT5677_GLB_CLK1, &val); +	val &= RT5677_SCLK_SRC_MASK; +	if (val == RT5677_SCLK_SRC_PLL1) +		return 1; +	else +		return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER, +			RT5677_M_STO1_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO1_ADC_MIXER, +			RT5677_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto1_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER, +			RT5677_M_STO1_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO1_ADC_MIXER, +			RT5677_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto2_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO2_ADC_MIXER, +			RT5677_M_STO2_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO2_ADC_MIXER, +			RT5677_M_STO2_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto2_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO2_ADC_MIXER, +			RT5677_M_STO2_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO2_ADC_MIXER, +			RT5677_M_STO2_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto3_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO3_ADC_MIXER, +			RT5677_M_STO3_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO3_ADC_MIXER, +			RT5677_M_STO3_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto3_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO3_ADC_MIXER, +			RT5677_M_STO3_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO3_ADC_MIXER, +			RT5677_M_STO3_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto4_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO4_ADC_MIXER, +			RT5677_M_STO4_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO4_ADC_MIXER, +			RT5677_M_STO4_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto4_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO4_ADC_MIXER, +			RT5677_M_STO4_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO4_ADC_MIXER, +			RT5677_M_STO4_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_mono_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_MONO_ADC_MIXER, +			RT5677_M_MONO_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_MONO_ADC_MIXER, +			RT5677_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_mono_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_MONO_ADC_MIXER, +			RT5677_M_MONO_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_MONO_ADC_MIXER, +			RT5677_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_dac_l_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5677_ADC_IF_DSP_DAC1_MIXER, +			RT5677_M_ADDA_MIXER1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 Switch", RT5677_ADC_IF_DSP_DAC1_MIXER, +			RT5677_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_dac_r_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5677_ADC_IF_DSP_DAC1_MIXER, +			RT5677_M_ADDA_MIXER1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 Switch", RT5677_ADC_IF_DSP_DAC1_MIXER, +			RT5677_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto1_dac_l_mix[] = { +	SOC_DAPM_SINGLE("ST L Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_ST_DAC1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_DAC1_L_STO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_DAC2_L_STO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_DAC1_R_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_sto1_dac_r_mix[] = { +	SOC_DAPM_SINGLE("ST R Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_ST_DAC1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_DAC1_R_STO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_DAC2_R_STO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER, +			RT5677_M_DAC1_L_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_mono_dac_l_mix[] = { +	SOC_DAPM_SINGLE("ST L Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_ST_DAC2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_DAC1_L_MONO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_DAC2_L_MONO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_DAC2_R_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_mono_dac_r_mix[] = { +	SOC_DAPM_SINGLE("ST R Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_ST_DAC2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_DAC1_R_MONO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_DAC2_R_MONO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER, +			RT5677_M_DAC2_L_MONO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_dd1_l_mix[] = { +	SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER, +			RT5677_M_STO_L_DD1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER, +			RT5677_M_MONO_L_DD1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER, +			RT5677_M_DAC3_L_DD1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER, +			RT5677_M_DAC3_R_DD1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_dd1_r_mix[] = { +	SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER, +			RT5677_M_STO_R_DD1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER, +			RT5677_M_MONO_R_DD1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER, +			RT5677_M_DAC3_R_DD1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER, +			RT5677_M_DAC3_L_DD1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_dd2_l_mix[] = { +	SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER, +			RT5677_M_STO_L_DD2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER, +			RT5677_M_MONO_L_DD2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER, +			RT5677_M_DAC4_L_DD2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER, +			RT5677_M_DAC4_R_DD2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_dd2_r_mix[] = { +	SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER, +			RT5677_M_STO_R_DD2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER, +			RT5677_M_MONO_R_DD2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER, +			RT5677_M_DAC4_R_DD2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER, +			RT5677_M_DAC4_L_DD2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_ob_01_mix[] = { +	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_01_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_23_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_45_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_6_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_7_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_8_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_9_H_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_ob_23_mix[] = { +	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_01_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_23_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_45_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_6_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_7_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_8_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL, +			RT5677_DSP_IB_9_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_ob_4_mix[] = { +	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_01_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_23_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_45_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_6_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_7_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_8_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_9_H_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_ob_5_mix[] = { +	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_01_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_23_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_45_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_6_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_7_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_8_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL, +			RT5677_DSP_IB_9_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_ob_6_mix[] = { +	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_01_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_23_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_45_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_6_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_7_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_8_H_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_9_H_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5677_ob_7_mix[] = { +	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_01_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_23_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_45_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_6_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_7_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_8_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL, +			RT5677_DSP_IB_9_L_SFT, 1, 1), +}; + + +/* Mux */ +/* DAC1 L/R source */ /* MX-29 [10:8] */ +static const char * const rt5677_dac1_src[] = { +	"IF1 DAC 01", "IF2 DAC 01", "IF3 DAC LR", "IF4 DAC LR", "SLB DAC 01", +	"OB 01" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac1_enum, RT5677_ADC_IF_DSP_DAC1_MIXER, +	RT5677_DAC1_L_SEL_SFT, rt5677_dac1_src); + +static const struct snd_kcontrol_new rt5677_dac1_mux = +	SOC_DAPM_ENUM("DAC1 source", rt5677_dac1_enum); + +/* ADDA1 L/R source */ /* MX-29 [1:0] */ +static const char * const rt5677_adda1_src[] = { +	"STO1 ADC MIX", "STO2 ADC MIX", "OB 67", +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_adda1_enum, RT5677_ADC_IF_DSP_DAC1_MIXER, +	RT5677_ADDA1_SEL_SFT, rt5677_adda1_src); + +static const struct snd_kcontrol_new rt5677_adda1_mux = +	SOC_DAPM_ENUM("ADDA1 source", rt5677_adda1_enum); + + +/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */ +static const char * const rt5677_dac2l_src[] = { +	"IF1 DAC 2", "IF2 DAC 2", "IF3 DAC L", "IF4 DAC L", "SLB DAC 2", +	"OB 2", +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac2l_enum, RT5677_IF_DSP_DAC2_MIXER, +	RT5677_SEL_DAC2_L_SRC_SFT, rt5677_dac2l_src); + +static const struct snd_kcontrol_new rt5677_dac2_l_mux = +	SOC_DAPM_ENUM("DAC2 L source", rt5677_dac2l_enum); + +static const char * const rt5677_dac2r_src[] = { +	"IF1 DAC 3", "IF2 DAC 3", "IF3 DAC R", "IF4 DAC R", "SLB DAC 3", +	"OB 3", "Haptic Generator", "VAD ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac2r_enum, RT5677_IF_DSP_DAC2_MIXER, +	RT5677_SEL_DAC2_R_SRC_SFT, rt5677_dac2r_src); + +static const struct snd_kcontrol_new rt5677_dac2_r_mux = +	SOC_DAPM_ENUM("DAC2 R source", rt5677_dac2r_enum); + +/*DAC3 L/R source*/ /* MX-16 [6:4] [2:0] */ +static const char * const rt5677_dac3l_src[] = { +	"IF1 DAC 4", "IF2 DAC 4", "IF3 DAC L", "IF4 DAC L", +	"SLB DAC 4", "OB 4" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac3l_enum, RT5677_IF_DSP_DAC3_4_MIXER, +	RT5677_SEL_DAC3_L_SRC_SFT, rt5677_dac3l_src); + +static const struct snd_kcontrol_new rt5677_dac3_l_mux = +	SOC_DAPM_ENUM("DAC3 L source", rt5677_dac3l_enum); + +static const char * const rt5677_dac3r_src[] = { +	"IF1 DAC 5", "IF2 DAC 5", "IF3 DAC R", "IF4 DAC R", +	"SLB DAC 5", "OB 5" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac3r_enum, RT5677_IF_DSP_DAC3_4_MIXER, +	RT5677_SEL_DAC3_R_SRC_SFT, rt5677_dac3r_src); + +static const struct snd_kcontrol_new rt5677_dac3_r_mux = +	SOC_DAPM_ENUM("DAC3 R source", rt5677_dac3r_enum); + +/*DAC4 L/R source*/ /* MX-16 [14:12] [10:8] */ +static const char * const rt5677_dac4l_src[] = { +	"IF1 DAC 6", "IF2 DAC 6", "IF3 DAC L", "IF4 DAC L", +	"SLB DAC 6", "OB 6" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac4l_enum, RT5677_IF_DSP_DAC3_4_MIXER, +	RT5677_SEL_DAC4_L_SRC_SFT, rt5677_dac4l_src); + +static const struct snd_kcontrol_new rt5677_dac4_l_mux = +	SOC_DAPM_ENUM("DAC4 L source", rt5677_dac4l_enum); + +static const char * const rt5677_dac4r_src[] = { +	"IF1 DAC 7", "IF2 DAC 7", "IF3 DAC R", "IF4 DAC R", +	"SLB DAC 7", "OB 7" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac4r_enum, RT5677_IF_DSP_DAC3_4_MIXER, +	RT5677_SEL_DAC4_R_SRC_SFT, rt5677_dac4r_src); + +static const struct snd_kcontrol_new rt5677_dac4_r_mux = +	SOC_DAPM_ENUM("DAC4 R source", rt5677_dac4r_enum); + +/* In/OutBound Source Pass SRC */ /* MX-A5 [3] [4] [0] [1] [2] */ +static const char * const rt5677_iob_bypass_src[] = { +	"Bypass", "Pass SRC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_ob01_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, +	RT5677_SEL_SRC_OB01_SFT, rt5677_iob_bypass_src); + +static const struct snd_kcontrol_new rt5677_ob01_bypass_src_mux = +	SOC_DAPM_ENUM("OB01 Bypass source", rt5677_ob01_bypass_src_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_ob23_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, +	RT5677_SEL_SRC_OB23_SFT, rt5677_iob_bypass_src); + +static const struct snd_kcontrol_new rt5677_ob23_bypass_src_mux = +	SOC_DAPM_ENUM("OB23 Bypass source", rt5677_ob23_bypass_src_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_ib01_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, +	RT5677_SEL_SRC_IB01_SFT, rt5677_iob_bypass_src); + +static const struct snd_kcontrol_new rt5677_ib01_bypass_src_mux = +	SOC_DAPM_ENUM("IB01 Bypass source", rt5677_ib01_bypass_src_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_ib23_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, +	RT5677_SEL_SRC_IB23_SFT, rt5677_iob_bypass_src); + +static const struct snd_kcontrol_new rt5677_ib23_bypass_src_mux = +	SOC_DAPM_ENUM("IB23 Bypass source", rt5677_ib23_bypass_src_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_ib45_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, +	RT5677_SEL_SRC_IB45_SFT, rt5677_iob_bypass_src); + +static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux = +	SOC_DAPM_ENUM("IB45 Bypass source", rt5677_ib45_bypass_src_enum); + +/* Stereo ADC Source 2 */ /* MX-27 MX26  MX25 [11:10] */ +static const char * const rt5677_stereo_adc2_src[] = { +	"DD MIX1", "DMIC", "Stereo DAC MIX" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo1_adc2_enum, RT5677_STO1_ADC_MIXER, +	RT5677_SEL_STO1_ADC2_SFT, rt5677_stereo_adc2_src); + +static const struct snd_kcontrol_new rt5677_sto1_adc2_mux = +	SOC_DAPM_ENUM("Stereo1 ADC2 source", rt5677_stereo1_adc2_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo2_adc2_enum, RT5677_STO2_ADC_MIXER, +	RT5677_SEL_STO2_ADC2_SFT, rt5677_stereo_adc2_src); + +static const struct snd_kcontrol_new rt5677_sto2_adc2_mux = +	SOC_DAPM_ENUM("Stereo2 ADC2 source", rt5677_stereo2_adc2_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo3_adc2_enum, RT5677_STO3_ADC_MIXER, +	RT5677_SEL_STO3_ADC2_SFT, rt5677_stereo_adc2_src); + +static const struct snd_kcontrol_new rt5677_sto3_adc2_mux = +	SOC_DAPM_ENUM("Stereo3 ADC2 source", rt5677_stereo3_adc2_enum); + +/* DMIC Source */ /* MX-28 [9:8][1:0] MX-27 MX-26 MX-25 MX-24 [9:8] */ +static const char * const rt5677_dmic_src[] = { +	"DMIC1", "DMIC2", "DMIC3", "DMIC4" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_mono_dmic_l_enum, RT5677_MONO_ADC_MIXER, +	RT5677_SEL_MONO_DMIC_L_SFT, rt5677_dmic_src); + +static const struct snd_kcontrol_new rt5677_mono_dmic_l_mux = +	SOC_DAPM_ENUM("Mono DMIC L source", rt5677_mono_dmic_l_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_mono_dmic_r_enum, RT5677_MONO_ADC_MIXER, +	RT5677_SEL_MONO_DMIC_R_SFT, rt5677_dmic_src); + +static const struct snd_kcontrol_new rt5677_mono_dmic_r_mux = +	SOC_DAPM_ENUM("Mono DMIC R source", rt5677_mono_dmic_r_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo1_dmic_enum, RT5677_STO1_ADC_MIXER, +	RT5677_SEL_STO1_DMIC_SFT, rt5677_dmic_src); + +static const struct snd_kcontrol_new rt5677_sto1_dmic_mux = +	SOC_DAPM_ENUM("Stereo1 DMIC source", rt5677_stereo1_dmic_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo2_dmic_enum, RT5677_STO2_ADC_MIXER, +	RT5677_SEL_STO2_DMIC_SFT, rt5677_dmic_src); + +static const struct snd_kcontrol_new rt5677_sto2_dmic_mux = +	SOC_DAPM_ENUM("Stereo2 DMIC source", rt5677_stereo2_dmic_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo3_dmic_enum, RT5677_STO3_ADC_MIXER, +	RT5677_SEL_STO3_DMIC_SFT, rt5677_dmic_src); + +static const struct snd_kcontrol_new rt5677_sto3_dmic_mux = +	SOC_DAPM_ENUM("Stereo3 DMIC source", rt5677_stereo3_dmic_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo4_dmic_enum, RT5677_STO4_ADC_MIXER, +	RT5677_SEL_STO4_DMIC_SFT, rt5677_dmic_src); + +static const struct snd_kcontrol_new rt5677_sto4_dmic_mux = +	SOC_DAPM_ENUM("Stereo4 DMIC source", rt5677_stereo4_dmic_enum); + +/* Stereo2 ADC source */ /* MX-26 [0] */ +static const char * const rt5677_stereo2_adc_lr_src[] = { +	"L", "LR" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo2_adc_lr_enum, RT5677_STO2_ADC_MIXER, +	RT5677_SEL_STO2_LR_MIX_SFT, rt5677_stereo2_adc_lr_src); + +static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux = +	SOC_DAPM_ENUM("Stereo2 ADC LR source", rt5677_stereo2_adc_lr_enum); + +/* Stereo1 ADC Source 1 */ /* MX-27 MX26  MX25 [13:12] */ +static const char * const rt5677_stereo_adc1_src[] = { +	"DD MIX1", "ADC1/2", "Stereo DAC MIX" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo1_adc1_enum, RT5677_STO1_ADC_MIXER, +	RT5677_SEL_STO1_ADC1_SFT, rt5677_stereo_adc1_src); + +static const struct snd_kcontrol_new rt5677_sto1_adc1_mux = +	SOC_DAPM_ENUM("Stereo1 ADC1 source", rt5677_stereo1_adc1_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo2_adc1_enum, RT5677_STO2_ADC_MIXER, +	RT5677_SEL_STO2_ADC1_SFT, rt5677_stereo_adc1_src); + +static const struct snd_kcontrol_new rt5677_sto2_adc1_mux = +	SOC_DAPM_ENUM("Stereo2 ADC1 source", rt5677_stereo2_adc1_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo3_adc1_enum, RT5677_STO3_ADC_MIXER, +	RT5677_SEL_STO3_ADC1_SFT, rt5677_stereo_adc1_src); + +static const struct snd_kcontrol_new rt5677_sto3_adc1_mux = +	SOC_DAPM_ENUM("Stereo3 ADC1 source", rt5677_stereo3_adc1_enum); + +/* Mono ADC Left source 2 */ /* MX-28 [11:10] */ +static const char * const rt5677_mono_adc2_l_src[] = { +	"DD MIX1L", "DMIC", "MONO DAC MIXL" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_mono_adc2_l_enum, RT5677_MONO_ADC_MIXER, +	RT5677_SEL_MONO_ADC_L2_SFT, rt5677_mono_adc2_l_src); + +static const struct snd_kcontrol_new rt5677_mono_adc2_l_mux = +	SOC_DAPM_ENUM("Mono ADC2 L source", rt5677_mono_adc2_l_enum); + +/* Mono ADC Left source 1 */ /* MX-28 [13:12] */ +static const char * const rt5677_mono_adc1_l_src[] = { +	"DD MIX1L", "ADC1", "MONO DAC MIXL" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_mono_adc1_l_enum, RT5677_MONO_ADC_MIXER, +	RT5677_SEL_MONO_ADC_L1_SFT, rt5677_mono_adc1_l_src); + +static const struct snd_kcontrol_new rt5677_mono_adc1_l_mux = +	SOC_DAPM_ENUM("Mono ADC1 L source", rt5677_mono_adc1_l_enum); + +/* Mono ADC Right source 2 */ /* MX-28 [3:2] */ +static const char * const rt5677_mono_adc2_r_src[] = { +	"DD MIX1R", "DMIC", "MONO DAC MIXR" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_mono_adc2_r_enum, RT5677_MONO_ADC_MIXER, +	RT5677_SEL_MONO_ADC_R2_SFT, rt5677_mono_adc2_r_src); + +static const struct snd_kcontrol_new rt5677_mono_adc2_r_mux = +	SOC_DAPM_ENUM("Mono ADC2 R source", rt5677_mono_adc2_r_enum); + +/* Mono ADC Right source 1 */ /* MX-28 [5:4] */ +static const char * const rt5677_mono_adc1_r_src[] = { +	"DD MIX1R", "ADC2", "MONO DAC MIXR" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_mono_adc1_r_enum, RT5677_MONO_ADC_MIXER, +	RT5677_SEL_MONO_ADC_R1_SFT, rt5677_mono_adc1_r_src); + +static const struct snd_kcontrol_new rt5677_mono_adc1_r_mux = +	SOC_DAPM_ENUM("Mono ADC1 R source", rt5677_mono_adc1_r_enum); + +/* Stereo4 ADC Source 2 */ /* MX-24 [11:10] */ +static const char * const rt5677_stereo4_adc2_src[] = { +	"DD MIX1", "DMIC", "DD MIX2" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo4_adc2_enum, RT5677_STO4_ADC_MIXER, +	RT5677_SEL_STO4_ADC2_SFT, rt5677_stereo4_adc2_src); + +static const struct snd_kcontrol_new rt5677_sto4_adc2_mux = +	SOC_DAPM_ENUM("Stereo4 ADC2 source", rt5677_stereo4_adc2_enum); + + +/* Stereo4 ADC Source 1 */ /* MX-24 [13:12] */ +static const char * const rt5677_stereo4_adc1_src[] = { +	"DD MIX1", "ADC1/2", "DD MIX2" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_stereo4_adc1_enum, RT5677_STO4_ADC_MIXER, +	RT5677_SEL_STO4_ADC1_SFT, rt5677_stereo4_adc1_src); + +static const struct snd_kcontrol_new rt5677_sto4_adc1_mux = +	SOC_DAPM_ENUM("Stereo4 ADC1 source", rt5677_stereo4_adc1_enum); + +/* InBound0/1 Source */ /* MX-A3 [14:12] */ +static const char * const rt5677_inbound01_src[] = { +	"IF1 DAC 01", "IF2 DAC 01", "SLB DAC 01", "STO1 ADC MIX", +	"VAD ADC/DAC1 FS" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_inbound01_enum, RT5677_DSP_INB_CTRL1, +	RT5677_IB01_SRC_SFT, rt5677_inbound01_src); + +static const struct snd_kcontrol_new rt5677_ib01_src_mux = +	SOC_DAPM_ENUM("InBound0/1 Source", rt5677_inbound01_enum); + +/* InBound2/3 Source */ /* MX-A3 [10:8] */ +static const char * const rt5677_inbound23_src[] = { +	"IF1 DAC 23", "IF2 DAC 23", "SLB DAC 23", "STO2 ADC MIX", +	"DAC1 FS", "IF4 DAC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_inbound23_enum, RT5677_DSP_INB_CTRL1, +	RT5677_IB23_SRC_SFT, rt5677_inbound23_src); + +static const struct snd_kcontrol_new rt5677_ib23_src_mux = +	SOC_DAPM_ENUM("InBound2/3 Source", rt5677_inbound23_enum); + +/* InBound4/5 Source */ /* MX-A3 [6:4] */ +static const char * const rt5677_inbound45_src[] = { +	"IF1 DAC 45", "IF2 DAC 45", "SLB DAC 45", "STO3 ADC MIX", +	"IF3 DAC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_inbound45_enum, RT5677_DSP_INB_CTRL1, +	RT5677_IB45_SRC_SFT, rt5677_inbound45_src); + +static const struct snd_kcontrol_new rt5677_ib45_src_mux = +	SOC_DAPM_ENUM("InBound4/5 Source", rt5677_inbound45_enum); + +/* InBound6 Source */ /* MX-A3 [2:0] */ +static const char * const rt5677_inbound6_src[] = { +	"IF1 DAC 6", "IF2 DAC 6", "SLB DAC 6", "STO4 ADC MIX L", +	"IF4 DAC L", "STO1 ADC MIX L", "STO2 ADC MIX L", "STO3 ADC MIX L" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_inbound6_enum, RT5677_DSP_INB_CTRL1, +	RT5677_IB6_SRC_SFT, rt5677_inbound6_src); + +static const struct snd_kcontrol_new rt5677_ib6_src_mux = +	SOC_DAPM_ENUM("InBound6 Source", rt5677_inbound6_enum); + +/* InBound7 Source */ /* MX-A4 [14:12] */ +static const char * const rt5677_inbound7_src[] = { +	"IF1 DAC 7", "IF2 DAC 7", "SLB DAC 7", "STO4 ADC MIX R", +	"IF4 DAC R", "STO1 ADC MIX R", "STO2 ADC MIX R", "STO3 ADC MIX R" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_inbound7_enum, RT5677_DSP_INB_CTRL2, +	RT5677_IB7_SRC_SFT, rt5677_inbound7_src); + +static const struct snd_kcontrol_new rt5677_ib7_src_mux = +	SOC_DAPM_ENUM("InBound7 Source", rt5677_inbound7_enum); + +/* InBound8 Source */ /* MX-A4 [10:8] */ +static const char * const rt5677_inbound8_src[] = { +	"STO1 ADC MIX L", "STO2 ADC MIX L", "STO3 ADC MIX L", "STO4 ADC MIX L", +	"MONO ADC MIX L", "DACL1 FS" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_inbound8_enum, RT5677_DSP_INB_CTRL2, +	RT5677_IB8_SRC_SFT, rt5677_inbound8_src); + +static const struct snd_kcontrol_new rt5677_ib8_src_mux = +	SOC_DAPM_ENUM("InBound8 Source", rt5677_inbound8_enum); + +/* InBound9 Source */ /* MX-A4 [6:4] */ +static const char * const rt5677_inbound9_src[] = { +	"STO1 ADC MIX R", "STO2 ADC MIX R", "STO3 ADC MIX R", "STO4 ADC MIX R", +	"MONO ADC MIX R", "DACR1 FS", "DAC1 FS" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_inbound9_enum, RT5677_DSP_INB_CTRL2, +	RT5677_IB9_SRC_SFT, rt5677_inbound9_src); + +static const struct snd_kcontrol_new rt5677_ib9_src_mux = +	SOC_DAPM_ENUM("InBound9 Source", rt5677_inbound9_enum); + +/* VAD Source */ /* MX-9F [6:4] */ +static const char * const rt5677_vad_src[] = { +	"STO1 ADC MIX L", "MONO ADC MIX L", "MONO ADC MIX R", "STO2 ADC MIX L", +	"STO3 ADC MIX L" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_vad_enum, RT5677_VAD_CTRL4, +	RT5677_VAD_SRC_SFT, rt5677_vad_src); + +static const struct snd_kcontrol_new rt5677_vad_src_mux = +	SOC_DAPM_ENUM("VAD Source", rt5677_vad_enum); + +/* Sidetone Source */ /* MX-13 [11:9] */ +static const char * const rt5677_sidetone_src[] = { +	"DMIC1 L", "DMIC2 L", "DMIC3 L", "DMIC4 L", "ADC1", "ADC2" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_sidetone_enum, RT5677_SIDETONE_CTRL, +	RT5677_ST_SEL_SFT, rt5677_sidetone_src); + +static const struct snd_kcontrol_new rt5677_sidetone_mux = +	SOC_DAPM_ENUM("Sidetone Source", rt5677_sidetone_enum); + +/* DAC1/2 Source */ /* MX-15 [1:0] */ +static const char * const rt5677_dac12_src[] = { +	"STO1 DAC MIX", "MONO DAC MIX", "DD MIX1", "DD MIX2" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac12_enum, RT5677_ANA_DAC1_2_3_SRC, +	RT5677_ANA_DAC1_2_SRC_SEL_SFT, rt5677_dac12_src); + +static const struct snd_kcontrol_new rt5677_dac12_mux = +	SOC_DAPM_ENUM("Analog DAC1/2 Source", rt5677_dac12_enum); + +/* DAC3 Source */ /* MX-15 [5:4] */ +static const char * const rt5677_dac3_src[] = { +	"MONO DAC MIXL", "MONO DAC MIXR", "DD MIX1L", "DD MIX2L" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_dac3_enum, RT5677_ANA_DAC1_2_3_SRC, +	RT5677_ANA_DAC3_SRC_SEL_SFT, rt5677_dac3_src); + +static const struct snd_kcontrol_new rt5677_dac3_mux = +	SOC_DAPM_ENUM("Analog DAC3 Source", rt5677_dac3_enum); + +/* PDM channel source */ /* MX-31 [13:12][9:8][5:4][1:0] */ +static const char * const rt5677_pdm_src[] = { +	"STO1 DAC MIX", "MONO DAC MIX", "DD MIX1", "DD MIX2" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_pdm1_l_enum, RT5677_PDM_OUT_CTRL, +	RT5677_SEL_PDM1_L_SFT, rt5677_pdm_src); + +static const struct snd_kcontrol_new rt5677_pdm1_l_mux = +	SOC_DAPM_ENUM("PDM1 source", rt5677_pdm1_l_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_pdm2_l_enum, RT5677_PDM_OUT_CTRL, +	RT5677_SEL_PDM2_L_SFT, rt5677_pdm_src); + +static const struct snd_kcontrol_new rt5677_pdm2_l_mux = +	SOC_DAPM_ENUM("PDM2 source", rt5677_pdm2_l_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_pdm1_r_enum, RT5677_PDM_OUT_CTRL, +	RT5677_SEL_PDM1_R_SFT, rt5677_pdm_src); + +static const struct snd_kcontrol_new rt5677_pdm1_r_mux = +	SOC_DAPM_ENUM("PDM1 source", rt5677_pdm1_r_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_pdm2_r_enum, RT5677_PDM_OUT_CTRL, +	RT5677_SEL_PDM2_R_SFT, rt5677_pdm_src); + +static const struct snd_kcontrol_new rt5677_pdm2_r_mux = +	SOC_DAPM_ENUM("PDM2 source", rt5677_pdm2_r_enum); + +/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0]*/ +static const char * const rt5677_if12_adc1_src[] = { +	"STO1 ADC MIX", "OB01", "VAD ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if1_adc1_enum, RT5677_TDM1_CTRL2, +	RT5677_IF1_ADC1_SFT, rt5677_if12_adc1_src); + +static const struct snd_kcontrol_new rt5677_if1_adc1_mux = +	SOC_DAPM_ENUM("IF1 ADC1 source", rt5677_if1_adc1_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if2_adc1_enum, RT5677_TDM2_CTRL2, +	RT5677_IF2_ADC1_SFT, rt5677_if12_adc1_src); + +static const struct snd_kcontrol_new rt5677_if2_adc1_mux = +	SOC_DAPM_ENUM("IF2 ADC1 source", rt5677_if2_adc1_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_slb_adc1_enum, RT5677_SLIMBUS_RX, +	RT5677_SLB_ADC1_SFT, rt5677_if12_adc1_src); + +static const struct snd_kcontrol_new rt5677_slb_adc1_mux = +	SOC_DAPM_ENUM("SLB ADC1 source", rt5677_slb_adc1_enum); + +/* TDM IF1/2 SLB ADC2 Data Selection */ /* MX-3C MX-41 [7:6] MX-08 [3:2] */ +static const char * const rt5677_if12_adc2_src[] = { +	"STO2 ADC MIX", "OB23" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if1_adc2_enum, RT5677_TDM1_CTRL2, +	RT5677_IF1_ADC2_SFT, rt5677_if12_adc2_src); + +static const struct snd_kcontrol_new rt5677_if1_adc2_mux = +	SOC_DAPM_ENUM("IF1 ADC2 source", rt5677_if1_adc2_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if2_adc2_enum, RT5677_TDM2_CTRL2, +	RT5677_IF2_ADC2_SFT, rt5677_if12_adc2_src); + +static const struct snd_kcontrol_new rt5677_if2_adc2_mux = +	SOC_DAPM_ENUM("IF2 ADC2 source", rt5677_if2_adc2_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_slb_adc2_enum, RT5677_SLIMBUS_RX, +	RT5677_SLB_ADC2_SFT, rt5677_if12_adc2_src); + +static const struct snd_kcontrol_new rt5677_slb_adc2_mux = +	SOC_DAPM_ENUM("SLB ADC2 source", rt5677_slb_adc2_enum); + +/* TDM IF1/2 SLB ADC3 Data Selection */ /* MX-3C MX-41 [9:8] MX-08 [5:4] */ +static const char * const rt5677_if12_adc3_src[] = { +	"STO3 ADC MIX", "MONO ADC MIX", "OB45" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if1_adc3_enum, RT5677_TDM1_CTRL2, +	RT5677_IF1_ADC3_SFT, rt5677_if12_adc3_src); + +static const struct snd_kcontrol_new rt5677_if1_adc3_mux = +	SOC_DAPM_ENUM("IF1 ADC3 source", rt5677_if1_adc3_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if2_adc3_enum, RT5677_TDM2_CTRL2, +	RT5677_IF2_ADC3_SFT, rt5677_if12_adc3_src); + +static const struct snd_kcontrol_new rt5677_if2_adc3_mux = +	SOC_DAPM_ENUM("IF2 ADC3 source", rt5677_if2_adc3_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_slb_adc3_enum, RT5677_SLIMBUS_RX, +	RT5677_SLB_ADC3_SFT, rt5677_if12_adc3_src); + +static const struct snd_kcontrol_new rt5677_slb_adc3_mux = +	SOC_DAPM_ENUM("SLB ADC3 source", rt5677_slb_adc3_enum); + +/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10]  MX-08 [7:6] */ +static const char * const rt5677_if12_adc4_src[] = { +	"STO4 ADC MIX", "OB67", "OB01" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if1_adc4_enum, RT5677_TDM1_CTRL2, +	RT5677_IF1_ADC4_SFT, rt5677_if12_adc4_src); + +static const struct snd_kcontrol_new rt5677_if1_adc4_mux = +	SOC_DAPM_ENUM("IF1 ADC4 source", rt5677_if1_adc4_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if2_adc4_enum, RT5677_TDM2_CTRL2, +	RT5677_IF2_ADC4_SFT, rt5677_if12_adc4_src); + +static const struct snd_kcontrol_new rt5677_if2_adc4_mux = +	SOC_DAPM_ENUM("IF2 ADC4 source", rt5677_if2_adc4_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_slb_adc4_enum, RT5677_SLIMBUS_RX, +	RT5677_SLB_ADC4_SFT, rt5677_if12_adc4_src); + +static const struct snd_kcontrol_new rt5677_slb_adc4_mux = +	SOC_DAPM_ENUM("SLB ADC4 source", rt5677_slb_adc4_enum); + +/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4]*/ +static const char * const rt5677_if34_adc_src[] = { +	"STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX", +	"MONO ADC MIX", "OB01", "OB23", "VAD ADC" +}; + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if3_adc_enum, RT5677_IF3_DATA, +	RT5677_IF3_ADC_IN_SFT, rt5677_if34_adc_src); + +static const struct snd_kcontrol_new rt5677_if3_adc_mux = +	SOC_DAPM_ENUM("IF3 ADC source", rt5677_if3_adc_enum); + +static SOC_ENUM_SINGLE_DECL( +	rt5677_if4_adc_enum, RT5677_IF4_DATA, +	RT5677_IF4_ADC_IN_SFT, rt5677_if34_adc_src); + +static const struct snd_kcontrol_new rt5677_if4_adc_mux = +	SOC_DAPM_ENUM("IF4 ADC source", rt5677_if4_adc_enum); + +static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, +			RT5677_PWR_BST1_P, RT5677_PWR_BST1_P); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, +			RT5677_PWR_BST1_P, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5677_bst2_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, +			RT5677_PWR_BST2_P, RT5677_PWR_BST2_P); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, +			RT5677_PWR_BST2_P, 0); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x2); +		regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x0); +		break; +	default: +		return 0; +	} + +	return 0; +} + +static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x2); +		regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x0); +		break; +	default: +		return 0; +	} + +	return 0; +} + +static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, +			RT5677_PWR_CLK_MB1 | RT5677_PWR_PP_MB1 | +			RT5677_PWR_CLK_MB, RT5677_PWR_CLK_MB1 | +			RT5677_PWR_PP_MB1 | RT5677_PWR_CLK_MB); +		break; +	default: +		return 0; +	} + +	return 0; +} + +static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, +		0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_SUPPLY("PLL2", RT5677_PWR_ANLG2, RT5677_PWR_PLL2_BIT, +		0, rt5677_set_pll2_event, SND_SOC_DAPM_POST_PMU), + +	/* Input Side */ +	/* micbias */ +	SND_SOC_DAPM_SUPPLY("micbias1", RT5677_PWR_ANLG2, RT5677_PWR_MB1_BIT, +		0, rt5677_set_micbias1_event, SND_SOC_DAPM_POST_PMU), + +	/* Input Lines */ +	SND_SOC_DAPM_INPUT("DMIC L1"), +	SND_SOC_DAPM_INPUT("DMIC R1"), +	SND_SOC_DAPM_INPUT("DMIC L2"), +	SND_SOC_DAPM_INPUT("DMIC R2"), +	SND_SOC_DAPM_INPUT("DMIC L3"), +	SND_SOC_DAPM_INPUT("DMIC R3"), +	SND_SOC_DAPM_INPUT("DMIC L4"), +	SND_SOC_DAPM_INPUT("DMIC R4"), + +	SND_SOC_DAPM_INPUT("IN1P"), +	SND_SOC_DAPM_INPUT("IN1N"), +	SND_SOC_DAPM_INPUT("IN2P"), +	SND_SOC_DAPM_INPUT("IN2N"), + +	SND_SOC_DAPM_INPUT("Haptic Generator"), + +	SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0, +		NULL, 0), +	SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0, +		NULL, 0), +	SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0, +		NULL, 0), +	SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0, +		NULL, 0), + +	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, +		set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + +	/* Boost */ +	SND_SOC_DAPM_PGA_E("BST1", RT5677_PWR_ANLG2, +		RT5677_PWR_BST1_BIT, 0, NULL, 0, rt5677_bst1_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_PGA_E("BST2", RT5677_PWR_ANLG2, +		RT5677_PWR_BST2_BIT, 0, NULL, 0, rt5677_bst2_event, +		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + +	/* ADCs */ +	SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, +		0, 0), +	SND_SOC_DAPM_ADC("ADC 2", NULL, SND_SOC_NOPM, +		0, 0), +	SND_SOC_DAPM_PGA("ADC 1_2", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("ADC 1 power", RT5677_PWR_DIG1, +		RT5677_PWR_ADC_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC 2 power", RT5677_PWR_DIG1, +		RT5677_PWR_ADC_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5677_PWR_DIG1, +		RT5677_PWR_ADCFED1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC2 clock", RT5677_PWR_DIG1, +		RT5677_PWR_ADCFED2_BIT, 0, NULL, 0), + +	/* ADC Mux */ +	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto1_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC1 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto1_adc1_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC2 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto1_adc2_mux), +	SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto2_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC1 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto2_adc1_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC2 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto2_adc2_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC LR Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto2_adc_lr_mux), +	SND_SOC_DAPM_MUX("Stereo3 DMIC Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto3_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo3 ADC1 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto3_adc1_mux), +	SND_SOC_DAPM_MUX("Stereo3 ADC2 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto3_adc2_mux), +	SND_SOC_DAPM_MUX("Stereo4 DMIC Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto4_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo4 ADC1 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto4_adc1_mux), +	SND_SOC_DAPM_MUX("Stereo4 ADC2 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_sto4_adc2_mux), +	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_mono_dmic_l_mux), +	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_mono_dmic_r_mux), +	SND_SOC_DAPM_MUX("Mono ADC2 L Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_mono_adc2_l_mux), +	SND_SOC_DAPM_MUX("Mono ADC1 L Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_mono_adc1_l_mux), +	SND_SOC_DAPM_MUX("Mono ADC1 R Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_mono_adc1_r_mux), +	SND_SOC_DAPM_MUX("Mono ADC2 R Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_mono_adc2_r_mux), + +	/* ADC Mixer */ +	SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5677_PWR_DIG2, +		RT5677_PWR_ADC_S1F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("adc stereo2 filter", RT5677_PWR_DIG2, +		RT5677_PWR_ADC_S2F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("adc stereo3 filter", RT5677_PWR_DIG2, +		RT5677_PWR_ADC_S3F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("adc stereo4 filter", RT5677_PWR_DIG2, +		RT5677_PWR_ADC_S4F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_sto1_adc_l_mix, ARRAY_SIZE(rt5677_sto1_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_sto1_adc_r_mix, ARRAY_SIZE(rt5677_sto1_adc_r_mix)), +	SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_sto2_adc_l_mix, ARRAY_SIZE(rt5677_sto2_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Sto2 ADC MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_sto2_adc_r_mix, ARRAY_SIZE(rt5677_sto2_adc_r_mix)), +	SND_SOC_DAPM_MIXER("Sto3 ADC MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_sto3_adc_l_mix, ARRAY_SIZE(rt5677_sto3_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Sto3 ADC MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_sto3_adc_r_mix, ARRAY_SIZE(rt5677_sto3_adc_r_mix)), +	SND_SOC_DAPM_MIXER("Sto4 ADC MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_sto4_adc_l_mix, ARRAY_SIZE(rt5677_sto4_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Sto4 ADC MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_sto4_adc_r_mix, ARRAY_SIZE(rt5677_sto4_adc_r_mix)), +	SND_SOC_DAPM_SUPPLY("adc mono left filter", RT5677_PWR_DIG2, +		RT5677_PWR_ADC_MF_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Mono ADC MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_mono_adc_l_mix, ARRAY_SIZE(rt5677_mono_adc_l_mix)), +	SND_SOC_DAPM_SUPPLY("adc mono right filter", RT5677_PWR_DIG2, +		RT5677_PWR_ADC_MF_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Mono ADC MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_mono_adc_r_mix, ARRAY_SIZE(rt5677_mono_adc_r_mix)), + +	/* ADC PGA */ +	SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo3 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo3 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo3 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo4 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo4 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* DSP */ +	SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib9_src_mux), +	SND_SOC_DAPM_MUX("IB8 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib8_src_mux), +	SND_SOC_DAPM_MUX("IB7 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib7_src_mux), +	SND_SOC_DAPM_MUX("IB6 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib6_src_mux), +	SND_SOC_DAPM_MUX("IB45 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib45_src_mux), +	SND_SOC_DAPM_MUX("IB23 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib23_src_mux), +	SND_SOC_DAPM_MUX("IB01 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib01_src_mux), +	SND_SOC_DAPM_MUX("IB45 Bypass Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib45_bypass_src_mux), +	SND_SOC_DAPM_MUX("IB23 Bypass Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib23_bypass_src_mux), +	SND_SOC_DAPM_MUX("IB01 Bypass Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ib01_bypass_src_mux), +	SND_SOC_DAPM_MUX("OB23 Bypass Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ob23_bypass_src_mux), +	SND_SOC_DAPM_MUX("OB01 Bypass Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_ob01_bypass_src_mux), + +	SND_SOC_DAPM_PGA("OB45", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("OB67", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_PGA("OutBound2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("OutBound3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("OutBound4", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("OutBound5", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("OutBound6", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("OutBound7", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* Digital Interface */ +	SND_SOC_DAPM_SUPPLY("I2S1", RT5677_PWR_DIG1, +		RT5677_PWR_I2S1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC4", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC5", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC6", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC7", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC01", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC23", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC45", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC67", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("I2S2", RT5677_PWR_DIG1, +		RT5677_PWR_I2S2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC4", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC5", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC6", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC7", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC01", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC23", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC45", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 DAC67", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2 ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("I2S3", RT5677_PWR_DIG1, +		RT5677_PWR_I2S3_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("I2S4", RT5677_PWR_DIG1, +		RT5677_PWR_I2S4_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF4 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF4 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF4 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF4 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF4 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF4 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("SLB", RT5677_PWR_DIG1, +		RT5677_PWR_SLB_BIT, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC0", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC4", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC5", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC6", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC7", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC01", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC23", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC45", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB DAC67", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("SLB ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* Digital Interface Select */ +	SND_SOC_DAPM_MUX("IF1 ADC1 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if1_adc1_mux), +	SND_SOC_DAPM_MUX("IF1 ADC2 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if1_adc2_mux), +	SND_SOC_DAPM_MUX("IF1 ADC3 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if1_adc3_mux), +	SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if1_adc4_mux), +	SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if2_adc1_mux), +	SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if2_adc2_mux), +	SND_SOC_DAPM_MUX("IF2 ADC3 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if2_adc3_mux), +	SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if2_adc4_mux), +	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if3_adc_mux), +	SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_if4_adc_mux), +	SND_SOC_DAPM_MUX("SLB ADC1 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_slb_adc1_mux), +	SND_SOC_DAPM_MUX("SLB ADC2 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_slb_adc2_mux), +	SND_SOC_DAPM_MUX("SLB ADC3 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_slb_adc3_mux), +	SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_slb_adc4_mux), + +	/* Audio Interface */ +	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF4RX", "AIF4 Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF4TX", "AIF4 Capture", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("SLBRX", "SLIMBus Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("SLBTX", "SLIMBus Capture", 0, SND_SOC_NOPM, 0, 0), + +	/* Sidetone Mux */ +	SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_sidetone_mux), +	/* VAD Mux*/ +	SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_vad_src_mux), + +	/* Tensilica DSP */ +	SND_SOC_DAPM_PGA("Tensilica DSP", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("OB01 MIX", SND_SOC_NOPM, 0, 0, +		rt5677_ob_01_mix, ARRAY_SIZE(rt5677_ob_01_mix)), +	SND_SOC_DAPM_MIXER("OB23 MIX", SND_SOC_NOPM, 0, 0, +		rt5677_ob_23_mix, ARRAY_SIZE(rt5677_ob_23_mix)), +	SND_SOC_DAPM_MIXER("OB4 MIX", SND_SOC_NOPM, 0, 0, +		rt5677_ob_4_mix, ARRAY_SIZE(rt5677_ob_4_mix)), +	SND_SOC_DAPM_MIXER("OB5 MIX", SND_SOC_NOPM, 0, 0, +		rt5677_ob_5_mix, ARRAY_SIZE(rt5677_ob_5_mix)), +	SND_SOC_DAPM_MIXER("OB6 MIX", SND_SOC_NOPM, 0, 0, +		rt5677_ob_6_mix, ARRAY_SIZE(rt5677_ob_6_mix)), +	SND_SOC_DAPM_MIXER("OB7 MIX", SND_SOC_NOPM, 0, 0, +		rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)), + +	/* Output Side */ +	/* DAC mixer before sound effect  */ +	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)), +	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_dac_r_mix, ARRAY_SIZE(rt5677_dac_r_mix)), +	SND_SOC_DAPM_PGA("DAC1 FS", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* DAC Mux */ +	SND_SOC_DAPM_MUX("DAC1 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_dac1_mux), +	SND_SOC_DAPM_MUX("ADDA1 Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_adda1_mux), +	SND_SOC_DAPM_MUX("DAC12 SRC Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_dac12_mux), +	SND_SOC_DAPM_MUX("DAC3 SRC Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_dac3_mux), + +	/* DAC2 channel Mux */ +	SND_SOC_DAPM_MUX("DAC2 L Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_dac2_l_mux), +	SND_SOC_DAPM_MUX("DAC2 R Mux", SND_SOC_NOPM, 0, 0, +				&rt5677_dac2_r_mux), + +	/* DAC3 channel Mux */ +	SND_SOC_DAPM_MUX("DAC3 L Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_dac3_l_mux), +	SND_SOC_DAPM_MUX("DAC3 R Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_dac3_r_mux), + +	/* DAC4 channel Mux */ +	SND_SOC_DAPM_MUX("DAC4 L Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_dac4_l_mux), +	SND_SOC_DAPM_MUX("DAC4 R Mux", SND_SOC_NOPM, 0, 0, +			&rt5677_dac4_r_mux), + +	/* DAC Mixer */ +	SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2, +		RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("dac mono left filter", RT5677_PWR_DIG2, +		RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("dac mono right filter", RT5677_PWR_DIG2, +		RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0), + +	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_sto1_dac_r_mix, ARRAY_SIZE(rt5677_sto1_dac_r_mix)), +	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_mono_dac_l_mix, ARRAY_SIZE(rt5677_mono_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_mono_dac_r_mix, ARRAY_SIZE(rt5677_mono_dac_r_mix)), +	SND_SOC_DAPM_MIXER("DD1 MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_dd1_l_mix, ARRAY_SIZE(rt5677_dd1_l_mix)), +	SND_SOC_DAPM_MIXER("DD1 MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_dd1_r_mix, ARRAY_SIZE(rt5677_dd1_r_mix)), +	SND_SOC_DAPM_MIXER("DD2 MIXL", SND_SOC_NOPM, 0, 0, +		rt5677_dd2_l_mix, ARRAY_SIZE(rt5677_dd2_l_mix)), +	SND_SOC_DAPM_MIXER("DD2 MIXR", SND_SOC_NOPM, 0, 0, +		rt5677_dd2_r_mix, ARRAY_SIZE(rt5677_dd2_r_mix)), +	SND_SOC_DAPM_PGA("Stereo DAC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Mono DAC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DD1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DD2 MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* DACs */ +	SND_SOC_DAPM_DAC("DAC 1", NULL, RT5677_PWR_DIG1, +		RT5677_PWR_DAC1_BIT, 0), +	SND_SOC_DAPM_DAC("DAC 2", NULL, RT5677_PWR_DIG1, +		RT5677_PWR_DAC2_BIT, 0), +	SND_SOC_DAPM_DAC("DAC 3", NULL, RT5677_PWR_DIG1, +		RT5677_PWR_DAC3_BIT, 0), + +	/* PDM */ +	SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5677_PWR_DIG2, +		RT5677_PWR_PDM1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5677_PWR_DIG2, +		RT5677_PWR_PDM2_BIT, 0, NULL, 0), + +	SND_SOC_DAPM_MUX("PDM1 L Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM1_L_SFT, +		1, &rt5677_pdm1_l_mux), +	SND_SOC_DAPM_MUX("PDM1 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM1_R_SFT, +		1, &rt5677_pdm1_r_mux), +	SND_SOC_DAPM_MUX("PDM2 L Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_L_SFT, +		1, &rt5677_pdm2_l_mux), +	SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT, +		1, &rt5677_pdm2_r_mux), + +	SND_SOC_DAPM_PGA_S("LOUT1 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_PGA_S("LOUT2 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_PGA_S("LOUT3 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT, +		0, NULL, 0), + +	/* Output Lines */ +	SND_SOC_DAPM_OUTPUT("LOUT1"), +	SND_SOC_DAPM_OUTPUT("LOUT2"), +	SND_SOC_DAPM_OUTPUT("LOUT3"), +	SND_SOC_DAPM_OUTPUT("PDM1L"), +	SND_SOC_DAPM_OUTPUT("PDM1R"), +	SND_SOC_DAPM_OUTPUT("PDM2L"), +	SND_SOC_DAPM_OUTPUT("PDM2R"), +}; + +static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { +	{ "DMIC1", NULL, "DMIC L1" }, +	{ "DMIC1", NULL, "DMIC R1" }, +	{ "DMIC2", NULL, "DMIC L2" }, +	{ "DMIC2", NULL, "DMIC R2" }, +	{ "DMIC3", NULL, "DMIC L3" }, +	{ "DMIC3", NULL, "DMIC R3" }, +	{ "DMIC4", NULL, "DMIC L4" }, +	{ "DMIC4", NULL, "DMIC R4" }, + +	{ "DMIC L1", NULL, "DMIC CLK" }, +	{ "DMIC R1", NULL, "DMIC CLK" }, +	{ "DMIC L2", NULL, "DMIC CLK" }, +	{ "DMIC R2", NULL, "DMIC CLK" }, +	{ "DMIC L3", NULL, "DMIC CLK" }, +	{ "DMIC R3", NULL, "DMIC CLK" }, +	{ "DMIC L4", NULL, "DMIC CLK" }, +	{ "DMIC R4", NULL, "DMIC CLK" }, + +	{ "BST1", NULL, "IN1P" }, +	{ "BST1", NULL, "IN1N" }, +	{ "BST2", NULL, "IN2P" }, +	{ "BST2", NULL, "IN2N" }, + +	{ "IN1P", NULL, "micbias1" }, +	{ "IN1N", NULL, "micbias1" }, +	{ "IN2P", NULL, "micbias1" }, +	{ "IN2N", NULL, "micbias1" }, + +	{ "ADC 1", NULL, "BST1" }, +	{ "ADC 1", NULL, "ADC 1 power" }, +	{ "ADC 1", NULL, "ADC1 clock" }, +	{ "ADC 2", NULL, "BST2" }, +	{ "ADC 2", NULL, "ADC 2 power" }, +	{ "ADC 2", NULL, "ADC2 clock" }, + +	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, +	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, +	{ "Stereo1 DMIC Mux", "DMIC3", "DMIC3" }, +	{ "Stereo1 DMIC Mux", "DMIC4", "DMIC4" }, + +	{ "Stereo2 DMIC Mux", "DMIC1", "DMIC1" }, +	{ "Stereo2 DMIC Mux", "DMIC2", "DMIC2" }, +	{ "Stereo2 DMIC Mux", "DMIC3", "DMIC3" }, +	{ "Stereo2 DMIC Mux", "DMIC4", "DMIC4" }, + +	{ "Stereo3 DMIC Mux", "DMIC1", "DMIC1" }, +	{ "Stereo3 DMIC Mux", "DMIC2", "DMIC2" }, +	{ "Stereo3 DMIC Mux", "DMIC3", "DMIC3" }, +	{ "Stereo3 DMIC Mux", "DMIC4", "DMIC4" }, + +	{ "Stereo4 DMIC Mux", "DMIC1", "DMIC1" }, +	{ "Stereo4 DMIC Mux", "DMIC2", "DMIC2" }, +	{ "Stereo4 DMIC Mux", "DMIC3", "DMIC3" }, +	{ "Stereo4 DMIC Mux", "DMIC4", "DMIC4" }, + +	{ "Mono DMIC L Mux", "DMIC1", "DMIC1" }, +	{ "Mono DMIC L Mux", "DMIC2", "DMIC2" }, +	{ "Mono DMIC L Mux", "DMIC3", "DMIC3" }, +	{ "Mono DMIC L Mux", "DMIC4", "DMIC4" }, + +	{ "Mono DMIC R Mux", "DMIC1", "DMIC1" }, +	{ "Mono DMIC R Mux", "DMIC2", "DMIC2" }, +	{ "Mono DMIC R Mux", "DMIC3", "DMIC3" }, +	{ "Mono DMIC R Mux", "DMIC4", "DMIC4" }, + +	{ "ADC 1_2", NULL, "ADC 1" }, +	{ "ADC 1_2", NULL, "ADC 2" }, + +	{ "Stereo1 ADC1 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo1 ADC1 Mux", "ADC1/2", "ADC 1_2" }, +	{ "Stereo1 ADC1 Mux", "Stereo DAC MIX", "Stereo DAC MIX" }, + +	{ "Stereo1 ADC2 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo1 ADC2 Mux", "DMIC", "Stereo1 DMIC Mux" }, +	{ "Stereo1 ADC2 Mux", "Stereo DAC MIX", "Stereo DAC MIX" }, + +	{ "Stereo2 ADC1 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo2 ADC1 Mux", "ADC1/2", "ADC 1_2" }, +	{ "Stereo2 ADC1 Mux", "Stereo DAC MIX", "Stereo DAC MIX" }, + +	{ "Stereo2 ADC2 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo2 ADC2 Mux", "DMIC", "Stereo2 DMIC Mux" }, +	{ "Stereo2 ADC2 Mux", "Stereo DAC MIX", "Stereo DAC MIX" }, + +	{ "Stereo3 ADC1 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo3 ADC1 Mux", "ADC1/2", "ADC 1_2" }, +	{ "Stereo3 ADC1 Mux", "Stereo DAC MIX", "Stereo DAC MIX" }, + +	{ "Stereo3 ADC2 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo3 ADC2 Mux", "DMIC", "Stereo3 DMIC Mux" }, +	{ "Stereo3 ADC2 Mux", "Stereo DAC MIX", "Stereo DAC MIX" }, + +	{ "Stereo4 ADC1 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo4 ADC1 Mux", "ADC1/2", "ADC 1_2" }, +	{ "Stereo4 ADC1 Mux", "DD MIX2", "DD2 MIX" }, + +	{ "Stereo4 ADC2 Mux", "DD MIX1", "DD1 MIX" }, +	{ "Stereo4 ADC2 Mux", "DMIC", "Stereo3 DMIC Mux" }, +	{ "Stereo4 ADC2 Mux", "DD MIX2", "DD2 MIX" }, + +	{ "Mono ADC2 L Mux", "DD MIX1L", "DD1 MIXL" }, +	{ "Mono ADC2 L Mux", "DMIC", "Mono DMIC L Mux" }, +	{ "Mono ADC2 L Mux", "MONO DAC MIXL", "Mono DAC MIXL" }, + +	{ "Mono ADC1 L Mux", "DD MIX1L", "DD1 MIXL" }, +	{ "Mono ADC1 L Mux", "ADC1", "ADC 1" }, +	{ "Mono ADC1 L Mux", "MONO DAC MIXL", "Mono DAC MIXL" }, + +	{ "Mono ADC1 R Mux", "DD MIX1R", "DD1 MIXR" }, +	{ "Mono ADC1 R Mux", "ADC2", "ADC 2" }, +	{ "Mono ADC1 R Mux", "MONO DAC MIXR", "Mono DAC MIXR" }, + +	{ "Mono ADC2 R Mux", "DD MIX1R", "DD1 MIXR" }, +	{ "Mono ADC2 R Mux", "DMIC", "Mono DMIC R Mux" }, +	{ "Mono ADC2 R Mux", "MONO DAC MIXR", "Mono DAC MIXR" }, + +	{ "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC1 Mux" }, +	{ "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC2 Mux" }, +	{ "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC1 Mux" }, +	{ "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC2 Mux" }, + +	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, +	{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" }, +	{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, +	{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" }, +	{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL" }, +	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" }, + +	{ "Sto2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC1 Mux" }, +	{ "Sto2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC2 Mux" }, +	{ "Sto2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC1 Mux" }, +	{ "Sto2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC2 Mux" }, + +	{ "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXL" }, +	{ "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXR" }, + +	{ "Stereo2 ADC LR Mux", "L", "Sto2 ADC MIXL" }, +	{ "Stereo2 ADC LR Mux", "LR", "Sto2 ADC LR MIX" }, + +	{ "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" }, +	{ "Stereo2 ADC MIXL", NULL, "adc stereo2 filter" }, +	{ "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" }, +	{ "Stereo2 ADC MIXR", NULL, "adc stereo2 filter" }, +	{ "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL" }, +	{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" }, + +	{ "Sto3 ADC MIXL", "ADC1 Switch", "Stereo3 ADC1 Mux" }, +	{ "Sto3 ADC MIXL", "ADC2 Switch", "Stereo3 ADC2 Mux" }, +	{ "Sto3 ADC MIXR", "ADC1 Switch", "Stereo3 ADC1 Mux" }, +	{ "Sto3 ADC MIXR", "ADC2 Switch", "Stereo3 ADC2 Mux" }, + +	{ "Stereo3 ADC MIXL", NULL, "Sto3 ADC MIXL" }, +	{ "Stereo3 ADC MIXL", NULL, "adc stereo3 filter" }, +	{ "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo3 ADC MIXR", NULL, "Sto3 ADC MIXR" }, +	{ "Stereo3 ADC MIXR", NULL, "adc stereo3 filter" }, +	{ "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo3 ADC MIX", NULL, "Stereo3 ADC MIXL" }, +	{ "Stereo3 ADC MIX", NULL, "Stereo3 ADC MIXR" }, + +	{ "Sto4 ADC MIXL", "ADC1 Switch", "Stereo4 ADC1 Mux" }, +	{ "Sto4 ADC MIXL", "ADC2 Switch", "Stereo4 ADC2 Mux" }, +	{ "Sto4 ADC MIXR", "ADC1 Switch", "Stereo4 ADC1 Mux" }, +	{ "Sto4 ADC MIXR", "ADC2 Switch", "Stereo4 ADC2 Mux" }, + +	{ "Stereo4 ADC MIXL", NULL, "Sto4 ADC MIXL" }, +	{ "Stereo4 ADC MIXL", NULL, "adc stereo4 filter" }, +	{ "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo4 ADC MIXR", NULL, "Sto4 ADC MIXR" }, +	{ "Stereo4 ADC MIXR", NULL, "adc stereo4 filter" }, +	{ "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Stereo4 ADC MIX", NULL, "Stereo4 ADC MIXL" }, +	{ "Stereo4 ADC MIX", NULL, "Stereo4 ADC MIXR" }, + +	{ "Mono ADC MIXL", "ADC1 Switch", "Mono ADC1 L Mux" }, +	{ "Mono ADC MIXL", "ADC2 Switch", "Mono ADC2 L Mux" }, +	{ "Mono ADC MIXL", NULL, "adc mono left filter" }, +	{ "adc mono left filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Mono ADC MIXR", "ADC1 Switch", "Mono ADC1 R Mux" }, +	{ "Mono ADC MIXR", "ADC2 Switch", "Mono ADC2 R Mux" }, +	{ "Mono ADC MIXR", NULL, "adc mono right filter" }, +	{ "adc mono right filter", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "Mono ADC MIX", NULL, "Mono ADC MIXL" }, +	{ "Mono ADC MIX", NULL, "Mono ADC MIXR" }, + +	{ "VAD ADC Mux", "STO1 ADC MIX L", "Stereo1 ADC MIXL" }, +	{ "VAD ADC Mux", "MONO ADC MIX L", "Mono ADC MIXL" }, +	{ "VAD ADC Mux", "MONO ADC MIX R", "Mono ADC MIXR" }, +	{ "VAD ADC Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" }, +	{ "VAD ADC Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" }, + +	{ "IF1 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, +	{ "IF1 ADC1 Mux", "OB01", "OB01 Bypass Mux" }, +	{ "IF1 ADC1 Mux", "VAD ADC", "VAD ADC Mux" }, + +	{ "IF1 ADC2 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, +	{ "IF1 ADC2 Mux", "OB23", "OB23 Bypass Mux" }, + +	{ "IF1 ADC3 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" }, +	{ "IF1 ADC3 Mux", "MONO ADC MIX", "Mono ADC MIX" }, +	{ "IF1 ADC3 Mux", "OB45", "OB45" }, + +	{ "IF1 ADC4 Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" }, +	{ "IF1 ADC4 Mux", "OB67", "OB67" }, +	{ "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, + +	{ "AIF1TX", NULL, "I2S1" }, +	{ "AIF1TX", NULL, "IF1 ADC1 Mux" }, +	{ "AIF1TX", NULL, "IF1 ADC2 Mux" }, +	{ "AIF1TX", NULL, "IF1 ADC3 Mux" }, +	{ "AIF1TX", NULL, "IF1 ADC4 Mux" }, + +	{ "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, +	{ "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" }, +	{ "IF2 ADC1 Mux", "VAD ADC", "VAD ADC Mux" }, + +	{ "IF2 ADC2 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, +	{ "IF2 ADC2 Mux", "OB23", "OB23 Bypass Mux" }, + +	{ "IF2 ADC3 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" }, +	{ "IF2 ADC3 Mux", "MONO ADC MIX", "Mono ADC MIX" }, +	{ "IF2 ADC3 Mux", "OB45", "OB45" }, + +	{ "IF2 ADC4 Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" }, +	{ "IF2 ADC4 Mux", "OB67", "OB67" }, +	{ "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, + +	{ "AIF2TX", NULL, "I2S2" }, +	{ "AIF2TX", NULL, "IF2 ADC1 Mux" }, +	{ "AIF2TX", NULL, "IF2 ADC2 Mux" }, +	{ "AIF2TX", NULL, "IF2 ADC3 Mux" }, +	{ "AIF2TX", NULL, "IF2 ADC4 Mux" }, + +	{ "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, +	{ "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, +	{ "IF3 ADC Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" }, +	{ "IF3 ADC Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" }, +	{ "IF3 ADC Mux", "MONO ADC MIX", "Mono ADC MIX" }, +	{ "IF3 ADC Mux", "OB01", "OB01 Bypass Mux" }, +	{ "IF3 ADC Mux", "OB23", "OB23 Bypass Mux" }, +	{ "IF3 ADC Mux", "VAD ADC", "VAD ADC Mux" }, + +	{ "AIF3TX", NULL, "I2S3" }, +	{ "AIF3TX", NULL, "IF3 ADC Mux" }, + +	{ "IF4 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, +	{ "IF4 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, +	{ "IF4 ADC Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" }, +	{ "IF4 ADC Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" }, +	{ "IF4 ADC Mux", "MONO ADC MIX", "Mono ADC MIX" }, +	{ "IF4 ADC Mux", "OB01", "OB01 Bypass Mux" }, +	{ "IF4 ADC Mux", "OB23", "OB23 Bypass Mux" }, +	{ "IF4 ADC Mux", "VAD ADC", "VAD ADC Mux" }, + +	{ "AIF4TX", NULL, "I2S4" }, +	{ "AIF4TX", NULL, "IF4 ADC Mux" }, + +	{ "SLB ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, +	{ "SLB ADC1 Mux", "OB01", "OB01 Bypass Mux" }, +	{ "SLB ADC1 Mux", "VAD ADC", "VAD ADC Mux" }, + +	{ "SLB ADC2 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, +	{ "SLB ADC2 Mux", "OB23", "OB23 Bypass Mux" }, + +	{ "SLB ADC3 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" }, +	{ "SLB ADC3 Mux", "MONO ADC MIX", "Mono ADC MIX" }, +	{ "SLB ADC3 Mux", "OB45", "OB45" }, + +	{ "SLB ADC4 Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" }, +	{ "SLB ADC4 Mux", "OB67", "OB67" }, +	{ "SLB ADC4 Mux", "OB01", "OB01 Bypass Mux" }, + +	{ "SLBTX", NULL, "SLB" }, +	{ "SLBTX", NULL, "SLB ADC1 Mux" }, +	{ "SLBTX", NULL, "SLB ADC2 Mux" }, +	{ "SLBTX", NULL, "SLB ADC3 Mux" }, +	{ "SLBTX", NULL, "SLB ADC4 Mux" }, + +	{ "IB01 Mux", "IF1 DAC 01", "IF1 DAC01" }, +	{ "IB01 Mux", "IF2 DAC 01", "IF2 DAC01" }, +	{ "IB01 Mux", "SLB DAC 01", "SLB DAC01" }, +	{ "IB01 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, +	{ "IB01 Mux", "VAD ADC/DAC1 FS", "DAC1 FS" }, + +	{ "IB01 Bypass Mux", "Bypass", "IB01 Mux" }, +	{ "IB01 Bypass Mux", "Pass SRC", "IB01 Mux" }, + +	{ "IB23 Mux", "IF1 DAC 23", "IF1 DAC23" }, +	{ "IB23 Mux", "IF2 DAC 23", "IF2 DAC23" }, +	{ "IB23 Mux", "SLB DAC 23", "SLB DAC23" }, +	{ "IB23 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, +	{ "IB23 Mux", "DAC1 FS", "DAC1 FS" }, +	{ "IB23 Mux", "IF4 DAC", "IF4 DAC" }, + +	{ "IB23 Bypass Mux", "Bypass", "IB23 Mux" }, +	{ "IB23 Bypass Mux", "Pass SRC", "IB23 Mux" }, + +	{ "IB45 Mux", "IF1 DAC 45", "IF1 DAC45" }, +	{ "IB45 Mux", "IF2 DAC 45", "IF2 DAC45" }, +	{ "IB45 Mux", "SLB DAC 45", "SLB DAC45" }, +	{ "IB45 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" }, +	{ "IB45 Mux", "IF3 DAC", "IF3 DAC" }, + +	{ "IB45 Bypass Mux", "Bypass", "IB45 Mux" }, +	{ "IB45 Bypass Mux", "Pass SRC", "IB45 Mux" }, + +	{ "IB6 Mux", "IF1 DAC 6", "IF1 DAC6" }, +	{ "IB6 Mux", "IF2 DAC 6", "IF2 DAC6" }, +	{ "IB6 Mux", "SLB DAC 6", "SLB DAC6" }, +	{ "IB6 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" }, +	{ "IB6 Mux", "IF4 DAC L", "IF4 DAC L" }, +	{ "IB6 Mux", "STO1 ADC MIX L", "Stereo1 ADC MIXL" }, +	{ "IB6 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" }, +	{ "IB6 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" }, + +	{ "IB7 Mux", "IF1 DAC 7", "IF1 DAC7" }, +	{ "IB7 Mux", "IF2 DAC 7", "IF2 DAC7" }, +	{ "IB7 Mux", "SLB DAC 7", "SLB DAC7" }, +	{ "IB7 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" }, +	{ "IB7 Mux", "IF4 DAC R", "IF4 DAC R" }, +	{ "IB7 Mux", "STO1 ADC MIX R", "Stereo1 ADC MIXR" }, +	{ "IB7 Mux", "STO2 ADC MIX R", "Stereo2 ADC MIXR" }, +	{ "IB7 Mux", "STO3 ADC MIX R", "Stereo3 ADC MIXR" }, + +	{ "IB8 Mux", "STO1 ADC MIX L", "Stereo1 ADC MIXL" }, +	{ "IB8 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" }, +	{ "IB8 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" }, +	{ "IB8 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" }, +	{ "IB8 Mux", "MONO ADC MIX L", "Mono ADC MIXL" }, +	{ "IB8 Mux", "DACL1 FS", "DAC1 MIXL" }, + +	{ "IB9 Mux", "STO1 ADC MIX R", "Stereo1 ADC MIXR" }, +	{ "IB9 Mux", "STO2 ADC MIX R", "Stereo2 ADC MIXR" }, +	{ "IB9 Mux", "STO3 ADC MIX R", "Stereo3 ADC MIXR" }, +	{ "IB9 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" }, +	{ "IB9 Mux", "MONO ADC MIX R", "Mono ADC MIXR" }, +	{ "IB9 Mux", "DACR1 FS", "DAC1 MIXR" }, +	{ "IB9 Mux", "DAC1 FS", "DAC1 FS" }, + +	{ "OB01 MIX", "IB01 Switch", "IB01 Bypass Mux" }, +	{ "OB01 MIX", "IB23 Switch", "IB23 Bypass Mux" }, +	{ "OB01 MIX", "IB45 Switch", "IB45 Bypass Mux" }, +	{ "OB01 MIX", "IB6 Switch", "IB6 Mux" }, +	{ "OB01 MIX", "IB7 Switch", "IB7 Mux" }, +	{ "OB01 MIX", "IB8 Switch", "IB8 Mux" }, +	{ "OB01 MIX", "IB9 Switch", "IB9 Mux" }, + +	{ "OB23 MIX", "IB01 Switch", "IB01 Bypass Mux" }, +	{ "OB23 MIX", "IB23 Switch", "IB23 Bypass Mux" }, +	{ "OB23 MIX", "IB45 Switch", "IB45 Bypass Mux" }, +	{ "OB23 MIX", "IB6 Switch", "IB6 Mux" }, +	{ "OB23 MIX", "IB7 Switch", "IB7 Mux" }, +	{ "OB23 MIX", "IB8 Switch", "IB8 Mux" }, +	{ "OB23 MIX", "IB9 Switch", "IB9 Mux" }, + +	{ "OB4 MIX", "IB01 Switch", "IB01 Bypass Mux" }, +	{ "OB4 MIX", "IB23 Switch", "IB23 Bypass Mux" }, +	{ "OB4 MIX", "IB45 Switch", "IB45 Bypass Mux" }, +	{ "OB4 MIX", "IB6 Switch", "IB6 Mux" }, +	{ "OB4 MIX", "IB7 Switch", "IB7 Mux" }, +	{ "OB4 MIX", "IB8 Switch", "IB8 Mux" }, +	{ "OB4 MIX", "IB9 Switch", "IB9 Mux" }, + +	{ "OB5 MIX", "IB01 Switch", "IB01 Bypass Mux" }, +	{ "OB5 MIX", "IB23 Switch", "IB23 Bypass Mux" }, +	{ "OB5 MIX", "IB45 Switch", "IB45 Bypass Mux" }, +	{ "OB5 MIX", "IB6 Switch", "IB6 Mux" }, +	{ "OB5 MIX", "IB7 Switch", "IB7 Mux" }, +	{ "OB5 MIX", "IB8 Switch", "IB8 Mux" }, +	{ "OB5 MIX", "IB9 Switch", "IB9 Mux" }, + +	{ "OB6 MIX", "IB01 Switch", "IB01 Bypass Mux" }, +	{ "OB6 MIX", "IB23 Switch", "IB23 Bypass Mux" }, +	{ "OB6 MIX", "IB45 Switch", "IB45 Bypass Mux" }, +	{ "OB6 MIX", "IB6 Switch", "IB6 Mux" }, +	{ "OB6 MIX", "IB7 Switch", "IB7 Mux" }, +	{ "OB6 MIX", "IB8 Switch", "IB8 Mux" }, +	{ "OB6 MIX", "IB9 Switch", "IB9 Mux" }, + +	{ "OB7 MIX", "IB01 Switch", "IB01 Bypass Mux" }, +	{ "OB7 MIX", "IB23 Switch", "IB23 Bypass Mux" }, +	{ "OB7 MIX", "IB45 Switch", "IB45 Bypass Mux" }, +	{ "OB7 MIX", "IB6 Switch", "IB6 Mux" }, +	{ "OB7 MIX", "IB7 Switch", "IB7 Mux" }, +	{ "OB7 MIX", "IB8 Switch", "IB8 Mux" }, +	{ "OB7 MIX", "IB9 Switch", "IB9 Mux" }, + +	{ "OB01 Bypass Mux", "Bypass", "OB01 MIX" }, +	{ "OB01 Bypass Mux", "Pass SRC", "OB01 MIX" }, +	{ "OB23 Bypass Mux", "Bypass", "OB23 MIX" }, +	{ "OB23 Bypass Mux", "Pass SRC", "OB23 MIX" }, + +	{ "OutBound2", NULL, "OB23 Bypass Mux" }, +	{ "OutBound3", NULL, "OB23 Bypass Mux" }, +	{ "OutBound4", NULL, "OB4 MIX" }, +	{ "OutBound5", NULL, "OB5 MIX" }, +	{ "OutBound6", NULL, "OB6 MIX" }, +	{ "OutBound7", NULL, "OB7 MIX" }, + +	{ "OB45", NULL, "OutBound4" }, +	{ "OB45", NULL, "OutBound5" }, +	{ "OB67", NULL, "OutBound6" }, +	{ "OB67", NULL, "OutBound7" }, + +	{ "IF1 DAC0", NULL, "AIF1RX" }, +	{ "IF1 DAC1", NULL, "AIF1RX" }, +	{ "IF1 DAC2", NULL, "AIF1RX" }, +	{ "IF1 DAC3", NULL, "AIF1RX" }, +	{ "IF1 DAC4", NULL, "AIF1RX" }, +	{ "IF1 DAC5", NULL, "AIF1RX" }, +	{ "IF1 DAC6", NULL, "AIF1RX" }, +	{ "IF1 DAC7", NULL, "AIF1RX" }, +	{ "IF1 DAC0", NULL, "I2S1" }, +	{ "IF1 DAC1", NULL, "I2S1" }, +	{ "IF1 DAC2", NULL, "I2S1" }, +	{ "IF1 DAC3", NULL, "I2S1" }, +	{ "IF1 DAC4", NULL, "I2S1" }, +	{ "IF1 DAC5", NULL, "I2S1" }, +	{ "IF1 DAC6", NULL, "I2S1" }, +	{ "IF1 DAC7", NULL, "I2S1" }, + +	{ "IF1 DAC01", NULL, "IF1 DAC0" }, +	{ "IF1 DAC01", NULL, "IF1 DAC1" }, +	{ "IF1 DAC23", NULL, "IF1 DAC2" }, +	{ "IF1 DAC23", NULL, "IF1 DAC3" }, +	{ "IF1 DAC45", NULL, "IF1 DAC4" }, +	{ "IF1 DAC45", NULL, "IF1 DAC5" }, +	{ "IF1 DAC67", NULL, "IF1 DAC6" }, +	{ "IF1 DAC67", NULL, "IF1 DAC7" }, + +	{ "IF2 DAC0", NULL, "AIF2RX" }, +	{ "IF2 DAC1", NULL, "AIF2RX" }, +	{ "IF2 DAC2", NULL, "AIF2RX" }, +	{ "IF2 DAC3", NULL, "AIF2RX" }, +	{ "IF2 DAC4", NULL, "AIF2RX" }, +	{ "IF2 DAC5", NULL, "AIF2RX" }, +	{ "IF2 DAC6", NULL, "AIF2RX" }, +	{ "IF2 DAC7", NULL, "AIF2RX" }, +	{ "IF2 DAC0", NULL, "I2S2" }, +	{ "IF2 DAC1", NULL, "I2S2" }, +	{ "IF2 DAC2", NULL, "I2S2" }, +	{ "IF2 DAC3", NULL, "I2S2" }, +	{ "IF2 DAC4", NULL, "I2S2" }, +	{ "IF2 DAC5", NULL, "I2S2" }, +	{ "IF2 DAC6", NULL, "I2S2" }, +	{ "IF2 DAC7", NULL, "I2S2" }, + +	{ "IF2 DAC01", NULL, "IF2 DAC0" }, +	{ "IF2 DAC01", NULL, "IF2 DAC1" }, +	{ "IF2 DAC23", NULL, "IF2 DAC2" }, +	{ "IF2 DAC23", NULL, "IF2 DAC3" }, +	{ "IF2 DAC45", NULL, "IF2 DAC4" }, +	{ "IF2 DAC45", NULL, "IF2 DAC5" }, +	{ "IF2 DAC67", NULL, "IF2 DAC6" }, +	{ "IF2 DAC67", NULL, "IF2 DAC7" }, + +	{ "IF3 DAC", NULL, "AIF3RX" }, +	{ "IF3 DAC", NULL, "I2S3" }, + +	{ "IF4 DAC", NULL, "AIF4RX" }, +	{ "IF4 DAC", NULL, "I2S4" }, + +	{ "IF3 DAC L", NULL, "IF3 DAC" }, +	{ "IF3 DAC R", NULL, "IF3 DAC" }, + +	{ "IF4 DAC L", NULL, "IF4 DAC" }, +	{ "IF4 DAC R", NULL, "IF4 DAC" }, + +	{ "SLB DAC0", NULL, "SLBRX" }, +	{ "SLB DAC1", NULL, "SLBRX" }, +	{ "SLB DAC2", NULL, "SLBRX" }, +	{ "SLB DAC3", NULL, "SLBRX" }, +	{ "SLB DAC4", NULL, "SLBRX" }, +	{ "SLB DAC5", NULL, "SLBRX" }, +	{ "SLB DAC6", NULL, "SLBRX" }, +	{ "SLB DAC7", NULL, "SLBRX" }, +	{ "SLB DAC0", NULL, "SLB" }, +	{ "SLB DAC1", NULL, "SLB" }, +	{ "SLB DAC2", NULL, "SLB" }, +	{ "SLB DAC3", NULL, "SLB" }, +	{ "SLB DAC4", NULL, "SLB" }, +	{ "SLB DAC5", NULL, "SLB" }, +	{ "SLB DAC6", NULL, "SLB" }, +	{ "SLB DAC7", NULL, "SLB" }, + +	{ "SLB DAC01", NULL, "SLB DAC0" }, +	{ "SLB DAC01", NULL, "SLB DAC1" }, +	{ "SLB DAC23", NULL, "SLB DAC2" }, +	{ "SLB DAC23", NULL, "SLB DAC3" }, +	{ "SLB DAC45", NULL, "SLB DAC4" }, +	{ "SLB DAC45", NULL, "SLB DAC5" }, +	{ "SLB DAC67", NULL, "SLB DAC6" }, +	{ "SLB DAC67", NULL, "SLB DAC7" }, + +	{ "ADDA1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, +	{ "ADDA1 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, +	{ "ADDA1 Mux", "OB 67", "OB67" }, + +	{ "DAC1 Mux", "IF1 DAC 01", "IF1 DAC01" }, +	{ "DAC1 Mux", "IF2 DAC 01", "IF2 DAC01" }, +	{ "DAC1 Mux", "IF3 DAC LR", "IF3 DAC" }, +	{ "DAC1 Mux", "IF4 DAC LR", "IF4 DAC" }, +	{ "DAC1 Mux", "SLB DAC 01", "SLB DAC01" }, +	{ "DAC1 Mux", "OB 01", "OB01 Bypass Mux" }, + +	{ "DAC1 MIXL", "Stereo ADC Switch", "ADDA1 Mux" }, +	{ "DAC1 MIXL", "DAC1 Switch", "DAC1 Mux" }, +	{ "DAC1 MIXL", NULL, "dac stereo1 filter" }, +	{ "DAC1 MIXR", "Stereo ADC Switch", "ADDA1 Mux" }, +	{ "DAC1 MIXR", "DAC1 Switch", "DAC1 Mux" }, +	{ "DAC1 MIXR", NULL, "dac stereo1 filter" }, + +	{ "DAC1 FS", NULL, "DAC1 MIXL" }, +	{ "DAC1 FS", NULL, "DAC1 MIXR" }, + +	{ "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2" }, +	{ "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2" }, +	{ "DAC2 L Mux", "IF3 DAC L", "IF3 DAC L" }, +	{ "DAC2 L Mux", "IF4 DAC L", "IF4 DAC L" }, +	{ "DAC2 L Mux", "SLB DAC 2", "SLB DAC2" }, +	{ "DAC2 L Mux", "OB 2", "OutBound2" }, + +	{ "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3" }, +	{ "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3" }, +	{ "DAC2 R Mux", "IF3 DAC R", "IF3 DAC R" }, +	{ "DAC2 R Mux", "IF4 DAC R", "IF4 DAC R" }, +	{ "DAC2 R Mux", "SLB DAC 3", "SLB DAC3" }, +	{ "DAC2 R Mux", "OB 3", "OutBound3" }, +	{ "DAC2 R Mux", "Haptic Generator", "Haptic Generator" }, +	{ "DAC2 R Mux", "VAD ADC", "VAD ADC Mux" }, + +	{ "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4" }, +	{ "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4" }, +	{ "DAC3 L Mux", "IF3 DAC L", "IF3 DAC L" }, +	{ "DAC3 L Mux", "IF4 DAC L", "IF4 DAC L" }, +	{ "DAC3 L Mux", "SLB DAC 4", "SLB DAC4" }, +	{ "DAC3 L Mux", "OB 4", "OutBound4" }, + +	{ "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC4" }, +	{ "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC4" }, +	{ "DAC3 R Mux", "IF3 DAC R", "IF3 DAC R" }, +	{ "DAC3 R Mux", "IF4 DAC R", "IF4 DAC R" }, +	{ "DAC3 R Mux", "SLB DAC 5", "SLB DAC5" }, +	{ "DAC3 R Mux", "OB 5", "OutBound5" }, + +	{ "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6" }, +	{ "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6" }, +	{ "DAC4 L Mux", "IF3 DAC L", "IF3 DAC L" }, +	{ "DAC4 L Mux", "IF4 DAC L", "IF4 DAC L" }, +	{ "DAC4 L Mux", "SLB DAC 6", "SLB DAC6" }, +	{ "DAC4 L Mux", "OB 6", "OutBound6" }, + +	{ "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7" }, +	{ "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7" }, +	{ "DAC4 R Mux", "IF3 DAC R", "IF3 DAC R" }, +	{ "DAC4 R Mux", "IF4 DAC R", "IF4 DAC R" }, +	{ "DAC4 R Mux", "SLB DAC 7", "SLB DAC7" }, +	{ "DAC4 R Mux", "OB 7", "OutBound7" }, + +	{ "Sidetone Mux", "DMIC1 L", "DMIC L1" }, +	{ "Sidetone Mux", "DMIC2 L", "DMIC L2" }, +	{ "Sidetone Mux", "DMIC3 L", "DMIC L3" }, +	{ "Sidetone Mux", "DMIC4 L", "DMIC L4" }, +	{ "Sidetone Mux", "ADC1", "ADC 1" }, +	{ "Sidetone Mux", "ADC2", "ADC 2" }, + +	{ "Stereo DAC MIXL", "ST L Switch", "Sidetone Mux" }, +	{ "Stereo DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, +	{ "Stereo DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" }, +	{ "Stereo DAC MIXL", "DAC1 R Switch", "DAC1 MIXR" }, +	{ "Stereo DAC MIXL", NULL, "dac stereo1 filter" }, +	{ "Stereo DAC MIXR", "ST R Switch", "Sidetone Mux" }, +	{ "Stereo DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" }, +	{ "Stereo DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" }, +	{ "Stereo DAC MIXR", "DAC1 L Switch", "DAC1 MIXL" }, +	{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" }, + +	{ "Mono DAC MIXL", "ST L Switch", "Sidetone Mux" }, +	{ "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, +	{ "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" }, +	{ "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" }, +	{ "Mono DAC MIXL", NULL, "dac mono left filter" }, +	{ "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" }, +	{ "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" }, +	{ "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" }, +	{ "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" }, +	{ "Mono DAC MIXR", NULL, "dac mono right filter" }, + +	{ "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, +	{ "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, +	{ "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" }, +	{ "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" }, +	{ "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, +	{ "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, +	{ "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" }, +	{ "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" }, + +	{ "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, +	{ "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, +	{ "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" }, +	{ "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" }, +	{ "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, +	{ "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, +	{ "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" }, +	{ "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" }, + +	{ "Stereo DAC MIX", NULL, "Stereo DAC MIXL" }, +	{ "Stereo DAC MIX", NULL, "Stereo DAC MIXR" }, +	{ "Mono DAC MIX", NULL, "Mono DAC MIXL" }, +	{ "Mono DAC MIX", NULL, "Mono DAC MIXR" }, +	{ "DD1 MIX", NULL, "DD1 MIXL" }, +	{ "DD1 MIX", NULL, "DD1 MIXR" }, +	{ "DD2 MIX", NULL, "DD2 MIXL" }, +	{ "DD2 MIX", NULL, "DD2 MIXR" }, + +	{ "DAC12 SRC Mux", "STO1 DAC MIX", "Stereo DAC MIX" }, +	{ "DAC12 SRC Mux", "MONO DAC MIX", "Mono DAC MIX" }, +	{ "DAC12 SRC Mux", "DD MIX1", "DD1 MIX" }, +	{ "DAC12 SRC Mux", "DD MIX2", "DD2 MIX" }, + +	{ "DAC3 SRC Mux", "MONO DAC MIXL", "Mono DAC MIXL" }, +	{ "DAC3 SRC Mux", "MONO DAC MIXR", "Mono DAC MIXR" }, +	{ "DAC3 SRC Mux", "DD MIX1L", "DD1 MIXL" }, +	{ "DAC3 SRC Mux", "DD MIX2L", "DD2 MIXL" }, + +	{ "DAC 1", NULL, "DAC12 SRC Mux" }, +	{ "DAC 1", NULL, "PLL1", is_sys_clk_from_pll }, +	{ "DAC 2", NULL, "DAC12 SRC Mux" }, +	{ "DAC 2", NULL, "PLL1", is_sys_clk_from_pll }, +	{ "DAC 3", NULL, "DAC3 SRC Mux" }, +	{ "DAC 3", NULL, "PLL1", is_sys_clk_from_pll }, + +	{ "PDM1 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" }, +	{ "PDM1 L Mux", "MONO DAC MIX", "Mono DAC MIXL" }, +	{ "PDM1 L Mux", "DD MIX1", "DD1 MIXL" }, +	{ "PDM1 L Mux", "DD MIX2", "DD2 MIXL" }, +	{ "PDM1 L Mux", NULL, "PDM1 Power" }, +	{ "PDM1 R Mux", "STO1 DAC MIX", "Stereo DAC MIXR" }, +	{ "PDM1 R Mux", "MONO DAC MIX", "Mono DAC MIXR" }, +	{ "PDM1 R Mux", "DD MIX1", "DD1 MIXR" }, +	{ "PDM1 R Mux", "DD MIX2", "DD2 MIXR" }, +	{ "PDM1 R Mux", NULL, "PDM1 Power" }, +	{ "PDM2 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" }, +	{ "PDM2 L Mux", "MONO DAC MIX", "Mono DAC MIXL" }, +	{ "PDM2 L Mux", "DD MIX1", "DD1 MIXL" }, +	{ "PDM2 L Mux", "DD MIX2", "DD2 MIXL" }, +	{ "PDM2 L Mux", NULL, "PDM2 Power" }, +	{ "PDM2 R Mux", "STO1 DAC MIX", "Stereo DAC MIXR" }, +	{ "PDM2 R Mux", "MONO DAC MIX", "Mono DAC MIXR" }, +	{ "PDM2 R Mux", "DD MIX1", "DD1 MIXR" }, +	{ "PDM2 R Mux", "DD MIX1", "DD2 MIXR" }, +	{ "PDM2 R Mux", NULL, "PDM2 Power" }, + +	{ "LOUT1 amp", NULL, "DAC 1" }, +	{ "LOUT2 amp", NULL, "DAC 2" }, +	{ "LOUT3 amp", NULL, "DAC 3" }, + +	{ "LOUT1", NULL, "LOUT1 amp" }, +	{ "LOUT2", NULL, "LOUT2 amp" }, +	{ "LOUT3", NULL, "LOUT3 amp" }, + +	{ "PDM1L", NULL, "PDM1 L Mux" }, +	{ "PDM1R", NULL, "PDM1 R Mux" }, +	{ "PDM2L", NULL, "PDM2 L Mux" }, +	{ "PDM2R", NULL, "PDM2 R Mux" }, +}; + +static int get_clk_info(int sclk, int rate) +{ +	int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + +	if (sclk <= 0 || rate <= 0) +		return -EINVAL; + +	rate = rate << 8; +	for (i = 0; i < ARRAY_SIZE(pd); i++) +		if (sclk == rate * pd[i]) +			return i; + +	return -EINVAL; +} + +static int rt5677_hw_params(struct snd_pcm_substream *substream, +	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); +	unsigned int val_len = 0, val_clk, mask_clk; +	int pre_div, bclk_ms, frame_size; + +	rt5677->lrck[dai->id] = params_rate(params); +	pre_div = get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]); +	if (pre_div < 0) { +		dev_err(codec->dev, "Unsupported clock setting\n"); +		return -EINVAL; +	} +	frame_size = snd_soc_params_to_frame_size(params); +	if (frame_size < 0) { +		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); +		return -EINVAL; +	} +	bclk_ms = frame_size > 32; +	rt5677->bclk[dai->id] = rt5677->lrck[dai->id] * (32 << bclk_ms); + +	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", +		rt5677->bclk[dai->id], rt5677->lrck[dai->id]); +	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", +				bclk_ms, pre_div, dai->id); + +	switch (params_width(params)) { +	case 16: +		break; +	case 20: +		val_len |= RT5677_I2S_DL_20; +		break; +	case 24: +		val_len |= RT5677_I2S_DL_24; +		break; +	case 8: +		val_len |= RT5677_I2S_DL_8; +		break; +	default: +		return -EINVAL; +	} + +	switch (dai->id) { +	case RT5677_AIF1: +		mask_clk = RT5677_I2S_PD1_MASK; +		val_clk = pre_div << RT5677_I2S_PD1_SFT; +		regmap_update_bits(rt5677->regmap, RT5677_I2S1_SDP, +			RT5677_I2S_DL_MASK, val_len); +		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1, +			mask_clk, val_clk); +		break; +	case RT5677_AIF2: +		mask_clk = RT5677_I2S_PD2_MASK; +		val_clk = pre_div << RT5677_I2S_PD2_SFT; +		regmap_update_bits(rt5677->regmap, RT5677_I2S2_SDP, +			RT5677_I2S_DL_MASK, val_len); +		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1, +			mask_clk, val_clk); +		break; +	case RT5677_AIF3: +		mask_clk = RT5677_I2S_BCLK_MS3_MASK | RT5677_I2S_PD3_MASK; +		val_clk = bclk_ms << RT5677_I2S_BCLK_MS3_SFT | +			pre_div << RT5677_I2S_PD3_SFT; +		regmap_update_bits(rt5677->regmap, RT5677_I2S3_SDP, +			RT5677_I2S_DL_MASK, val_len); +		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1, +			mask_clk, val_clk); +		break; +	case RT5677_AIF4: +		mask_clk = RT5677_I2S_BCLK_MS4_MASK | RT5677_I2S_PD4_MASK; +		val_clk = bclk_ms << RT5677_I2S_BCLK_MS4_SFT | +			pre_div << RT5677_I2S_PD4_SFT; +		regmap_update_bits(rt5677->regmap, RT5677_I2S4_SDP, +			RT5677_I2S_DL_MASK, val_len); +		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1, +			mask_clk, val_clk); +		break; +	default: +		break; +	} + +	return 0; +} + +static int rt5677_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		rt5677->master[dai->id] = 1; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		reg_val |= RT5677_I2S_MS_S; +		rt5677->master[dai->id] = 0; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		break; +	case SND_SOC_DAIFMT_IB_NF: +		reg_val |= RT5677_I2S_BP_INV; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		reg_val |= RT5677_I2S_DF_LEFT; +		break; +	case SND_SOC_DAIFMT_DSP_A: +		reg_val |= RT5677_I2S_DF_PCM_A; +		break; +	case SND_SOC_DAIFMT_DSP_B: +		reg_val |= RT5677_I2S_DF_PCM_B; +		break; +	default: +		return -EINVAL; +	} + +	switch (dai->id) { +	case RT5677_AIF1: +		regmap_update_bits(rt5677->regmap, RT5677_I2S1_SDP, +			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK | +			RT5677_I2S_DF_MASK, reg_val); +		break; +	case RT5677_AIF2: +		regmap_update_bits(rt5677->regmap, RT5677_I2S2_SDP, +			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK | +			RT5677_I2S_DF_MASK, reg_val); +		break; +	case RT5677_AIF3: +		regmap_update_bits(rt5677->regmap, RT5677_I2S3_SDP, +			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK | +			RT5677_I2S_DF_MASK, reg_val); +		break; +	case RT5677_AIF4: +		regmap_update_bits(rt5677->regmap, RT5677_I2S4_SDP, +			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK | +			RT5677_I2S_DF_MASK, reg_val); +		break; +	default: +		break; +	} + + +	return 0; +} + +static int rt5677_set_dai_sysclk(struct snd_soc_dai *dai, +		int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	if (freq == rt5677->sysclk && clk_id == rt5677->sysclk_src) +		return 0; + +	switch (clk_id) { +	case RT5677_SCLK_S_MCLK: +		reg_val |= RT5677_SCLK_SRC_MCLK; +		break; +	case RT5677_SCLK_S_PLL1: +		reg_val |= RT5677_SCLK_SRC_PLL1; +		break; +	case RT5677_SCLK_S_RCCLK: +		reg_val |= RT5677_SCLK_SRC_RCCLK; +		break; +	default: +		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); +		return -EINVAL; +	} +	regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, +		RT5677_SCLK_SRC_MASK, reg_val); +	rt5677->sysclk = freq; +	rt5677->sysclk_src = clk_id; + +	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + +	return 0; +} + +/** + * rt5677_pll_calc - Calcualte PLL M/N/K code. + * @freq_in: external clock provided to codec. + * @freq_out: target clock which codec works on. + * @pll_code: Pointer to structure with M, N, K, bypass K and bypass M flag. + * + * Calcualte M/N/K code and bypass K/M flag to configure PLL for codec. + * + * Returns 0 for success or negative error code. + */ +static int rt5677_pll_calc(const unsigned int freq_in, +	const unsigned int freq_out, struct rt5677_pll_code *pll_code) +{ +	int max_n = RT5677_PLL_N_MAX, max_m = RT5677_PLL_M_MAX; +	int k, red, n_t, pll_out, in_t; +	int n = 0, m = 0, m_t = 0; +	int out_t, red_t = abs(freq_out - freq_in); +	bool m_bp = false, k_bp = false; + +	if (RT5677_PLL_INP_MAX < freq_in || RT5677_PLL_INP_MIN > freq_in) +		return -EINVAL; + +	k = 100000000 / freq_out - 2; +	if (k > RT5677_PLL_K_MAX) +		k = RT5677_PLL_K_MAX; +	for (n_t = 0; n_t <= max_n; n_t++) { +		in_t = freq_in / (k + 2); +		pll_out = freq_out / (n_t + 2); +		if (in_t < 0) +			continue; +		if (in_t == pll_out) { +			m_bp = true; +			n = n_t; +			goto code_find; +		} +		red = abs(in_t - pll_out); +		if (red < red_t) { +			m_bp = true; +			n = n_t; +			m = m_t; +			if (red == 0) +				goto code_find; +			red_t = red; +		} +		for (m_t = 0; m_t <= max_m; m_t++) { +			out_t = in_t / (m_t + 2); +			red = abs(out_t - pll_out); +			if (red < red_t) { +				m_bp = false; +				n = n_t; +				m = m_t; +				if (red == 0) +					goto code_find; +				red_t = red; +			} +		} +	} +	pr_debug("Only get approximation about PLL\n"); + +code_find: + +	pll_code->m_bp = m_bp; +	pll_code->k_bp = k_bp; +	pll_code->m_code = m; +	pll_code->n_code = n; +	pll_code->k_code = k; +	return 0; +} + +static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, +			unsigned int freq_in, unsigned int freq_out) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); +	struct rt5677_pll_code pll_code; +	int ret; + +	if (source == rt5677->pll_src && freq_in == rt5677->pll_in && +	    freq_out == rt5677->pll_out) +		return 0; + +	if (!freq_in || !freq_out) { +		dev_dbg(codec->dev, "PLL disabled\n"); + +		rt5677->pll_in = 0; +		rt5677->pll_out = 0; +		regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, +			RT5677_SCLK_SRC_MASK, RT5677_SCLK_SRC_MCLK); +		return 0; +	} + +	switch (source) { +	case RT5677_PLL1_S_MCLK: +		regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, +			RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_MCLK); +		break; +	case RT5677_PLL1_S_BCLK1: +	case RT5677_PLL1_S_BCLK2: +	case RT5677_PLL1_S_BCLK3: +	case RT5677_PLL1_S_BCLK4: +		switch (dai->id) { +		case RT5677_AIF1: +			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, +				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK1); +			break; +		case RT5677_AIF2: +			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, +				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK2); +			break; +		case RT5677_AIF3: +			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, +				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK3); +			break; +		case RT5677_AIF4: +			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, +				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK4); +			break; +		default: +			break; +		} +		break; +	default: +		dev_err(codec->dev, "Unknown PLL source %d\n", source); +		return -EINVAL; +	} + +	ret = rt5677_pll_calc(freq_in, freq_out, &pll_code); +	if (ret < 0) { +		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); +		return ret; +	} + +	dev_dbg(codec->dev, "m_bypass=%d k_bypass=%d m=%d n=%d k=%d\n", +		pll_code.m_bp, pll_code.k_bp, +		(pll_code.m_bp ? 0 : pll_code.m_code), pll_code.n_code, +		(pll_code.k_bp ? 0 : pll_code.k_code)); + +	regmap_write(rt5677->regmap, RT5677_PLL1_CTRL1, +		pll_code.n_code << RT5677_PLL_N_SFT | +		pll_code.k_bp << RT5677_PLL_K_BP_SFT | +		(pll_code.k_bp ? 0 : pll_code.k_code)); +	regmap_write(rt5677->regmap, RT5677_PLL1_CTRL2, +		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5677_PLL_M_SFT | +		pll_code.m_bp << RT5677_PLL_M_BP_SFT); + +	rt5677->pll_in = freq_in; +	rt5677->pll_out = freq_out; +	rt5677->pll_src = source; + +	return 0; +} + +static int rt5677_set_bias_level(struct snd_soc_codec *codec, +			enum snd_soc_bias_level level) +{ +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	switch (level) { +	case SND_SOC_BIAS_ON: +		break; + +	case SND_SOC_BIAS_PREPARE: +		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { +			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, +				RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, +				0x0055); +			regmap_update_bits(rt5677->regmap, +				RT5677_PR_BASE + RT5677_BIAS_CUR4, +				0x0f00, 0x0f00); +			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, +				RT5677_PWR_VREF1 | RT5677_PWR_MB | +				RT5677_PWR_BG | RT5677_PWR_VREF2, +				RT5677_PWR_VREF1 | RT5677_PWR_MB | +				RT5677_PWR_BG | RT5677_PWR_VREF2); +			mdelay(20); +			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, +				RT5677_PWR_FV1 | RT5677_PWR_FV2, +				RT5677_PWR_FV1 | RT5677_PWR_FV2); +			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, +				RT5677_PWR_CORE, RT5677_PWR_CORE); +			regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, +				0x1, 0x1); +		} +		break; + +	case SND_SOC_BIAS_STANDBY: +		break; + +	case SND_SOC_BIAS_OFF: +		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0); +		regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000); +		regmap_write(rt5677->regmap, RT5677_PWR_DIG2, 0x0000); +		regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, 0x0000); +		regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); +		regmap_update_bits(rt5677->regmap, +			RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); +		break; + +	default: +		break; +	} +	codec->dapm.bias_level = level; + +	return 0; +} + +static int rt5677_probe(struct snd_soc_codec *codec) +{ +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	rt5677->codec = codec; + +	rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF); + +	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); +	regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); + +	return 0; +} + +static int rt5677_remove(struct snd_soc_codec *codec) +{ +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); + +	return 0; +} + +#ifdef CONFIG_PM +static int rt5677_suspend(struct snd_soc_codec *codec) +{ +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5677->regmap, true); +	regcache_mark_dirty(rt5677->regmap); + +	return 0; +} + +static int rt5677_resume(struct snd_soc_codec *codec) +{ +	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5677->regmap, false); +	regcache_sync(rt5677->regmap); + +	return 0; +} +#else +#define rt5677_suspend NULL +#define rt5677_resume NULL +#endif + +#define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt5677_aif_dai_ops = { +	.hw_params = rt5677_hw_params, +	.set_fmt = rt5677_set_dai_fmt, +	.set_sysclk = rt5677_set_dai_sysclk, +	.set_pll = rt5677_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5677_dai[] = { +	{ +		.name = "rt5677-aif1", +		.id = RT5677_AIF1, +		.playback = { +			.stream_name = "AIF1 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF1 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.ops = &rt5677_aif_dai_ops, +	}, +	{ +		.name = "rt5677-aif2", +		.id = RT5677_AIF2, +		.playback = { +			.stream_name = "AIF2 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF2 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.ops = &rt5677_aif_dai_ops, +	}, +	{ +		.name = "rt5677-aif3", +		.id = RT5677_AIF3, +		.playback = { +			.stream_name = "AIF3 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF3 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.ops = &rt5677_aif_dai_ops, +	}, +	{ +		.name = "rt5677-aif4", +		.id = RT5677_AIF4, +		.playback = { +			.stream_name = "AIF4 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF4 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.ops = &rt5677_aif_dai_ops, +	}, +	{ +		.name = "rt5677-slimbus", +		.id = RT5677_AIF5, +		.playback = { +			.stream_name = "SLIMBus Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.capture = { +			.stream_name = "SLIMBus Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5677_STEREO_RATES, +			.formats = RT5677_FORMATS, +		}, +		.ops = &rt5677_aif_dai_ops, +	}, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5677 = { +	.probe = rt5677_probe, +	.remove = rt5677_remove, +	.suspend = rt5677_suspend, +	.resume = rt5677_resume, +	.set_bias_level = rt5677_set_bias_level, +	.idle_bias_off = true, +	.controls = rt5677_snd_controls, +	.num_controls = ARRAY_SIZE(rt5677_snd_controls), +	.dapm_widgets = rt5677_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(rt5677_dapm_widgets), +	.dapm_routes = rt5677_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), +}; + +static const struct regmap_config rt5677_regmap = { +	.reg_bits = 8, +	.val_bits = 16, + +	.max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) * +						RT5677_PR_SPACING), + +	.volatile_reg = rt5677_volatile_register, +	.readable_reg = rt5677_readable_register, + +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults = rt5677_reg, +	.num_reg_defaults = ARRAY_SIZE(rt5677_reg), +	.ranges = rt5677_ranges, +	.num_ranges = ARRAY_SIZE(rt5677_ranges), +}; + +static const struct i2c_device_id rt5677_i2c_id[] = { +	{ "rt5677", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); + +static int rt5677_i2c_probe(struct i2c_client *i2c, +		    const struct i2c_device_id *id) +{ +	struct rt5677_platform_data *pdata = dev_get_platdata(&i2c->dev); +	struct rt5677_priv *rt5677; +	int ret; +	unsigned int val; + +	rt5677 = devm_kzalloc(&i2c->dev, sizeof(struct rt5677_priv), +				GFP_KERNEL); +	if (rt5677 == NULL) +		return -ENOMEM; + +	i2c_set_clientdata(i2c, rt5677); + +	if (pdata) +		rt5677->pdata = *pdata; + +	rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap); +	if (IS_ERR(rt5677->regmap)) { +		ret = PTR_ERR(rt5677->regmap); +		dev_err(&i2c->dev, "Failed to allocate register map: %d\n", +			ret); +		return ret; +	} + +	regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val); +	if (val != RT5677_DEVICE_ID) { +		dev_err(&i2c->dev, +			"Device with ID register %x is not rt5677\n", val); +		return -ENODEV; +	} + +	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); + +	ret = regmap_register_patch(rt5677->regmap, init_list, +				    ARRAY_SIZE(init_list)); +	if (ret != 0) +		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + +	if (rt5677->pdata.in1_diff) +		regmap_update_bits(rt5677->regmap, RT5677_IN1, +					RT5677_IN_DF1, RT5677_IN_DF1); + +	if (rt5677->pdata.in2_diff) +		regmap_update_bits(rt5677->regmap, RT5677_IN1, +					RT5677_IN_DF2, RT5677_IN_DF2); + +	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, +			rt5677_dai, ARRAY_SIZE(rt5677_dai)); +	if (ret < 0) +		goto err; + +	return 0; +err: +	return ret; +} + +static int rt5677_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); + +	return 0; +} + +static struct i2c_driver rt5677_i2c_driver = { +	.driver = { +		.name = "rt5677", +		.owner = THIS_MODULE, +	}, +	.probe = rt5677_i2c_probe, +	.remove   = rt5677_i2c_remove, +	.id_table = rt5677_i2c_id, +}; + +static int __init rt5677_modinit(void) +{ +	return i2c_add_driver(&rt5677_i2c_driver); +} +module_init(rt5677_modinit); + +static void __exit rt5677_modexit(void) +{ +	i2c_del_driver(&rt5677_i2c_driver); +} +module_exit(rt5677_modexit); + +MODULE_DESCRIPTION("ASoC RT5677 driver"); +MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h new file mode 100644 index 00000000000..af4e9c79740 --- /dev/null +++ b/sound/soc/codecs/rt5677.h @@ -0,0 +1,1451 @@ +/* + * rt5677.h  --  RT5677 ALSA SoC audio driver + * + * Copyright 2013 Realtek Semiconductor Corp. + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5677_H__ +#define __RT5677_H__ + +#include <sound/rt5677.h> + +/* Info */ +#define RT5677_RESET				0x00 +#define RT5677_VENDOR_ID			0xfd +#define RT5677_VENDOR_ID1			0xfe +#define RT5677_VENDOR_ID2			0xff +/*  I/O - Output */ +#define RT5677_LOUT1				0x01 +/* I/O - Input */ +#define RT5677_IN1				0x03 +#define RT5677_MICBIAS				0x04 +/* I/O - SLIMBus */ +#define RT5677_SLIMBUS_PARAM			0x07 +#define RT5677_SLIMBUS_RX			0x08 +#define RT5677_SLIMBUS_CTRL			0x09 +/* I/O */ +#define RT5677_SIDETONE_CTRL			0x13 +/* I/O - ADC/DAC */ +#define RT5677_ANA_DAC1_2_3_SRC			0x15 +#define RT5677_IF_DSP_DAC3_4_MIXER		0x16 +#define RT5677_DAC4_DIG_VOL			0x17 +#define RT5677_DAC3_DIG_VOL			0x18 +#define RT5677_DAC1_DIG_VOL			0x19 +#define RT5677_DAC2_DIG_VOL			0x1a +#define RT5677_IF_DSP_DAC2_MIXER		0x1b +#define RT5677_STO1_ADC_DIG_VOL			0x1c +#define RT5677_MONO_ADC_DIG_VOL			0x1d +#define RT5677_STO1_2_ADC_BST			0x1e +#define RT5677_STO2_ADC_DIG_VOL			0x1f +/* Mixer - D-D */ +#define RT5677_ADC_BST_CTRL2			0x20 +#define RT5677_STO3_4_ADC_BST			0x21 +#define RT5677_STO3_ADC_DIG_VOL			0x22 +#define RT5677_STO4_ADC_DIG_VOL			0x23 +#define RT5677_STO4_ADC_MIXER			0x24 +#define RT5677_STO3_ADC_MIXER			0x25 +#define RT5677_STO2_ADC_MIXER			0x26 +#define RT5677_STO1_ADC_MIXER			0x27 +#define RT5677_MONO_ADC_MIXER			0x28 +#define RT5677_ADC_IF_DSP_DAC1_MIXER		0x29 +#define RT5677_STO1_DAC_MIXER			0x2a +#define RT5677_MONO_DAC_MIXER			0x2b +#define RT5677_DD1_MIXER			0x2c +#define RT5677_DD2_MIXER			0x2d +#define RT5677_IF3_DATA				0x2f +#define RT5677_IF4_DATA				0x30 +/* Mixer - PDM */ +#define RT5677_PDM_OUT_CTRL			0x31 +#define RT5677_PDM_DATA_CTRL1			0x32 +#define RT5677_PDM_DATA_CTRL2			0x33 +#define RT5677_PDM1_DATA_CTRL2			0x34 +#define RT5677_PDM1_DATA_CTRL3			0x35 +#define RT5677_PDM1_DATA_CTRL4			0x36 +#define RT5677_PDM2_DATA_CTRL2			0x37 +#define RT5677_PDM2_DATA_CTRL3			0x38 +#define RT5677_PDM2_DATA_CTRL4			0x39 +/* TDM */ +#define RT5677_TDM1_CTRL1			0x3b +#define RT5677_TDM1_CTRL2			0x3c +#define RT5677_TDM1_CTRL3			0x3d +#define RT5677_TDM1_CTRL4			0x3e +#define RT5677_TDM1_CTRL5			0x3f +#define RT5677_TDM2_CTRL1			0x40 +#define RT5677_TDM2_CTRL2			0x41 +#define RT5677_TDM2_CTRL3			0x42 +#define RT5677_TDM2_CTRL4			0x43 +#define RT5677_TDM2_CTRL5			0x44 +/* I2C_MASTER_CTRL */ +#define RT5677_I2C_MASTER_CTRL1			0x47 +#define RT5677_I2C_MASTER_CTRL2			0x48 +#define RT5677_I2C_MASTER_CTRL3			0x49 +#define RT5677_I2C_MASTER_CTRL4			0x4a +#define RT5677_I2C_MASTER_CTRL5			0x4b +#define RT5677_I2C_MASTER_CTRL6			0x4c +#define RT5677_I2C_MASTER_CTRL7			0x4d +#define RT5677_I2C_MASTER_CTRL8			0x4e +/* DMIC */ +#define RT5677_DMIC_CTRL1			0x50 +#define RT5677_DMIC_CTRL2			0x51 +/* Haptic Generator */ +#define RT5677_HAP_GENE_CTRL1			0x56 +#define RT5677_HAP_GENE_CTRL2			0x57 +#define RT5677_HAP_GENE_CTRL3			0x58 +#define RT5677_HAP_GENE_CTRL4			0x59 +#define RT5677_HAP_GENE_CTRL5			0x5a +#define RT5677_HAP_GENE_CTRL6			0x5b +#define RT5677_HAP_GENE_CTRL7			0x5c +#define RT5677_HAP_GENE_CTRL8			0x5d +#define RT5677_HAP_GENE_CTRL9			0x5e +#define RT5677_HAP_GENE_CTRL10			0x5f +/* Power */ +#define RT5677_PWR_DIG1				0x61 +#define RT5677_PWR_DIG2				0x62 +#define RT5677_PWR_ANLG1			0x63 +#define RT5677_PWR_ANLG2			0x64 +#define RT5677_PWR_DSP1				0x65 +#define RT5677_PWR_DSP_ST			0x66 +#define RT5677_PWR_DSP2				0x67 +#define RT5677_ADC_DAC_HPF_CTRL1		0x68 +/* Private Register Control */ +#define RT5677_PRIV_INDEX			0x6a +#define RT5677_PRIV_DATA			0x6c +/* Format - ADC/DAC */ +#define RT5677_I2S4_SDP				0x6f +#define RT5677_I2S1_SDP				0x70 +#define RT5677_I2S2_SDP				0x71 +#define RT5677_I2S3_SDP				0x72 +#define RT5677_CLK_TREE_CTRL1			0x73 +#define RT5677_CLK_TREE_CTRL2			0x74 +#define RT5677_CLK_TREE_CTRL3			0x75 +/* Function - Analog */ +#define RT5677_PLL1_CTRL1			0x7a +#define RT5677_PLL1_CTRL2			0x7b +#define RT5677_PLL2_CTRL1			0x7c +#define RT5677_PLL2_CTRL2			0x7d +#define RT5677_GLB_CLK1				0x80 +#define RT5677_GLB_CLK2				0x81 +#define RT5677_ASRC_1				0x83 +#define RT5677_ASRC_2				0x84 +#define RT5677_ASRC_3				0x85 +#define RT5677_ASRC_4				0x86 +#define RT5677_ASRC_5				0x87 +#define RT5677_ASRC_6				0x88 +#define RT5677_ASRC_7				0x89 +#define RT5677_ASRC_8				0x8a +#define RT5677_ASRC_9				0x8b +#define RT5677_ASRC_10				0x8c +#define RT5677_ASRC_11				0x8d +#define RT5677_ASRC_12				0x8e +#define RT5677_ASRC_13				0x8f +#define RT5677_ASRC_14				0x90 +#define RT5677_ASRC_15				0x91 +#define RT5677_ASRC_16				0x92 +#define RT5677_ASRC_17				0x93 +#define RT5677_ASRC_18				0x94 +#define RT5677_ASRC_19				0x95 +#define RT5677_ASRC_20				0x97 +#define RT5677_ASRC_21				0x98 +#define RT5677_ASRC_22				0x99 +#define RT5677_ASRC_23				0x9a +#define RT5677_VAD_CTRL1			0x9c +#define RT5677_VAD_CTRL2			0x9d +#define RT5677_VAD_CTRL3			0x9e +#define RT5677_VAD_CTRL4			0x9f +#define RT5677_VAD_CTRL5			0xa0 +/* Function - Digital */ +#define RT5677_DSP_INB_CTRL1			0xa3 +#define RT5677_DSP_INB_CTRL2			0xa4 +#define RT5677_DSP_IN_OUTB_CTRL			0xa5 +#define RT5677_DSP_OUTB0_1_DIG_VOL		0xa6 +#define RT5677_DSP_OUTB2_3_DIG_VOL		0xa7 +#define RT5677_DSP_OUTB4_5_DIG_VOL		0xa8 +#define RT5677_DSP_OUTB6_7_DIG_VOL		0xa9 +#define RT5677_ADC_EQ_CTRL1			0xae +#define RT5677_ADC_EQ_CTRL2			0xaf +#define RT5677_EQ_CTRL1				0xb0 +#define RT5677_EQ_CTRL2				0xb1 +#define RT5677_EQ_CTRL3				0xb2 +#define RT5677_SOFT_VOL_ZERO_CROSS1		0xb3 +#define RT5677_JD_CTRL1				0xb5 +#define RT5677_JD_CTRL2				0xb6 +#define RT5677_JD_CTRL3				0xb8 +#define RT5677_IRQ_CTRL1			0xbd +#define RT5677_IRQ_CTRL2			0xbe +#define RT5677_GPIO_ST				0xbf +#define RT5677_GPIO_CTRL1			0xc0 +#define RT5677_GPIO_CTRL2			0xc1 +#define RT5677_GPIO_CTRL3			0xc2 +#define RT5677_STO1_ADC_HI_FILTER1		0xc5 +#define RT5677_STO1_ADC_HI_FILTER2		0xc6 +#define RT5677_MONO_ADC_HI_FILTER1		0xc7 +#define RT5677_MONO_ADC_HI_FILTER2		0xc8 +#define RT5677_STO2_ADC_HI_FILTER1		0xc9 +#define RT5677_STO2_ADC_HI_FILTER2		0xca +#define RT5677_STO3_ADC_HI_FILTER1		0xcb +#define RT5677_STO3_ADC_HI_FILTER2		0xcc +#define RT5677_STO4_ADC_HI_FILTER1		0xcd +#define RT5677_STO4_ADC_HI_FILTER2		0xce +#define RT5677_MB_DRC_CTRL1			0xd0 +#define RT5677_DRC1_CTRL1			0xd2 +#define RT5677_DRC1_CTRL2			0xd3 +#define RT5677_DRC1_CTRL3			0xd4 +#define RT5677_DRC1_CTRL4			0xd5 +#define RT5677_DRC1_CTRL5			0xd6 +#define RT5677_DRC1_CTRL6			0xd7 +#define RT5677_DRC2_CTRL1			0xd8 +#define RT5677_DRC2_CTRL2			0xd9 +#define RT5677_DRC2_CTRL3			0xda +#define RT5677_DRC2_CTRL4			0xdb +#define RT5677_DRC2_CTRL5			0xdc +#define RT5677_DRC2_CTRL6			0xdd +#define RT5677_DRC1_HL_CTRL1			0xde +#define RT5677_DRC1_HL_CTRL2			0xdf +#define RT5677_DRC2_HL_CTRL1			0xe0 +#define RT5677_DRC2_HL_CTRL2			0xe1 +#define RT5677_DSP_INB1_SRC_CTRL1		0xe3 +#define RT5677_DSP_INB1_SRC_CTRL2		0xe4 +#define RT5677_DSP_INB1_SRC_CTRL3		0xe5 +#define RT5677_DSP_INB1_SRC_CTRL4		0xe6 +#define RT5677_DSP_INB2_SRC_CTRL1		0xe7 +#define RT5677_DSP_INB2_SRC_CTRL2		0xe8 +#define RT5677_DSP_INB2_SRC_CTRL3		0xe9 +#define RT5677_DSP_INB2_SRC_CTRL4		0xea +#define RT5677_DSP_INB3_SRC_CTRL1		0xeb +#define RT5677_DSP_INB3_SRC_CTRL2		0xec +#define RT5677_DSP_INB3_SRC_CTRL3		0xed +#define RT5677_DSP_INB3_SRC_CTRL4		0xee +#define RT5677_DSP_OUTB1_SRC_CTRL1		0xef +#define RT5677_DSP_OUTB1_SRC_CTRL2		0xf0 +#define RT5677_DSP_OUTB1_SRC_CTRL3		0xf1 +#define RT5677_DSP_OUTB1_SRC_CTRL4		0xf2 +#define RT5677_DSP_OUTB2_SRC_CTRL1		0xf3 +#define RT5677_DSP_OUTB2_SRC_CTRL2		0xf4 +#define RT5677_DSP_OUTB2_SRC_CTRL3		0xf5 +#define RT5677_DSP_OUTB2_SRC_CTRL4		0xf6 + +/* Virtual DSP Mixer Control */ +#define RT5677_DSP_OUTB_0123_MIXER_CTRL		0xf7 +#define RT5677_DSP_OUTB_45_MIXER_CTRL		0xf8 +#define RT5677_DSP_OUTB_67_MIXER_CTRL		0xf9 + +/* General Control */ +#define RT5677_DIG_MISC				0xfa +#define RT5677_GEN_CTRL1			0xfb +#define RT5677_GEN_CTRL2			0xfc + +/* DSP Mode I2C Control*/ +#define RT5677_DSP_I2C_OP_CODE			0x00 +#define RT5677_DSP_I2C_ADDR_LSB			0x01 +#define RT5677_DSP_I2C_ADDR_MSB			0x02 +#define RT5677_DSP_I2C_DATA_LSB			0x03 +#define RT5677_DSP_I2C_DATA_MSB			0x04 + +/* Index of Codec Private Register definition */ +#define RT5677_PR_DRC1_CTRL_1			0x01 +#define RT5677_PR_DRC1_CTRL_2			0x02 +#define RT5677_PR_DRC1_CTRL_3			0x03 +#define RT5677_PR_DRC1_CTRL_4			0x04 +#define RT5677_PR_DRC1_CTRL_5			0x05 +#define RT5677_PR_DRC1_CTRL_6			0x06 +#define RT5677_PR_DRC1_CTRL_7			0x07 +#define RT5677_PR_DRC2_CTRL_1			0x08 +#define RT5677_PR_DRC2_CTRL_2			0x09 +#define RT5677_PR_DRC2_CTRL_3			0x0a +#define RT5677_PR_DRC2_CTRL_4			0x0b +#define RT5677_PR_DRC2_CTRL_5			0x0c +#define RT5677_PR_DRC2_CTRL_6			0x0d +#define RT5677_PR_DRC2_CTRL_7			0x0e +#define RT5677_BIAS_CUR1			0x10 +#define RT5677_BIAS_CUR2			0x12 +#define RT5677_BIAS_CUR3			0x13 +#define RT5677_BIAS_CUR4			0x14 +#define RT5677_BIAS_CUR5			0x15 +#define RT5677_VREF_LOUT_CTRL			0x17 +#define RT5677_DIG_VOL_CTRL1			0x1a +#define RT5677_DIG_VOL_CTRL2			0x1b +#define RT5677_ANA_ADC_GAIN_CTRL		0x1e +#define RT5677_VAD_SRAM_TEST1			0x20 +#define RT5677_VAD_SRAM_TEST2			0x21 +#define RT5677_VAD_SRAM_TEST3			0x22 +#define RT5677_VAD_SRAM_TEST4			0x23 +#define RT5677_PAD_DRV_CTRL			0x26 +#define RT5677_DIG_IN_PIN_ST_CTRL1		0x29 +#define RT5677_DIG_IN_PIN_ST_CTRL2		0x2a +#define RT5677_DIG_IN_PIN_ST_CTRL3		0x2b +#define RT5677_PLL1_INT				0x38 +#define RT5677_PLL2_INT				0x39 +#define RT5677_TEST_CTRL1			0x3a +#define RT5677_TEST_CTRL2			0x3b +#define RT5677_TEST_CTRL3			0x3c +#define RT5677_CHOP_DAC_ADC			0x3d +#define RT5677_SOFT_DEPOP_DAC_CLK_CTRL		0x3e +#define RT5677_CROSS_OVER_FILTER1		0x90 +#define RT5677_CROSS_OVER_FILTER2		0x91 +#define RT5677_CROSS_OVER_FILTER3		0x92 +#define RT5677_CROSS_OVER_FILTER4		0x93 +#define RT5677_CROSS_OVER_FILTER5		0x94 +#define RT5677_CROSS_OVER_FILTER6		0x95 +#define RT5677_CROSS_OVER_FILTER7		0x96 +#define RT5677_CROSS_OVER_FILTER8		0x97 +#define RT5677_CROSS_OVER_FILTER9		0x98 +#define RT5677_CROSS_OVER_FILTER10		0x99 + +/* global definition */ +#define RT5677_L_MUTE				(0x1 << 15) +#define RT5677_L_MUTE_SFT			15 +#define RT5677_VOL_L_MUTE			(0x1 << 14) +#define RT5677_VOL_L_SFT			14 +#define RT5677_R_MUTE				(0x1 << 7) +#define RT5677_R_MUTE_SFT			7 +#define RT5677_VOL_R_MUTE			(0x1 << 6) +#define RT5677_VOL_R_SFT			6 +#define RT5677_L_VOL_MASK			(0x3f << 8) +#define RT5677_L_VOL_SFT			8 +#define RT5677_R_VOL_MASK			(0x3f) +#define RT5677_R_VOL_SFT			0 + +/* LOUT1 Control (0x01) */ +#define RT5677_LOUT1_L_MUTE			(0x1 << 15) +#define RT5677_LOUT1_L_MUTE_SFT			(15) +#define RT5677_LOUT1_L_DF			(0x1 << 14) +#define RT5677_LOUT1_L_DF_SFT			(14) +#define RT5677_LOUT2_L_MUTE			(0x1 << 13) +#define RT5677_LOUT2_L_MUTE_SFT			(13) +#define RT5677_LOUT2_L_DF			(0x1 << 12) +#define RT5677_LOUT2_L_DF_SFT			(12) +#define RT5677_LOUT3_L_MUTE			(0x1 << 11) +#define RT5677_LOUT3_L_MUTE_SFT			(11) +#define RT5677_LOUT3_L_DF			(0x1 << 10) +#define RT5677_LOUT3_L_DF_SFT			(10) +#define RT5677_LOUT1_ENH_DRV			(0x1 << 9) +#define RT5677_LOUT1_ENH_DRV_SFT		(9) +#define RT5677_LOUT2_ENH_DRV			(0x1 << 8) +#define RT5677_LOUT2_ENH_DRV_SFT		(8) +#define RT5677_LOUT3_ENH_DRV			(0x1 << 7) +#define RT5677_LOUT3_ENH_DRV_SFT		(7) + +/* IN1 Control (0x03) */ +#define RT5677_BST_MASK1			(0xf << 12) +#define RT5677_BST_SFT1				12 +#define RT5677_BST_MASK2			(0xf << 8) +#define RT5677_BST_SFT2				8 +#define RT5677_IN_DF1				(0x1 << 7) +#define RT5677_IN_DF1_SFT			7 +#define RT5677_IN_DF2				(0x1 << 6) +#define RT5677_IN_DF2_SFT			6 + +/* Micbias Control (0x04) */ +#define RT5677_MICBIAS1_OUTVOLT_MASK		(0x1 << 15) +#define RT5677_MICBIAS1_OUTVOLT_SFT		(15) +#define RT5677_MICBIAS1_OUTVOLT_2_7V		(0x0 << 15) +#define RT5677_MICBIAS1_OUTVOLT_2_25V		(0x1 << 15) +#define RT5677_MICBIAS1_CTRL_VDD_MASK		(0x1 << 14) +#define RT5677_MICBIAS1_CTRL_VDD_SFT		(14) +#define RT5677_MICBIAS1_CTRL_VDD_1_8V		(0x0 << 14) +#define RT5677_MICBIAS1_CTRL_VDD_3_3V		(0x1 << 14) +#define RT5677_MICBIAS1_OVCD_MASK		(0x1 << 11) +#define RT5677_MICBIAS1_OVCD_SHIFT		(11) +#define RT5677_MICBIAS1_OVCD_DIS		(0x0 << 11) +#define RT5677_MICBIAS1_OVCD_EN			(0x1 << 11) +#define RT5677_MICBIAS1_OVTH_MASK		(0x3 << 9) +#define RT5677_MICBIAS1_OVTH_SFT		9 +#define RT5677_MICBIAS1_OVTH_640UA		(0x0 << 9) +#define RT5677_MICBIAS1_OVTH_1280UA		(0x1 << 9) +#define RT5677_MICBIAS1_OVTH_1920UA		(0x2 << 9) + +/* SLIMbus Parameter (0x07) */ + +/* SLIMbus Rx (0x08) */ +#define RT5677_SLB_ADC4_MASK			(0x3 << 6) +#define RT5677_SLB_ADC4_SFT			6 +#define RT5677_SLB_ADC3_MASK			(0x3 << 4) +#define RT5677_SLB_ADC3_SFT			4 +#define RT5677_SLB_ADC2_MASK			(0x3 << 2) +#define RT5677_SLB_ADC2_SFT			2 +#define RT5677_SLB_ADC1_MASK			(0x3 << 0) +#define RT5677_SLB_ADC1_SFT			0 + +/* SLIMBus control (0x09) */ + +/* Sidetone Control (0x13) */ +#define RT5677_ST_HPF_SEL_MASK			(0x7 << 13) +#define RT5677_ST_HPF_SEL_SFT			13 +#define RT5677_ST_HPF_PATH			(0x1 << 12) +#define RT5677_ST_HPF_PATH_SFT			12 +#define RT5677_ST_SEL_MASK			(0x7 << 9) +#define RT5677_ST_SEL_SFT			9 +#define RT5677_ST_EN				(0x1 << 6) +#define RT5677_ST_EN_SFT			6 + +/* Analog DAC1/2/3 Source Control (0x15) */ +#define RT5677_ANA_DAC3_SRC_SEL_MASK		(0x3 << 4) +#define RT5677_ANA_DAC3_SRC_SEL_SFT		4 +#define RT5677_ANA_DAC1_2_SRC_SEL_MASK		(0x3 << 0) +#define RT5677_ANA_DAC1_2_SRC_SEL_SFT		0 + +/* IF/DSP to DAC3/4 Mixer Control (0x16) */ +#define RT5677_M_DAC4_L_VOL			(0x1 << 15) +#define RT5677_M_DAC4_L_VOL_SFT			15 +#define RT5677_SEL_DAC4_L_SRC_MASK		(0x7 << 12) +#define RT5677_SEL_DAC4_L_SRC_SFT		12 +#define RT5677_M_DAC4_R_VOL			(0x1 << 11) +#define RT5677_M_DAC4_R_VOL_SFT			11 +#define RT5677_SEL_DAC4_R_SRC_MASK		(0x7 << 8) +#define RT5677_SEL_DAC4_R_SRC_SFT		8 +#define RT5677_M_DAC3_L_VOL			(0x1 << 7) +#define RT5677_M_DAC3_L_VOL_SFT			7 +#define RT5677_SEL_DAC3_L_SRC_MASK		(0x7 << 4) +#define RT5677_SEL_DAC3_L_SRC_SFT		4 +#define RT5677_M_DAC3_R_VOL			(0x1 << 3) +#define RT5677_M_DAC3_R_VOL_SFT			3 +#define RT5677_SEL_DAC3_R_SRC_MASK		(0x7 << 0) +#define RT5677_SEL_DAC3_R_SRC_SFT		0 + +/* DAC4 Digital Volume (0x17) */ +#define RT5677_DAC4_L_VOL_MASK			(0xff << 8) +#define RT5677_DAC4_L_VOL_SFT			8 +#define RT5677_DAC4_R_VOL_MASK			(0xff) +#define RT5677_DAC4_R_VOL_SFT			0 + +/* DAC3 Digital Volume (0x18) */ +#define RT5677_DAC3_L_VOL_MASK			(0xff << 8) +#define RT5677_DAC3_L_VOL_SFT			8 +#define RT5677_DAC3_R_VOL_MASK			(0xff) +#define RT5677_DAC3_R_VOL_SFT			0 + +/* DAC3 Digital Volume (0x19) */ +#define RT5677_DAC1_L_VOL_MASK			(0xff << 8) +#define RT5677_DAC1_L_VOL_SFT			8 +#define RT5677_DAC1_R_VOL_MASK			(0xff) +#define RT5677_DAC1_R_VOL_SFT			0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5677_DAC2_L_VOL_MASK			(0xff << 8) +#define RT5677_DAC2_L_VOL_SFT			8 +#define RT5677_DAC2_R_VOL_MASK			(0xff) +#define RT5677_DAC2_R_VOL_SFT			0 + +/* IF/DSP to DAC2 Mixer Control (0x1b) */ +#define RT5677_M_DAC2_L_VOL			(0x1 << 7) +#define RT5677_M_DAC2_L_VOL_SFT			7 +#define RT5677_SEL_DAC2_L_SRC_MASK		(0x7 << 4) +#define RT5677_SEL_DAC2_L_SRC_SFT		4 +#define RT5677_M_DAC2_R_VOL			(0x1 << 3) +#define RT5677_M_DAC2_R_VOL_SFT			3 +#define RT5677_SEL_DAC2_R_SRC_MASK		(0x7 << 0) +#define RT5677_SEL_DAC2_R_SRC_SFT		0 + +/* Stereo1 ADC Digital Volume Control (0x1c) */ +#define RT5677_STO1_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5677_STO1_ADC_L_VOL_SFT		8 +#define RT5677_STO1_ADC_R_VOL_MASK		(0x7f) +#define RT5677_STO1_ADC_R_VOL_SFT		0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5677_MONO_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5677_MONO_ADC_L_VOL_SFT		8 +#define RT5677_MONO_ADC_R_VOL_MASK		(0x7f) +#define RT5677_MONO_ADC_R_VOL_SFT		0 + +/* Stereo 1/2 ADC Boost Gain Control (0x1e) */ +#define RT5677_STO1_ADC_L_BST_MASK		(0x3 << 14) +#define RT5677_STO1_ADC_L_BST_SFT		14 +#define RT5677_STO1_ADC_R_BST_MASK		(0x3 << 12) +#define RT5677_STO1_ADC_R_BST_SFT		12 +#define RT5677_STO1_ADC_COMP_MASK		(0x3 << 10) +#define RT5677_STO1_ADC_COMP_SFT		10 +#define RT5677_STO2_ADC_L_BST_MASK		(0x3 << 8) +#define RT5677_STO2_ADC_L_BST_SFT		8 +#define RT5677_STO2_ADC_R_BST_MASK		(0x3 << 6) +#define RT5677_STO2_ADC_R_BST_SFT		6 +#define RT5677_STO2_ADC_COMP_MASK		(0x3 << 4) +#define RT5677_STO2_ADC_COMP_SFT		4 + +/* Stereo2 ADC Digital Volume Control (0x1f) */ +#define RT5677_STO2_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5677_STO2_ADC_L_VOL_SFT		8 +#define RT5677_STO2_ADC_R_VOL_MASK		(0x7f) +#define RT5677_STO2_ADC_R_VOL_SFT		0 + +/* ADC Boost Gain Control 2 (0x20) */ +#define RT5677_MONO_ADC_L_BST_MASK		(0x3 << 14) +#define RT5677_MONO_ADC_L_BST_SFT		14 +#define RT5677_MONO_ADC_R_BST_MASK		(0x3 << 12) +#define RT5677_MONO_ADC_R_BST_SFT		12 +#define RT5677_MONO_ADC_COMP_MASK		(0x3 << 10) +#define RT5677_MONO_ADC_COMP_SFT		10 + +/* Stereo 3/4 ADC Boost Gain Control (0x21) */ +#define RT5677_STO3_ADC_L_BST_MASK		(0x3 << 14) +#define RT5677_STO3_ADC_L_BST_SFT		14 +#define RT5677_STO3_ADC_R_BST_MASK		(0x3 << 12) +#define RT5677_STO3_ADC_R_BST_SFT		12 +#define RT5677_STO3_ADC_COMP_MASK		(0x3 << 10) +#define RT5677_STO3_ADC_COMP_SFT		10 +#define RT5677_STO4_ADC_L_BST_MASK		(0x3 << 8) +#define RT5677_STO4_ADC_L_BST_SFT		8 +#define RT5677_STO4_ADC_R_BST_MASK		(0x3 << 6) +#define RT5677_STO4_ADC_R_BST_SFT		6 +#define RT5677_STO4_ADC_COMP_MASK		(0x3 << 4) +#define RT5677_STO4_ADC_COMP_SFT		4 + +/* Stereo3 ADC Digital Volume Control (0x22) */ +#define RT5677_STO3_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5677_STO3_ADC_L_VOL_SFT		8 +#define RT5677_STO3_ADC_R_VOL_MASK		(0x7f) +#define RT5677_STO3_ADC_R_VOL_SFT		0 + +/* Stereo4 ADC Digital Volume Control (0x23) */ +#define RT5677_STO4_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5677_STO4_ADC_L_VOL_SFT		8 +#define RT5677_STO4_ADC_R_VOL_MASK		(0x7f) +#define RT5677_STO4_ADC_R_VOL_SFT		0 + +/* Stereo4 ADC Mixer control (0x24) */ +#define RT5677_M_STO4_ADC_L2			(0x1 << 15) +#define RT5677_M_STO4_ADC_L2_SFT		15 +#define RT5677_M_STO4_ADC_L1			(0x1 << 14) +#define RT5677_M_STO4_ADC_L1_SFT		14 +#define RT5677_SEL_STO4_ADC1_MASK		(0x3 << 12) +#define RT5677_SEL_STO4_ADC1_SFT		12 +#define RT5677_SEL_STO4_ADC2_MASK		(0x3 << 10) +#define RT5677_SEL_STO4_ADC2_SFT		10 +#define RT5677_SEL_STO4_DMIC_MASK		(0x3 << 8) +#define RT5677_SEL_STO4_DMIC_SFT		8 +#define RT5677_M_STO4_ADC_R1			(0x1 << 7) +#define RT5677_M_STO4_ADC_R1_SFT		7 +#define RT5677_M_STO4_ADC_R2			(0x1 << 6) +#define RT5677_M_STO4_ADC_R2_SFT		6 + +/* Stereo3 ADC Mixer control (0x25) */ +#define RT5677_M_STO3_ADC_L2			(0x1 << 15) +#define RT5677_M_STO3_ADC_L2_SFT		15 +#define RT5677_M_STO3_ADC_L1			(0x1 << 14) +#define RT5677_M_STO3_ADC_L1_SFT		14 +#define RT5677_SEL_STO3_ADC1_MASK		(0x3 << 12) +#define RT5677_SEL_STO3_ADC1_SFT		12 +#define RT5677_SEL_STO3_ADC2_MASK		(0x3 << 10) +#define RT5677_SEL_STO3_ADC2_SFT		10 +#define RT5677_SEL_STO3_DMIC_MASK		(0x3 << 8) +#define RT5677_SEL_STO3_DMIC_SFT		8 +#define RT5677_M_STO3_ADC_R1			(0x1 << 7) +#define RT5677_M_STO3_ADC_R1_SFT		7 +#define RT5677_M_STO3_ADC_R2			(0x1 << 6) +#define RT5677_M_STO3_ADC_R2_SFT		6 + +/* Stereo2 ADC Mixer Control (0x26) */ +#define RT5677_M_STO2_ADC_L2			(0x1 << 15) +#define RT5677_M_STO2_ADC_L2_SFT		15 +#define RT5677_M_STO2_ADC_L1			(0x1 << 14) +#define RT5677_M_STO2_ADC_L1_SFT		14 +#define RT5677_SEL_STO2_ADC1_MASK		(0x3 << 12) +#define RT5677_SEL_STO2_ADC1_SFT		12 +#define RT5677_SEL_STO2_ADC2_MASK		(0x3 << 10) +#define RT5677_SEL_STO2_ADC2_SFT		10 +#define RT5677_SEL_STO2_DMIC_MASK		(0x3 << 8) +#define RT5677_SEL_STO2_DMIC_SFT		8 +#define RT5677_M_STO2_ADC_R1			(0x1 << 7) +#define RT5677_M_STO2_ADC_R1_SFT		7 +#define RT5677_M_STO2_ADC_R2			(0x1 << 6) +#define RT5677_M_STO2_ADC_R2_SFT		6 +#define RT5677_SEL_STO2_LR_MIX_MASK		(0x1 << 0) +#define RT5677_SEL_STO2_LR_MIX_SFT		0 +#define RT5677_SEL_STO2_LR_MIX_L		(0x0 << 0) +#define RT5677_SEL_STO2_LR_MIX_LR		(0x1 << 0) + +/* Stereo1 ADC Mixer control (0x27) */ +#define RT5677_M_STO1_ADC_L2			(0x1 << 15) +#define RT5677_M_STO1_ADC_L2_SFT		15 +#define RT5677_M_STO1_ADC_L1			(0x1 << 14) +#define RT5677_M_STO1_ADC_L1_SFT		14 +#define RT5677_SEL_STO1_ADC1_MASK		(0x3 << 12) +#define RT5677_SEL_STO1_ADC1_SFT		12 +#define RT5677_SEL_STO1_ADC2_MASK		(0x3 << 10) +#define RT5677_SEL_STO1_ADC2_SFT		10 +#define RT5677_SEL_STO1_DMIC_MASK		(0x3 << 8) +#define RT5677_SEL_STO1_DMIC_SFT		8 +#define RT5677_M_STO1_ADC_R1			(0x1 << 7) +#define RT5677_M_STO1_ADC_R1_SFT		7 +#define RT5677_M_STO1_ADC_R2			(0x1 << 6) +#define RT5677_M_STO1_ADC_R2_SFT		6 + +/* Mono ADC Mixer control (0x28) */ +#define RT5677_M_MONO_ADC_L2			(0x1 << 15) +#define RT5677_M_MONO_ADC_L2_SFT		15 +#define RT5677_M_MONO_ADC_L1			(0x1 << 14) +#define RT5677_M_MONO_ADC_L1_SFT		14 +#define RT5677_SEL_MONO_ADC_L1_MASK		(0x3 << 12) +#define RT5677_SEL_MONO_ADC_L1_SFT		12 +#define RT5677_SEL_MONO_ADC_L2_MASK		(0x3 << 10) +#define RT5677_SEL_MONO_ADC_L2_SFT		10 +#define RT5677_SEL_MONO_DMIC_L_MASK		(0x3 << 8) +#define RT5677_SEL_MONO_DMIC_L_SFT		8 +#define RT5677_M_MONO_ADC_R1			(0x1 << 7) +#define RT5677_M_MONO_ADC_R1_SFT		7 +#define RT5677_M_MONO_ADC_R2			(0x1 << 6) +#define RT5677_M_MONO_ADC_R2_SFT		6 +#define RT5677_SEL_MONO_ADC_R1_MASK		(0x3 << 4) +#define RT5677_SEL_MONO_ADC_R1_SFT		4 +#define RT5677_SEL_MONO_ADC_R2_MASK		(0x3 << 2) +#define RT5677_SEL_MONO_ADC_R2_SFT		2 +#define RT5677_SEL_MONO_DMIC_R_MASK		(0x3 << 0) +#define RT5677_SEL_MONO_DMIC_R_SFT		0 + +/* ADC/IF/DSP to DAC1 Mixer control (0x29) */ +#define RT5677_M_ADDA_MIXER1_L			(0x1 << 15) +#define RT5677_M_ADDA_MIXER1_L_SFT		15 +#define RT5677_M_DAC1_L				(0x1 << 14) +#define RT5677_M_DAC1_L_SFT			14 +#define RT5677_DAC1_L_SEL_MASK			(0x7 << 8) +#define RT5677_DAC1_L_SEL_SFT			8 +#define RT5677_M_ADDA_MIXER1_R			(0x1 << 7) +#define RT5677_M_ADDA_MIXER1_R_SFT		7 +#define RT5677_M_DAC1_R				(0x1 << 6) +#define RT5677_M_DAC1_R_SFT			6 +#define RT5677_ADDA1_SEL_MASK			(0x3 << 0) +#define RT5677_ADDA1_SEL_SFT			0 + +/* Stereo1 DAC Mixer L/R Control (0x2a) */ +#define RT5677_M_ST_DAC1_L			(0x1 << 15) +#define RT5677_M_ST_DAC1_L_SFT			15 +#define RT5677_M_DAC1_L_STO_L			(0x1 << 13) +#define RT5677_M_DAC1_L_STO_L_SFT		13 +#define RT5677_DAC1_L_STO_L_VOL_MASK		(0x1 << 12) +#define RT5677_DAC1_L_STO_L_VOL_SFT		12 +#define RT5677_M_DAC2_L_STO_L			(0x1 << 11) +#define RT5677_M_DAC2_L_STO_L_SFT		11 +#define RT5677_DAC2_L_STO_L_VOL_MASK		(0x1 << 10) +#define RT5677_DAC2_L_STO_L_VOL_SFT		10 +#define RT5677_M_DAC1_R_STO_L			(0x1 << 9) +#define RT5677_M_DAC1_R_STO_L_SFT		9 +#define RT5677_DAC1_R_STO_L_VOL_MASK		(0x1 << 8) +#define RT5677_DAC1_R_STO_L_VOL_SFT		8 +#define RT5677_M_ST_DAC1_R			(0x1 << 7) +#define RT5677_M_ST_DAC1_R_SFT			7 +#define RT5677_M_DAC1_R_STO_R			(0x1 << 5) +#define RT5677_M_DAC1_R_STO_R_SFT		5 +#define RT5677_DAC1_R_STO_R_VOL_MASK		(0x1 << 4) +#define RT5677_DAC1_R_STO_R_VOL_SFT		4 +#define RT5677_M_DAC2_R_STO_R			(0x1 << 3) +#define RT5677_M_DAC2_R_STO_R_SFT		3 +#define RT5677_DAC2_R_STO_R_VOL_MASK		(0x1 << 2) +#define RT5677_DAC2_R_STO_R_VOL_SFT		2 +#define RT5677_M_DAC1_L_STO_R			(0x1 << 1) +#define RT5677_M_DAC1_L_STO_R_SFT		1 +#define RT5677_DAC1_L_STO_R_VOL_MASK		(0x1 << 0) +#define RT5677_DAC1_L_STO_R_VOL_SFT		0 + +/* Mono DAC Mixer L/R Control (0x2b) */ +#define RT5677_M_ST_DAC2_L			(0x1 << 15) +#define RT5677_M_ST_DAC2_L_SFT			15 +#define RT5677_M_DAC2_L_MONO_L			(0x1 << 13) +#define RT5677_M_DAC2_L_MONO_L_SFT		13 +#define RT5677_DAC2_L_MONO_L_VOL_MASK		(0x1 << 12) +#define RT5677_DAC2_L_MONO_L_VOL_SFT		12 +#define RT5677_M_DAC2_R_MONO_L			(0x1 << 11) +#define RT5677_M_DAC2_R_MONO_L_SFT		11 +#define RT5677_DAC2_R_MONO_L_VOL_MASK		(0x1 << 10) +#define RT5677_DAC2_R_MONO_L_VOL_SFT		10 +#define RT5677_M_DAC1_L_MONO_L			(0x1 << 9) +#define RT5677_M_DAC1_L_MONO_L_SFT		9 +#define RT5677_DAC1_L_MONO_L_VOL_MASK		(0x1 << 8) +#define RT5677_DAC1_L_MONO_L_VOL_SFT		8 +#define RT5677_M_ST_DAC2_R			(0x1 << 7) +#define RT5677_M_ST_DAC2_R_SFT			7 +#define RT5677_M_DAC2_R_MONO_R			(0x1 << 5) +#define RT5677_M_DAC2_R_MONO_R_SFT		5 +#define RT5677_DAC2_R_MONO_R_VOL_MASK		(0x1 << 4) +#define RT5677_DAC2_R_MONO_R_VOL_SFT		4 +#define RT5677_M_DAC1_R_MONO_R			(0x1 << 3) +#define RT5677_M_DAC1_R_MONO_R_SFT		3 +#define RT5677_DAC1_R_MONO_R_VOL_MASK		(0x1 << 2) +#define RT5677_DAC1_R_MONO_R_VOL_SFT		2 +#define RT5677_M_DAC2_L_MONO_R			(0x1 << 1) +#define RT5677_M_DAC2_L_MONO_R_SFT		1 +#define RT5677_DAC2_L_MONO_R_VOL_MASK		(0x1 << 0) +#define RT5677_DAC2_L_MONO_R_VOL_SFT		0 + +/* DD Mixer 1 Control (0x2c) */ +#define RT5677_M_STO_L_DD1_L			(0x1 << 15) +#define RT5677_M_STO_L_DD1_L_SFT		15 +#define RT5677_STO_L_DD1_L_VOL_MASK		(0x1 << 14) +#define RT5677_STO_L_DD1_L_VOL_SFT		14 +#define RT5677_M_MONO_L_DD1_L			(0x1 << 13) +#define RT5677_M_MONO_L_DD1_L_SFT		13 +#define RT5677_MONO_L_DD1_L_VOL_MASK		(0x1 << 12) +#define RT5677_MONO_L_DD1_L_VOL_SFT		12 +#define RT5677_M_DAC3_L_DD1_L			(0x1 << 11) +#define RT5677_M_DAC3_L_DD1_L_SFT		11 +#define RT5677_DAC3_L_DD1_L_VOL_MASK		(0x1 << 10) +#define RT5677_DAC3_L_DD1_L_VOL_SFT		10 +#define RT5677_M_DAC3_R_DD1_L			(0x1 << 9) +#define RT5677_M_DAC3_R_DD1_L_SFT		9 +#define RT5677_DAC3_R_DD1_L_VOL_MASK		(0x1 << 8) +#define RT5677_DAC3_R_DD1_L_VOL_SFT		8 +#define RT5677_M_STO_R_DD1_R			(0x1 << 7) +#define RT5677_M_STO_R_DD1_R_SFT		7 +#define RT5677_STO_R_DD1_R_VOL_MASK		(0x1 << 6) +#define RT5677_STO_R_DD1_R_VOL_SFT		6 +#define RT5677_M_MONO_R_DD1_R			(0x1 << 5) +#define RT5677_M_MONO_R_DD1_R_SFT		5 +#define RT5677_MONO_R_DD1_R_VOL_MASK		(0x1 << 4) +#define RT5677_MONO_R_DD1_R_VOL_SFT		4 +#define RT5677_M_DAC3_R_DD1_R			(0x1 << 3) +#define RT5677_M_DAC3_R_DD1_R_SFT		3 +#define RT5677_DAC3_R_DD1_R_VOL_MASK		(0x1 << 2) +#define RT5677_DAC3_R_DD1_R_VOL_SFT		2 +#define RT5677_M_DAC3_L_DD1_R			(0x1 << 1) +#define RT5677_M_DAC3_L_DD1_R_SFT		1 +#define RT5677_DAC3_L_DD1_R_VOL_MASK		(0x1 << 0) +#define RT5677_DAC3_L_DD1_R_VOL_SFT		0 + +/* DD Mixer 2 Control (0x2d) */ +#define RT5677_M_STO_L_DD2_L			(0x1 << 15) +#define RT5677_M_STO_L_DD2_L_SFT		15 +#define RT5677_STO_L_DD2_L_VOL_MASK		(0x1 << 14) +#define RT5677_STO_L_DD2_L_VOL_SFT		14 +#define RT5677_M_MONO_L_DD2_L			(0x1 << 13) +#define RT5677_M_MONO_L_DD2_L_SFT		13 +#define RT5677_MONO_L_DD2_L_VOL_MASK		(0x1 << 12) +#define RT5677_MONO_L_DD2_L_VOL_SFT		12 +#define RT5677_M_DAC4_L_DD2_L			(0x1 << 11) +#define RT5677_M_DAC4_L_DD2_L_SFT		11 +#define RT5677_DAC4_L_DD2_L_VOL_MASK		(0x1 << 10) +#define RT5677_DAC4_L_DD2_L_VOL_SFT		10 +#define RT5677_M_DAC4_R_DD2_L			(0x1 << 9) +#define RT5677_M_DAC4_R_DD2_L_SFT		9 +#define RT5677_DAC4_R_DD2_L_VOL_MASK		(0x1 << 8) +#define RT5677_DAC4_R_DD2_L_VOL_SFT		8 +#define RT5677_M_STO_R_DD2_R			(0x1 << 7) +#define RT5677_M_STO_R_DD2_R_SFT		7 +#define RT5677_STO_R_DD2_R_VOL_MASK		(0x1 << 6) +#define RT5677_STO_R_DD2_R_VOL_SFT		6 +#define RT5677_M_MONO_R_DD2_R			(0x1 << 5) +#define RT5677_M_MONO_R_DD2_R_SFT		5 +#define RT5677_MONO_R_DD2_R_VOL_MASK		(0x1 << 4) +#define RT5677_MONO_R_DD2_R_VOL_SFT		4 +#define RT5677_M_DAC4_R_DD2_R			(0x1 << 3) +#define RT5677_M_DAC4_R_DD2_R_SFT		3 +#define RT5677_DAC4_R_DD2_R_VOL_MASK		(0x1 << 2) +#define RT5677_DAC4_R_DD2_R_VOL_SFT		2 +#define RT5677_M_DAC4_L_DD2_R			(0x1 << 1) +#define RT5677_M_DAC4_L_DD2_R_SFT		1 +#define RT5677_DAC4_L_DD2_R_VOL_MASK		(0x1 << 0) +#define RT5677_DAC4_L_DD2_R_VOL_SFT		0 + +/* IF3 data control (0x2f) */ +#define RT5677_IF3_DAC_SEL_MASK			(0x3 << 6) +#define RT5677_IF3_DAC_SEL_SFT			6 +#define RT5677_IF3_ADC_SEL_MASK			(0x3 << 4) +#define RT5677_IF3_ADC_SEL_SFT			4 +#define RT5677_IF3_ADC_IN_MASK			(0xf << 0) +#define RT5677_IF3_ADC_IN_SFT			0 + +/* IF4 data control (0x30) */ +#define RT5677_IF4_ADC_IN_MASK			(0xf << 4) +#define RT5677_IF4_ADC_IN_SFT			4 +#define RT5677_IF4_DAC_SEL_MASK			(0x3 << 2) +#define RT5677_IF4_DAC_SEL_SFT			2 +#define RT5677_IF4_ADC_SEL_MASK			(0x3 << 0) +#define RT5677_IF4_ADC_SEL_SFT			0 + +/* PDM Output Control (0x31) */ +#define RT5677_M_PDM1_L				(0x1 << 15) +#define RT5677_M_PDM1_L_SFT			15 +#define RT5677_SEL_PDM1_L_MASK			(0x3 << 12) +#define RT5677_SEL_PDM1_L_SFT			12 +#define RT5677_M_PDM1_R				(0x1 << 11) +#define RT5677_M_PDM1_R_SFT			11 +#define RT5677_SEL_PDM1_R_MASK			(0x3 << 8) +#define RT5677_SEL_PDM1_R_SFT			8 +#define RT5677_M_PDM2_L				(0x1 << 7) +#define RT5677_M_PDM2_L_SFT			7 +#define RT5677_SEL_PDM2_L_MASK			(0x3 << 4) +#define RT5677_SEL_PDM2_L_SFT			4 +#define RT5677_M_PDM2_R				(0x1 << 3) +#define RT5677_M_PDM2_R_SFT			3 +#define RT5677_SEL_PDM2_R_MASK			(0x3 << 0) +#define RT5677_SEL_PDM2_R_SFT			0 + +/* PDM I2C / Data Control 1 (0x32) */ +#define RT5677_PDM2_PW_DOWN			(0x1 << 7) +#define RT5677_PDM1_PW_DOWN			(0x1 << 6) +#define RT5677_PDM2_BUSY			(0x1 << 5) +#define RT5677_PDM1_BUSY			(0x1 << 4) +#define RT5677_PDM_PATTERN			(0x1 << 3) +#define RT5677_PDM_GAIN				(0x1 << 2) +#define RT5677_PDM_DIV_MASK			(0x3 << 0) + +/* PDM I2C / Data Control 2 (0x33) */ +#define RT5677_PDM1_I2C_ID			(0xf << 12) +#define RT5677_PDM1_EXE				(0x1 << 11) +#define RT5677_PDM1_I2C_CMD			(0x1 << 10) +#define RT5677_PDM1_I2C_EXE			(0x1 << 9) +#define RT5677_PDM1_I2C_BUSY			(0x1 << 8) +#define RT5677_PDM2_I2C_ID			(0xf << 4) +#define RT5677_PDM2_EXE				(0x1 << 3) +#define RT5677_PDM2_I2C_CMD			(0x1 << 2) +#define RT5677_PDM2_I2C_EXE			(0x1 << 1) +#define RT5677_PDM2_I2C_BUSY			(0x1 << 0) + +/* MX3C TDM1 control 1 (0x3c) */ +#define RT5677_IF1_ADC4_MASK			(0x3 << 10) +#define RT5677_IF1_ADC4_SFT			10 +#define RT5677_IF1_ADC3_MASK			(0x3 << 8) +#define RT5677_IF1_ADC3_SFT			8 +#define RT5677_IF1_ADC2_MASK			(0x3 << 6) +#define RT5677_IF1_ADC2_SFT			6 +#define RT5677_IF1_ADC1_MASK			(0x3 << 4) +#define RT5677_IF1_ADC1_SFT			4 + +/* MX41 TDM2 control 1 (0x41) */ +#define RT5677_IF2_ADC4_MASK			(0x3 << 10) +#define RT5677_IF2_ADC4_SFT			10 +#define RT5677_IF2_ADC3_MASK			(0x3 << 8) +#define RT5677_IF2_ADC3_SFT			8 +#define RT5677_IF2_ADC2_MASK			(0x3 << 6) +#define RT5677_IF2_ADC2_SFT			6 +#define RT5677_IF2_ADC1_MASK			(0x3 << 4) +#define RT5677_IF2_ADC1_SFT			4 + +/* Digital Microphone Control 1 (0x50) */ +#define RT5677_DMIC_1_EN_MASK			(0x1 << 15) +#define RT5677_DMIC_1_EN_SFT			15 +#define RT5677_DMIC_1_DIS			(0x0 << 15) +#define RT5677_DMIC_1_EN			(0x1 << 15) +#define RT5677_DMIC_2_EN_MASK			(0x1 << 14) +#define RT5677_DMIC_2_EN_SFT			14 +#define RT5677_DMIC_2_DIS			(0x0 << 14) +#define RT5677_DMIC_2_EN			(0x1 << 14) +#define RT5677_DMIC_L_STO1_LH_MASK		(0x1 << 13) +#define RT5677_DMIC_L_STO1_LH_SFT		13 +#define RT5677_DMIC_L_STO1_LH_FALLING		(0x0 << 13) +#define RT5677_DMIC_L_STO1_LH_RISING		(0x1 << 13) +#define RT5677_DMIC_R_STO1_LH_MASK		(0x1 << 12) +#define RT5677_DMIC_R_STO1_LH_SFT		12 +#define RT5677_DMIC_R_STO1_LH_FALLING		(0x0 << 12) +#define RT5677_DMIC_R_STO1_LH_RISING		(0x1 << 12) +#define RT5677_DMIC_L_STO3_LH_MASK		(0x1 << 11) +#define RT5677_DMIC_L_STO3_LH_SFT		11 +#define RT5677_DMIC_L_STO3_LH_FALLING		(0x0 << 11) +#define RT5677_DMIC_L_STO3_LH_RISING		(0x1 << 11) +#define RT5677_DMIC_R_STO3_LH_MASK		(0x1 << 10) +#define RT5677_DMIC_R_STO3_LH_SFT		10 +#define RT5677_DMIC_R_STO3_LH_FALLING		(0x0 << 10) +#define RT5677_DMIC_R_STO3_LH_RISING		(0x1 << 10) +#define RT5677_DMIC_L_STO2_LH_MASK		(0x1 << 9) +#define RT5677_DMIC_L_STO2_LH_SFT		9 +#define RT5677_DMIC_L_STO2_LH_FALLING		(0x0 << 9) +#define RT5677_DMIC_L_STO2_LH_RISING		(0x1 << 9) +#define RT5677_DMIC_R_STO2_LH_MASK		(0x1 << 8) +#define RT5677_DMIC_R_STO2_LH_SFT		8 +#define RT5677_DMIC_R_STO2_LH_FALLING		(0x0 << 8) +#define RT5677_DMIC_R_STO2_LH_RISING		(0x1 << 8) +#define RT5677_DMIC_CLK_MASK			(0x7 << 5) +#define RT5677_DMIC_CLK_SFT			5 +#define RT5677_DMIC_3_EN_MASK			(0x1 << 4) +#define RT5677_DMIC_3_EN_SFT			4 +#define RT5677_DMIC_3_DIS			(0x0 << 4) +#define RT5677_DMIC_3_EN			(0x1 << 4) +#define RT5677_DMIC_R_MONO_LH_MASK		(0x1 << 2) +#define RT5677_DMIC_R_MONO_LH_SFT		2 +#define RT5677_DMIC_R_MONO_LH_FALLING		(0x0 << 2) +#define RT5677_DMIC_R_MONO_LH_RISING		(0x1 << 2) +#define RT5677_DMIC_L_STO4_LH_MASK		(0x1 << 1) +#define RT5677_DMIC_L_STO4_LH_SFT		1 +#define RT5677_DMIC_L_STO4_LH_FALLING		(0x0 << 1) +#define RT5677_DMIC_L_STO4_LH_RISING		(0x1 << 1) +#define RT5677_DMIC_R_STO4_LH_MASK		(0x1 << 0) +#define RT5677_DMIC_R_STO4_LH_SFT		0 +#define RT5677_DMIC_R_STO4_LH_FALLING		(0x0 << 0) +#define RT5677_DMIC_R_STO4_LH_RISING		(0x1 << 0) + +/* Digital Microphone Control 2 (0x51) */ +#define RT5677_DMIC_4_EN_MASK			(0x1 << 15) +#define RT5677_DMIC_4_EN_SFT			15 +#define RT5677_DMIC_4_DIS			(0x0 << 15) +#define RT5677_DMIC_4_EN			(0x1 << 15) +#define RT5677_DMIC_4L_LH_MASK			(0x1 << 7) +#define RT5677_DMIC_4L_LH_SFT			7 +#define RT5677_DMIC_4L_LH_FALLING		(0x0 << 7) +#define RT5677_DMIC_4L_LH_RISING		(0x1 << 7) +#define RT5677_DMIC_4R_LH_MASK			(0x1 << 6) +#define RT5677_DMIC_4R_LH_SFT			6 +#define RT5677_DMIC_4R_LH_FALLING		(0x0 << 6) +#define RT5677_DMIC_4R_LH_RISING		(0x1 << 6) +#define RT5677_DMIC_3L_LH_MASK			(0x1 << 5) +#define RT5677_DMIC_3L_LH_SFT			5 +#define RT5677_DMIC_3L_LH_FALLING		(0x0 << 5) +#define RT5677_DMIC_3L_LH_RISING		(0x1 << 5) +#define RT5677_DMIC_3R_LH_MASK			(0x1 << 4) +#define RT5677_DMIC_3R_LH_SFT			4 +#define RT5677_DMIC_3R_LH_FALLING		(0x0 << 4) +#define RT5677_DMIC_3R_LH_RISING		(0x1 << 4) +#define RT5677_DMIC_2L_LH_MASK			(0x1 << 3) +#define RT5677_DMIC_2L_LH_SFT			3 +#define RT5677_DMIC_2L_LH_FALLING		(0x0 << 3) +#define RT5677_DMIC_2L_LH_RISING		(0x1 << 3) +#define RT5677_DMIC_2R_LH_MASK			(0x1 << 2) +#define RT5677_DMIC_2R_LH_SFT			2 +#define RT5677_DMIC_2R_LH_FALLING		(0x0 << 2) +#define RT5677_DMIC_2R_LH_RISING		(0x1 << 2) +#define RT5677_DMIC_1L_LH_MASK			(0x1 << 1) +#define RT5677_DMIC_1L_LH_SFT			1 +#define RT5677_DMIC_1L_LH_FALLING		(0x0 << 1) +#define RT5677_DMIC_1L_LH_RISING		(0x1 << 1) +#define RT5677_DMIC_1R_LH_MASK			(0x1 << 0) +#define RT5677_DMIC_1R_LH_SFT			0 +#define RT5677_DMIC_1R_LH_FALLING		(0x0 << 0) +#define RT5677_DMIC_1R_LH_RISING		(0x1 << 0) + +/* Power Management for Digital 1 (0x61) */ +#define RT5677_PWR_I2S1				(0x1 << 15) +#define RT5677_PWR_I2S1_BIT			15 +#define RT5677_PWR_I2S2				(0x1 << 14) +#define RT5677_PWR_I2S2_BIT			14 +#define RT5677_PWR_I2S3				(0x1 << 13) +#define RT5677_PWR_I2S3_BIT			13 +#define RT5677_PWR_DAC1				(0x1 << 12) +#define RT5677_PWR_DAC1_BIT			12 +#define RT5677_PWR_DAC2				(0x1 << 11) +#define RT5677_PWR_DAC2_BIT			11 +#define RT5677_PWR_I2S4				(0x1 << 10) +#define RT5677_PWR_I2S4_BIT			10 +#define RT5677_PWR_SLB				(0x1 << 9) +#define RT5677_PWR_SLB_BIT			9 +#define RT5677_PWR_DAC3				(0x1 << 7) +#define RT5677_PWR_DAC3_BIT			7 +#define RT5677_PWR_ADCFED2			(0x1 << 4) +#define RT5677_PWR_ADCFED2_BIT			4 +#define RT5677_PWR_ADCFED1			(0x1 << 3) +#define RT5677_PWR_ADCFED1_BIT			3 +#define RT5677_PWR_ADC_L			(0x1 << 2) +#define RT5677_PWR_ADC_L_BIT			2 +#define RT5677_PWR_ADC_R			(0x1 << 1) +#define RT5677_PWR_ADC_R_BIT			1 +#define RT5677_PWR_I2C_MASTER			(0x1 << 0) +#define RT5677_PWR_I2C_MASTER_BIT		0 + +/* Power Management for Digital 2 (0x62) */ +#define RT5677_PWR_ADC_S1F			(0x1 << 15) +#define RT5677_PWR_ADC_S1F_BIT			15 +#define RT5677_PWR_ADC_MF_L			(0x1 << 14) +#define RT5677_PWR_ADC_MF_L_BIT			14 +#define RT5677_PWR_ADC_MF_R			(0x1 << 13) +#define RT5677_PWR_ADC_MF_R_BIT			13 +#define RT5677_PWR_DAC_S1F			(0x1 << 12) +#define RT5677_PWR_DAC_S1F_BIT			12 +#define RT5677_PWR_DAC_M2F_L			(0x1 << 11) +#define RT5677_PWR_DAC_M2F_L_BIT		11 +#define RT5677_PWR_DAC_M2F_R			(0x1 << 10) +#define RT5677_PWR_DAC_M2F_R_BIT		10 +#define RT5677_PWR_DAC_M3F_L			(0x1 << 9) +#define RT5677_PWR_DAC_M3F_L_BIT		9 +#define RT5677_PWR_DAC_M3F_R			(0x1 << 8) +#define RT5677_PWR_DAC_M3F_R_BIT		8 +#define RT5677_PWR_DAC_M4F_L			(0x1 << 7) +#define RT5677_PWR_DAC_M4F_L_BIT		7 +#define RT5677_PWR_DAC_M4F_R			(0x1 << 6) +#define RT5677_PWR_DAC_M4F_R_BIT		6 +#define RT5677_PWR_ADC_S2F			(0x1 << 5) +#define RT5677_PWR_ADC_S2F_BIT			5 +#define RT5677_PWR_ADC_S3F			(0x1 << 4) +#define RT5677_PWR_ADC_S3F_BIT			4 +#define RT5677_PWR_ADC_S4F			(0x1 << 3) +#define RT5677_PWR_ADC_S4F_BIT			3 +#define RT5677_PWR_PDM1				(0x1 << 2) +#define RT5677_PWR_PDM1_BIT			2 +#define RT5677_PWR_PDM2				(0x1 << 1) +#define RT5677_PWR_PDM2_BIT			1 + +/* Power Management for Analog 1 (0x63) */ +#define RT5677_PWR_VREF1			(0x1 << 15) +#define RT5677_PWR_VREF1_BIT			15 +#define RT5677_PWR_FV1				(0x1 << 14) +#define RT5677_PWR_FV1_BIT			14 +#define RT5677_PWR_MB				(0x1 << 13) +#define RT5677_PWR_MB_BIT			13 +#define RT5677_PWR_LO1				(0x1 << 12) +#define RT5677_PWR_LO1_BIT			12 +#define RT5677_PWR_BG				(0x1 << 11) +#define RT5677_PWR_BG_BIT			11 +#define RT5677_PWR_LO2				(0x1 << 10) +#define RT5677_PWR_LO2_BIT			10 +#define RT5677_PWR_LO3				(0x1 << 9) +#define RT5677_PWR_LO3_BIT			9 +#define RT5677_PWR_VREF2			(0x1 << 8) +#define RT5677_PWR_VREF2_BIT			8 +#define RT5677_PWR_FV2				(0x1 << 7) +#define RT5677_PWR_FV2_BIT			7 +#define RT5677_LDO2_SEL_MASK			(0x7 << 4) +#define RT5677_LDO2_SEL_SFT			4 +#define RT5677_LDO1_SEL_MASK			(0x7 << 0) +#define RT5677_LDO1_SEL_SFT			0 + +/* Power Management for Analog 2 (0x64) */ +#define RT5677_PWR_BST1				(0x1 << 15) +#define RT5677_PWR_BST1_BIT			15 +#define RT5677_PWR_BST2				(0x1 << 14) +#define RT5677_PWR_BST2_BIT			14 +#define RT5677_PWR_CLK_MB1			(0x1 << 13) +#define RT5677_PWR_CLK_MB1_BIT			13 +#define RT5677_PWR_SLIM				(0x1 << 12) +#define RT5677_PWR_SLIM_BIT			12 +#define RT5677_PWR_MB1				(0x1 << 11) +#define RT5677_PWR_MB1_BIT			11 +#define RT5677_PWR_PP_MB1			(0x1 << 10) +#define RT5677_PWR_PP_MB1_BIT			10 +#define RT5677_PWR_PLL1				(0x1 << 9) +#define RT5677_PWR_PLL1_BIT			9 +#define RT5677_PWR_PLL2				(0x1 << 8) +#define RT5677_PWR_PLL2_BIT			8 +#define RT5677_PWR_CORE				(0x1 << 7) +#define RT5677_PWR_CORE_BIT			7 +#define RT5677_PWR_CLK_MB			(0x1 << 6) +#define RT5677_PWR_CLK_MB_BIT			6 +#define RT5677_PWR_BST1_P			(0x1 << 5) +#define RT5677_PWR_BST1_P_BIT			5 +#define RT5677_PWR_BST2_P			(0x1 << 4) +#define RT5677_PWR_BST2_P_BIT			4 +#define RT5677_PWR_IPTV				(0x1 << 3) +#define RT5677_PWR_IPTV_BIT			3 +#define RT5677_PWR_25M_CLK			(0x1 << 1) +#define RT5677_PWR_25M_CLK_BIT			1 +#define RT5677_PWR_LDO1				(0x1 << 0) +#define RT5677_PWR_LDO1_BIT			0 + +/* Power Management for DSP (0x65) */ +#define RT5677_PWR_SR7				(0x1 << 10) +#define RT5677_PWR_SR7_BIT			10 +#define RT5677_PWR_SR6				(0x1 << 9) +#define RT5677_PWR_SR6_BIT			9 +#define RT5677_PWR_SR5				(0x1 << 8) +#define RT5677_PWR_SR5_BIT			8 +#define RT5677_PWR_SR4				(0x1 << 7) +#define RT5677_PWR_SR4_BIT			7 +#define RT5677_PWR_SR3				(0x1 << 6) +#define RT5677_PWR_SR3_BIT			6 +#define RT5677_PWR_SR2				(0x1 << 5) +#define RT5677_PWR_SR2_BIT			5 +#define RT5677_PWR_SR1				(0x1 << 4) +#define RT5677_PWR_SR1_BIT			4 +#define RT5677_PWR_SR0				(0x1 << 3) +#define RT5677_PWR_SR0_BIT			3 +#define RT5677_PWR_MLT				(0x1 << 2) +#define RT5677_PWR_MLT_BIT			2 +#define RT5677_PWR_DSP				(0x1 << 1) +#define RT5677_PWR_DSP_BIT			1 +#define RT5677_PWR_DSP_CPU			(0x1 << 0) +#define RT5677_PWR_DSP_CPU_BIT			0 + +/* Power Status for DSP (0x66) */ +#define RT5677_PWR_SR7_RDY			(0x1 << 9) +#define RT5677_PWR_SR7_RDY_BIT			9 +#define RT5677_PWR_SR6_RDY			(0x1 << 8) +#define RT5677_PWR_SR6_RDY_BIT			8 +#define RT5677_PWR_SR5_RDY			(0x1 << 7) +#define RT5677_PWR_SR5_RDY_BIT			7 +#define RT5677_PWR_SR4_RDY			(0x1 << 6) +#define RT5677_PWR_SR4_RDY_BIT			6 +#define RT5677_PWR_SR3_RDY			(0x1 << 5) +#define RT5677_PWR_SR3_RDY_BIT			5 +#define RT5677_PWR_SR2_RDY			(0x1 << 4) +#define RT5677_PWR_SR2_RDY_BIT			4 +#define RT5677_PWR_SR1_RDY			(0x1 << 3) +#define RT5677_PWR_SR1_RDY_BIT			3 +#define RT5677_PWR_SR0_RDY			(0x1 << 2) +#define RT5677_PWR_SR0_RDY_BIT			2 +#define RT5677_PWR_MLT_RDY			(0x1 << 1) +#define RT5677_PWR_MLT_RDY_BIT			1 +#define RT5677_PWR_DSP_RDY			(0x1 << 0) +#define RT5677_PWR_DSP_RDY_BIT			0 + +/* Power Management for DSP (0x67) */ +#define RT5677_PWR_SLIM_ISO			(0x1 << 11) +#define RT5677_PWR_SLIM_ISO_BIT			11 +#define RT5677_PWR_CORE_ISO			(0x1 << 10) +#define RT5677_PWR_CORE_ISO_BIT			10 +#define RT5677_PWR_DSP_ISO			(0x1 << 9) +#define RT5677_PWR_DSP_ISO_BIT			9 +#define RT5677_PWR_SR7_ISO			(0x1 << 8) +#define RT5677_PWR_SR7_ISO_BIT			8 +#define RT5677_PWR_SR6_ISO			(0x1 << 7) +#define RT5677_PWR_SR6_ISO_BIT			7 +#define RT5677_PWR_SR5_ISO			(0x1 << 6) +#define RT5677_PWR_SR5_ISO_BIT			6 +#define RT5677_PWR_SR4_ISO			(0x1 << 5) +#define RT5677_PWR_SR4_ISO_BIT			5 +#define RT5677_PWR_SR3_ISO			(0x1 << 4) +#define RT5677_PWR_SR3_ISO_BIT			4 +#define RT5677_PWR_SR2_ISO			(0x1 << 3) +#define RT5677_PWR_SR2_ISO_BIT			3 +#define RT5677_PWR_SR1_ISO			(0x1 << 2) +#define RT5677_PWR_SR1_ISO_BIT			2 +#define RT5677_PWR_SR0_ISO			(0x1 << 1) +#define RT5677_PWR_SR0_ISO_BIT			1 +#define RT5677_PWR_MLT_ISO			(0x1 << 0) +#define RT5677_PWR_MLT_ISO_BIT			0 + +/* I2S1/2/3/4 Audio Serial Data Port Control (0x6f 0x70 0x71 0x72) */ +#define RT5677_I2S_MS_MASK			(0x1 << 15) +#define RT5677_I2S_MS_SFT			15 +#define RT5677_I2S_MS_M				(0x0 << 15) +#define RT5677_I2S_MS_S				(0x1 << 15) +#define RT5677_I2S_O_CP_MASK			(0x3 << 10) +#define RT5677_I2S_O_CP_SFT			10 +#define RT5677_I2S_O_CP_OFF			(0x0 << 10) +#define RT5677_I2S_O_CP_U_LAW			(0x1 << 10) +#define RT5677_I2S_O_CP_A_LAW			(0x2 << 10) +#define RT5677_I2S_I_CP_MASK			(0x3 << 8) +#define RT5677_I2S_I_CP_SFT			8 +#define RT5677_I2S_I_CP_OFF			(0x0 << 8) +#define RT5677_I2S_I_CP_U_LAW			(0x1 << 8) +#define RT5677_I2S_I_CP_A_LAW			(0x2 << 8) +#define RT5677_I2S_BP_MASK			(0x1 << 7) +#define RT5677_I2S_BP_SFT			7 +#define RT5677_I2S_BP_NOR			(0x0 << 7) +#define RT5677_I2S_BP_INV			(0x1 << 7) +#define RT5677_I2S_DL_MASK			(0x3 << 2) +#define RT5677_I2S_DL_SFT			2 +#define RT5677_I2S_DL_16			(0x0 << 2) +#define RT5677_I2S_DL_20			(0x1 << 2) +#define RT5677_I2S_DL_24			(0x2 << 2) +#define RT5677_I2S_DL_8				(0x3 << 2) +#define RT5677_I2S_DF_MASK			(0x3 << 0) +#define RT5677_I2S_DF_SFT			0 +#define RT5677_I2S_DF_I2S			(0x0 << 0) +#define RT5677_I2S_DF_LEFT			(0x1 << 0) +#define RT5677_I2S_DF_PCM_A			(0x2 << 0) +#define RT5677_I2S_DF_PCM_B			(0x3 << 0) + +/* Clock Tree Control 1 (0x73) */ +#define RT5677_I2S_PD1_MASK			(0x7 << 12) +#define RT5677_I2S_PD1_SFT			12 +#define RT5677_I2S_PD1_1			(0x0 << 12) +#define RT5677_I2S_PD1_2			(0x1 << 12) +#define RT5677_I2S_PD1_3			(0x2 << 12) +#define RT5677_I2S_PD1_4			(0x3 << 12) +#define RT5677_I2S_PD1_6			(0x4 << 12) +#define RT5677_I2S_PD1_8			(0x5 << 12) +#define RT5677_I2S_PD1_12			(0x6 << 12) +#define RT5677_I2S_PD1_16			(0x7 << 12) +#define RT5677_I2S_BCLK_MS2_MASK		(0x1 << 11) +#define RT5677_I2S_BCLK_MS2_SFT			11 +#define RT5677_I2S_BCLK_MS2_32			(0x0 << 11) +#define RT5677_I2S_BCLK_MS2_64			(0x1 << 11) +#define RT5677_I2S_PD2_MASK			(0x7 << 8) +#define RT5677_I2S_PD2_SFT			8 +#define RT5677_I2S_PD2_1			(0x0 << 8) +#define RT5677_I2S_PD2_2			(0x1 << 8) +#define RT5677_I2S_PD2_3			(0x2 << 8) +#define RT5677_I2S_PD2_4			(0x3 << 8) +#define RT5677_I2S_PD2_6			(0x4 << 8) +#define RT5677_I2S_PD2_8			(0x5 << 8) +#define RT5677_I2S_PD2_12			(0x6 << 8) +#define RT5677_I2S_PD2_16			(0x7 << 8) +#define RT5677_I2S_BCLK_MS3_MASK		(0x1 << 7) +#define RT5677_I2S_BCLK_MS3_SFT			7 +#define RT5677_I2S_BCLK_MS3_32			(0x0 << 7) +#define RT5677_I2S_BCLK_MS3_64			(0x1 << 7) +#define RT5677_I2S_PD3_MASK			(0x7 << 4) +#define RT5677_I2S_PD3_SFT			4 +#define RT5677_I2S_PD3_1			(0x0 << 4) +#define RT5677_I2S_PD3_2			(0x1 << 4) +#define RT5677_I2S_PD3_3			(0x2 << 4) +#define RT5677_I2S_PD3_4			(0x3 << 4) +#define RT5677_I2S_PD3_6			(0x4 << 4) +#define RT5677_I2S_PD3_8			(0x5 << 4) +#define RT5677_I2S_PD3_12			(0x6 << 4) +#define RT5677_I2S_PD3_16			(0x7 << 4) +#define RT5677_I2S_BCLK_MS4_MASK		(0x1 << 3) +#define RT5677_I2S_BCLK_MS4_SFT			3 +#define RT5677_I2S_BCLK_MS4_32			(0x0 << 3) +#define RT5677_I2S_BCLK_MS4_64			(0x1 << 3) +#define RT5677_I2S_PD4_MASK			(0x7 << 0) +#define RT5677_I2S_PD4_SFT			0 +#define RT5677_I2S_PD4_1			(0x0 << 0) +#define RT5677_I2S_PD4_2			(0x1 << 0) +#define RT5677_I2S_PD4_3			(0x2 << 0) +#define RT5677_I2S_PD4_4			(0x3 << 0) +#define RT5677_I2S_PD4_6			(0x4 << 0) +#define RT5677_I2S_PD4_8			(0x5 << 0) +#define RT5677_I2S_PD4_12			(0x6 << 0) +#define RT5677_I2S_PD4_16			(0x7 << 0) + +/* Clock Tree Control 2 (0x74) */ +#define RT5677_I2S_PD5_MASK			(0x7 << 12) +#define RT5677_I2S_PD5_SFT			12 +#define RT5677_I2S_PD5_1			(0x0 << 12) +#define RT5677_I2S_PD5_2			(0x1 << 12) +#define RT5677_I2S_PD5_3			(0x2 << 12) +#define RT5677_I2S_PD5_4			(0x3 << 12) +#define RT5677_I2S_PD5_6			(0x4 << 12) +#define RT5677_I2S_PD5_8			(0x5 << 12) +#define RT5677_I2S_PD5_12			(0x6 << 12) +#define RT5677_I2S_PD5_16			(0x7 << 12) +#define RT5677_I2S_PD6_MASK			(0x7 << 8) +#define RT5677_I2S_PD6_SFT			8 +#define RT5677_I2S_PD6_1			(0x0 << 8) +#define RT5677_I2S_PD6_2			(0x1 << 8) +#define RT5677_I2S_PD6_3			(0x2 << 8) +#define RT5677_I2S_PD6_4			(0x3 << 8) +#define RT5677_I2S_PD6_6			(0x4 << 8) +#define RT5677_I2S_PD6_8			(0x5 << 8) +#define RT5677_I2S_PD6_12			(0x6 << 8) +#define RT5677_I2S_PD6_16			(0x7 << 8) +#define RT5677_I2S_PD7_MASK			(0x7 << 4) +#define RT5677_I2S_PD7_SFT			4 +#define RT5677_I2S_PD7_1			(0x0 << 4) +#define RT5677_I2S_PD7_2			(0x1 << 4) +#define RT5677_I2S_PD7_3			(0x2 << 4) +#define RT5677_I2S_PD7_4			(0x3 << 4) +#define RT5677_I2S_PD7_6			(0x4 << 4) +#define RT5677_I2S_PD7_8			(0x5 << 4) +#define RT5677_I2S_PD7_12			(0x6 << 4) +#define RT5677_I2S_PD7_16			(0x7 << 4) +#define RT5677_I2S_PD8_MASK			(0x7 << 0) +#define RT5677_I2S_PD8_SFT			0 +#define RT5677_I2S_PD8_1			(0x0 << 0) +#define RT5677_I2S_PD8_2			(0x1 << 0) +#define RT5677_I2S_PD8_3			(0x2 << 0) +#define RT5677_I2S_PD8_4			(0x3 << 0) +#define RT5677_I2S_PD8_6			(0x4 << 0) +#define RT5677_I2S_PD8_8			(0x5 << 0) +#define RT5677_I2S_PD8_12			(0x6 << 0) +#define RT5677_I2S_PD8_16			(0x7 << 0) + +/* Clock Tree Control 3 (0x75) */ +#define RT5677_DSP_ASRC_O_MASK			(0x3 << 6) +#define RT5677_DSP_ASRC_O_SFT			6 +#define RT5677_DSP_ASRC_O_1_0			(0x0 << 6) +#define RT5677_DSP_ASRC_O_1_5			(0x1 << 6) +#define RT5677_DSP_ASRC_O_2_0			(0x2 << 6) +#define RT5677_DSP_ASRC_O_3_0			(0x3 << 6) +#define RT5677_DSP_ASRC_I_MASK			(0x3 << 4) +#define RT5677_DSP_ASRC_I_SFT			4 +#define RT5677_DSP_ASRC_I_1_0			(0x0 << 4) +#define RT5677_DSP_ASRC_I_1_5			(0x1 << 4) +#define RT5677_DSP_ASRC_I_2_0			(0x2 << 4) +#define RT5677_DSP_ASRC_I_3_0			(0x3 << 4) +#define RT5677_DSP_BUS_PD_MASK			(0x7 << 0) +#define RT5677_DSP_BUS_PD_SFT			0 +#define RT5677_DSP_BUS_PD_1			(0x0 << 0) +#define RT5677_DSP_BUS_PD_2			(0x1 << 0) +#define RT5677_DSP_BUS_PD_3			(0x2 << 0) +#define RT5677_DSP_BUS_PD_4			(0x3 << 0) +#define RT5677_DSP_BUS_PD_6			(0x4 << 0) +#define RT5677_DSP_BUS_PD_8			(0x5 << 0) +#define RT5677_DSP_BUS_PD_12			(0x6 << 0) +#define RT5677_DSP_BUS_PD_16			(0x7 << 0) + +#define RT5677_PLL_INP_MAX			40000000 +#define RT5677_PLL_INP_MIN			2048000 +/* PLL M/N/K Code Control 1 (0x7a 0x7c) */ +#define RT5677_PLL_N_MAX			0x1ff +#define RT5677_PLL_N_MASK			(RT5677_PLL_N_MAX << 7) +#define RT5677_PLL_N_SFT			7 +#define RT5677_PLL_K_BP				(0x1 << 5) +#define RT5677_PLL_K_BP_SFT			5 +#define RT5677_PLL_K_MAX			0x1f +#define RT5677_PLL_K_MASK			(RT5677_PLL_K_MAX) +#define RT5677_PLL_K_SFT			0 + +/* PLL M/N/K Code Control 2 (0x7b 0x7d) */ +#define RT5677_PLL_M_MAX			0xf +#define RT5677_PLL_M_MASK			(RT5677_PLL_M_MAX << 12) +#define RT5677_PLL_M_SFT			12 +#define RT5677_PLL_M_BP				(0x1 << 11) +#define RT5677_PLL_M_BP_SFT			11 + +/* Global Clock Control 1 (0x80) */ +#define RT5677_SCLK_SRC_MASK			(0x3 << 14) +#define RT5677_SCLK_SRC_SFT			14 +#define RT5677_SCLK_SRC_MCLK			(0x0 << 14) +#define RT5677_SCLK_SRC_PLL1			(0x1 << 14) +#define RT5677_SCLK_SRC_RCCLK			(0x2 << 14) /* 25MHz */ +#define RT5677_SCLK_SRC_SLIM			(0x3 << 14) +#define RT5677_PLL1_SRC_MASK			(0x7 << 11) +#define RT5677_PLL1_SRC_SFT			11 +#define RT5677_PLL1_SRC_MCLK			(0x0 << 11) +#define RT5677_PLL1_SRC_BCLK1			(0x1 << 11) +#define RT5677_PLL1_SRC_BCLK2			(0x2 << 11) +#define RT5677_PLL1_SRC_BCLK3			(0x3 << 11) +#define RT5677_PLL1_SRC_BCLK4			(0x4 << 11) +#define RT5677_PLL1_SRC_RCCLK			(0x5 << 11) +#define RT5677_PLL1_SRC_SLIM			(0x6 << 11) +#define RT5677_MCLK_SRC_MASK			(0x1 << 10) +#define RT5677_MCLK_SRC_SFT			10 +#define RT5677_MCLK1_SRC			(0x0 << 10) +#define RT5677_MCLK2_SRC			(0x1 << 10) +#define RT5677_PLL1_PD_MASK			(0x1 << 8) +#define RT5677_PLL1_PD_SFT			8 +#define RT5677_PLL1_PD_1			(0x0 << 8) +#define RT5677_PLL1_PD_2			(0x1 << 8) +#define RT5671_DAC_OSR_MASK			(0x3 << 6) +#define RT5671_DAC_OSR_SFT			6 +#define RT5671_DAC_OSR_128			(0x0 << 6) +#define RT5671_DAC_OSR_64			(0x1 << 6) +#define RT5671_DAC_OSR_32			(0x2 << 6) +#define RT5671_ADC_OSR_MASK			(0x3 << 4) +#define RT5671_ADC_OSR_SFT			4 +#define RT5671_ADC_OSR_128			(0x0 << 4) +#define RT5671_ADC_OSR_64			(0x1 << 4) +#define RT5671_ADC_OSR_32			(0x2 << 4) + +/* Global Clock Control 2 (0x81) */ +#define RT5677_PLL2_PR_SRC_MASK			(0x1 << 15) +#define RT5677_PLL2_PR_SRC_SFT			15 +#define RT5677_PLL2_PR_SRC_MCLK1		(0x0 << 15) +#define RT5677_PLL2_PR_SRC_MCLK2		(0x1 << 15) +#define RT5677_PLL2_SRC_MASK			(0x7 << 12) +#define RT5677_PLL2_SRC_SFT			12 +#define RT5677_PLL2_SRC_MCLK			(0x0 << 12) +#define RT5677_PLL2_SRC_BCLK1			(0x1 << 12) +#define RT5677_PLL2_SRC_BCLK2			(0x2 << 12) +#define RT5677_PLL2_SRC_BCLK3			(0x3 << 12) +#define RT5677_PLL2_SRC_BCLK4			(0x4 << 12) +#define RT5677_PLL2_SRC_RCCLK			(0x5 << 12) +#define RT5677_PLL2_SRC_SLIM			(0x6 << 12) +#define RT5671_DSP_ASRC_O_SRC			(0x3 << 10) +#define RT5671_DSP_ASRC_O_SRC_SFT		10 +#define RT5671_DSP_ASRC_O_MCLK			(0x0 << 10) +#define RT5671_DSP_ASRC_O_PLL1			(0x1 << 10) +#define RT5671_DSP_ASRC_O_SLIM			(0x2 << 10) +#define RT5671_DSP_ASRC_O_RCCLK			(0x3 << 10) +#define RT5671_DSP_ASRC_I_SRC			(0x3 << 8) +#define RT5671_DSP_ASRC_I_SRC_SFT		8 +#define RT5671_DSP_ASRC_I_MCLK			(0x0 << 8) +#define RT5671_DSP_ASRC_I_PLL1			(0x1 << 8) +#define RT5671_DSP_ASRC_I_SLIM			(0x2 << 8) +#define RT5671_DSP_ASRC_I_RCCLK			(0x3 << 8) +#define RT5677_DSP_CLK_SRC_MASK			(0x1 << 7) +#define RT5677_DSP_CLK_SRC_SFT			7 +#define RT5677_DSP_CLK_SRC_PLL2			(0x0 << 7) +#define RT5677_DSP_CLK_SRC_BYPASS		(0x1 << 7) + +/* VAD Function Control 4 (0x9f) */ +#define RT5677_VAD_SRC_MASK			(0x7 << 8) +#define RT5677_VAD_SRC_SFT			8 + +/* DSP InBound Control (0xa3) */ +#define RT5677_IB01_SRC_MASK			(0x7 << 12) +#define RT5677_IB01_SRC_SFT			12 +#define RT5677_IB23_SRC_MASK			(0x7 << 8) +#define RT5677_IB23_SRC_SFT			8 +#define RT5677_IB45_SRC_MASK			(0x7 << 4) +#define RT5677_IB45_SRC_SFT			4 +#define RT5677_IB6_SRC_MASK			(0x7 << 0) +#define RT5677_IB6_SRC_SFT			0 + +/* DSP InBound Control (0xa4) */ +#define RT5677_IB7_SRC_MASK			(0x7 << 12) +#define RT5677_IB7_SRC_SFT			12 +#define RT5677_IB8_SRC_MASK			(0x7 << 8) +#define RT5677_IB8_SRC_SFT			8 +#define RT5677_IB9_SRC_MASK			(0x7 << 4) +#define RT5677_IB9_SRC_SFT			4 + +/* DSP In/OutBound Control (0xa5) */ +#define RT5677_SEL_SRC_OB23			(0x1 << 4) +#define RT5677_SEL_SRC_OB23_SFT			4 +#define RT5677_SEL_SRC_OB01			(0x1 << 3) +#define RT5677_SEL_SRC_OB01_SFT			3 +#define RT5677_SEL_SRC_IB45			(0x1 << 2) +#define RT5677_SEL_SRC_IB45_SFT			2 +#define RT5677_SEL_SRC_IB23			(0x1 << 1) +#define RT5677_SEL_SRC_IB23_SFT			1 +#define RT5677_SEL_SRC_IB01			(0x1 << 0) +#define RT5677_SEL_SRC_IB01_SFT			0 + +/* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */ +#define RT5677_DSP_IB_01_H			(0x1 << 15) +#define RT5677_DSP_IB_01_H_SFT			15 +#define RT5677_DSP_IB_23_H			(0x1 << 14) +#define RT5677_DSP_IB_23_H_SFT			14 +#define RT5677_DSP_IB_45_H			(0x1 << 13) +#define RT5677_DSP_IB_45_H_SFT			13 +#define RT5677_DSP_IB_6_H			(0x1 << 12) +#define RT5677_DSP_IB_6_H_SFT			12 +#define RT5677_DSP_IB_7_H			(0x1 << 11) +#define RT5677_DSP_IB_7_H_SFT			11 +#define RT5677_DSP_IB_8_H			(0x1 << 10) +#define RT5677_DSP_IB_8_H_SFT			10 +#define RT5677_DSP_IB_9_H			(0x1 << 9) +#define RT5677_DSP_IB_9_H_SFT			9 +#define RT5677_DSP_IB_01_L			(0x1 << 7) +#define RT5677_DSP_IB_01_L_SFT			7 +#define RT5677_DSP_IB_23_L			(0x1 << 6) +#define RT5677_DSP_IB_23_L_SFT			6 +#define RT5677_DSP_IB_45_L			(0x1 << 5) +#define RT5677_DSP_IB_45_L_SFT			5 +#define RT5677_DSP_IB_6_L			(0x1 << 4) +#define RT5677_DSP_IB_6_L_SFT			4 +#define RT5677_DSP_IB_7_L			(0x1 << 3) +#define RT5677_DSP_IB_7_L_SFT			3 +#define RT5677_DSP_IB_8_L			(0x1 << 2) +#define RT5677_DSP_IB_8_L_SFT			2 +#define RT5677_DSP_IB_9_L			(0x1 << 1) +#define RT5677_DSP_IB_9_L_SFT			1 + +/* Debug String Length */ +#define RT5677_REG_DISP_LEN 23 + +#define RT5677_NO_JACK		BIT(0) +#define RT5677_HEADSET_DET	BIT(1) +#define RT5677_HEADPHO_DET	BIT(2) + +/* System Clock Source */ +enum { +	RT5677_SCLK_S_MCLK, +	RT5677_SCLK_S_PLL1, +	RT5677_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { +	RT5677_PLL1_S_MCLK, +	RT5677_PLL1_S_BCLK1, +	RT5677_PLL1_S_BCLK2, +	RT5677_PLL1_S_BCLK3, +	RT5677_PLL1_S_BCLK4, +}; + +enum { +	RT5677_AIF1, +	RT5677_AIF2, +	RT5677_AIF3, +	RT5677_AIF4, +	RT5677_AIF5, +	RT5677_AIFS, +}; + +struct rt5677_pll_code { +	bool m_bp; /* Indicates bypass m code or not. */ +	bool k_bp; /* Indicates bypass k code or not. */ +	int m_code; +	int n_code; +	int k_code; +}; + +struct rt5677_priv { +	struct snd_soc_codec *codec; +	struct rt5677_platform_data pdata; +	struct regmap *regmap; + +	int sysclk; +	int sysclk_src; +	int lrck[RT5677_AIFS]; +	int bclk[RT5677_AIFS]; +	int master[RT5677_AIFS]; +	int pll_src; +	int pll_in; +	int pll_out; +}; + +#endif /* __RT5677_H__ */ diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 1f4093f3f3a..3d39f0b5b4a 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -36,18 +36,32 @@  /* default value of sgtl5000 registers */  static const struct reg_default sgtl5000_reg_defaults[] = { +	{ SGTL5000_CHIP_DIG_POWER,		0x0000 },  	{ SGTL5000_CHIP_CLK_CTRL,		0x0008 },  	{ SGTL5000_CHIP_I2S_CTRL,		0x0010 },  	{ SGTL5000_CHIP_SSS_CTRL,		0x0010 }, +	{ SGTL5000_CHIP_ADCDAC_CTRL,		0x020c },  	{ SGTL5000_CHIP_DAC_VOL,		0x3c3c },  	{ SGTL5000_CHIP_PAD_STRENGTH,		0x015f }, +	{ SGTL5000_CHIP_ANA_ADC_CTRL,		0x0000 },  	{ SGTL5000_CHIP_ANA_HP_CTRL,		0x1818 },  	{ SGTL5000_CHIP_ANA_CTRL,		0x0111 }, +	{ SGTL5000_CHIP_LINREG_CTRL,		0x0000 }, +	{ SGTL5000_CHIP_REF_CTRL,		0x0000 }, +	{ SGTL5000_CHIP_MIC_CTRL,		0x0000 }, +	{ SGTL5000_CHIP_LINE_OUT_CTRL,		0x0000 },  	{ SGTL5000_CHIP_LINE_OUT_VOL,		0x0404 },  	{ SGTL5000_CHIP_ANA_POWER,		0x7060 },  	{ SGTL5000_CHIP_PLL_CTRL,		0x5000 }, +	{ SGTL5000_CHIP_CLK_TOP_CTRL,		0x0000 }, +	{ SGTL5000_CHIP_ANA_STATUS,		0x0000 }, +	{ SGTL5000_CHIP_SHORT_CTRL,		0x0000 }, +	{ SGTL5000_CHIP_ANA_TEST2,		0x0000 }, +	{ SGTL5000_DAP_CTRL,			0x0000 }, +	{ SGTL5000_DAP_PEQ,			0x0000 },  	{ SGTL5000_DAP_BASS_ENHANCE,		0x0040 },  	{ SGTL5000_DAP_BASS_ENHANCE_CTRL,	0x051f }, +	{ SGTL5000_DAP_AUDIO_EQ,		0x0000 },  	{ SGTL5000_DAP_SURROUND,		0x0040 },  	{ SGTL5000_DAP_EQ_BASS_BAND0,		0x002f },  	{ SGTL5000_DAP_EQ_BASS_BAND1,		0x002f }, @@ -55,6 +69,7 @@ static const struct reg_default sgtl5000_reg_defaults[] = {  	{ SGTL5000_DAP_EQ_BASS_BAND3,		0x002f },  	{ SGTL5000_DAP_EQ_BASS_BAND4,		0x002f },  	{ SGTL5000_DAP_MAIN_CHAN,		0x8000 }, +	{ SGTL5000_DAP_MIX_CHAN,		0x0000 },  	{ SGTL5000_DAP_AVC_CTRL,		0x0510 },  	{ SGTL5000_DAP_AVC_THRESHOLD,		0x1473 },  	{ SGTL5000_DAP_AVC_ATTACK,		0x0028 }, @@ -115,6 +130,7 @@ struct sgtl5000_priv {  	struct ldo_regulator *ldo;  	struct regmap *regmap;  	struct clk *mclk; +	int revision;  };  /* @@ -186,8 +202,9 @@ static const char *adc_mux_text[] = {  	"MIC_IN", "LINE_IN"  }; -static const struct soc_enum adc_enum = -SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 2, 2, adc_mux_text); +static SOC_ENUM_SINGLE_DECL(adc_enum, +			    SGTL5000_CHIP_ANA_CTRL, 2, +			    adc_mux_text);  static const struct snd_kcontrol_new adc_mux =  SOC_DAPM_ENUM("Capture Mux", adc_enum); @@ -197,8 +214,9 @@ static const char *dac_mux_text[] = {  	"DAC", "LINE_IN"  }; -static const struct soc_enum dac_enum = -SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text); +static SOC_ENUM_SINGLE_DECL(dac_enum, +			    SGTL5000_CHIP_ANA_CTRL, 6, +			    dac_mux_text);  static const struct snd_kcontrol_new dac_mux =  SOC_DAPM_ENUM("Headphone Mux", dac_enum); @@ -293,7 +311,7 @@ static int dac_info_volsw(struct snd_kcontrol *kcontrol,  static int dac_get_volsw(struct snd_kcontrol *kcontrol,  			 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	int reg;  	int l;  	int r; @@ -346,7 +364,7 @@ static int dac_get_volsw(struct snd_kcontrol *kcontrol,  static int dac_put_volsw(struct snd_kcontrol *kcontrol,  			 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	int reg;  	int l;  	int r; @@ -1065,71 +1083,11 @@ static int sgtl5000_suspend(struct snd_soc_codec *codec)  	return 0;  } -/* - * restore all sgtl5000 registers, - * since a big hole between dap and regular registers, - * we will restore them respectively. - */ -static int sgtl5000_restore_regs(struct snd_soc_codec *codec) -{ -	u16 *cache = codec->reg_cache; -	u16 reg; - -	/* restore regular registers */ -	for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) { - -		/* These regs should restore in particular order */ -		if (reg == SGTL5000_CHIP_ANA_POWER || -			reg == SGTL5000_CHIP_CLK_CTRL || -			reg == SGTL5000_CHIP_LINREG_CTRL || -			reg == SGTL5000_CHIP_LINE_OUT_CTRL || -			reg == SGTL5000_CHIP_REF_CTRL) -			continue; - -		snd_soc_write(codec, reg, cache[reg]); -	} - -	/* restore dap registers */ -	for (reg = SGTL5000_DAP_REG_OFFSET; reg < SGTL5000_MAX_REG_OFFSET; reg += 2) -		snd_soc_write(codec, reg, cache[reg]); - -	/* -	 * restore these regs according to the power setting sequence in -	 * sgtl5000_set_power_regs() and clock setting sequence in -	 * sgtl5000_set_clock(). -	 * -	 * The order of restore is: -	 * 1. SGTL5000_CHIP_CLK_CTRL MCLK_FREQ bits (1:0) should be restore after -	 *    SGTL5000_CHIP_ANA_POWER PLL bits set -	 * 2. SGTL5000_CHIP_LINREG_CTRL should be set before -	 *    SGTL5000_CHIP_ANA_POWER LINREG_D restored -	 * 3. SGTL5000_CHIP_REF_CTRL controls Analog Ground Voltage, -	 *    prefer to resotre it after SGTL5000_CHIP_ANA_POWER restored -	 */ -	snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, -			cache[SGTL5000_CHIP_LINREG_CTRL]); - -	snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, -			cache[SGTL5000_CHIP_ANA_POWER]); - -	snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, -			cache[SGTL5000_CHIP_CLK_CTRL]); - -	snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL, -			cache[SGTL5000_CHIP_REF_CTRL]); - -	snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL, -			cache[SGTL5000_CHIP_LINE_OUT_CTRL]); -	return 0; -} -  static int sgtl5000_resume(struct snd_soc_codec *codec)  {  	/* Bring the codec back up to standby to enable regulators */  	sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	/* Restore registers by cached in memory */ -	sgtl5000_restore_regs(codec);  	return 0;  }  #else @@ -1285,90 +1243,57 @@ static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)  	sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), -			sgtl5000->supplies); - -	if (ret) { -		ldo_regulator_remove(codec); -		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); -		return ret; -	} -  	dev_info(codec->dev, "Using internal LDO instead of VDDD\n");  	return 0;  }  static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)  { -	int reg;  	int ret; -	int rev;  	int i;  	int external_vddd = 0;  	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); +	struct regulator *vddd;  	for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++)  		sgtl5000->supplies[i].supply = supply_names[i]; -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), -				sgtl5000->supplies); -	if (!ret) -		external_vddd = 1; -	else { +	/* External VDDD only works before revision 0x11 */ +	if (sgtl5000->revision < 0x11) { +		vddd = regulator_get_optional(codec->dev, "VDDD"); +		if (IS_ERR(vddd)) { +			/* See if it's just not registered yet */ +			if (PTR_ERR(vddd) == -EPROBE_DEFER) +				return -EPROBE_DEFER; +		} else { +			external_vddd = 1; +			regulator_put(vddd); +		} +	} + +	if (!external_vddd) {  		ret = sgtl5000_replace_vddd_with_ldo(codec);  		if (ret)  			return ret;  	} +	ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), +				 sgtl5000->supplies); +	if (ret) +		goto err_ldo_remove; +  	ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),  					sgtl5000->supplies);  	if (ret) -		goto err_regulator_free; +		goto err_ldo_remove;  	/* wait for all power rails bring up */  	udelay(10); -	/* -	 * workaround for revision 0x11 and later, -	 * roll back to use internal LDO -	 */ - -	ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, ®); -	if (ret) -		goto err_regulator_disable; - -	rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT; - -	if (external_vddd && rev >= 0x11) { -		/* disable all regulator first */ -		regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), -					sgtl5000->supplies); -		/* free VDDD regulator */ -		regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), -					sgtl5000->supplies); - -		ret = sgtl5000_replace_vddd_with_ldo(codec); -		if (ret) -			return ret; - -		ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), -						sgtl5000->supplies); -		if (ret) -			goto err_regulator_free; - -		/* wait for all power rails bring up */ -		udelay(10); -	} -  	return 0; -err_regulator_disable: -	regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), -				sgtl5000->supplies); -err_regulator_free: -	regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), -				sgtl5000->supplies); -	if (external_vddd) +err_ldo_remove: +	if (!external_vddd)  		ldo_regulator_remove(codec);  	return ret; @@ -1379,14 +1304,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)  	int ret;  	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); -	/* setup i2c data ops */ -	codec->control_data = sgtl5000->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = sgtl5000_enable_regulators(codec);  	if (ret)  		return ret; @@ -1444,8 +1361,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)  err:  	regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),  						sgtl5000->supplies); -	regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), -				sgtl5000->supplies);  	ldo_regulator_remove(codec);  	return ret; @@ -1459,8 +1374,6 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)  	regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),  						sgtl5000->supplies); -	regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), -				sgtl5000->supplies);  	ldo_regulator_remove(codec);  	return 0; @@ -1566,6 +1479,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,  	rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;  	dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); +	sgtl5000->revision = rev;  	i2c_set_clientdata(client, sgtl5000); diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 38f3b105c17..f26befb0c29 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -21,6 +21,7 @@  #include <linux/slab.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> +#include <linux/regmap.h>  #include <sound/soc.h>  #include <sound/initval.h> @@ -60,48 +61,6 @@ enum si476x_pcm_format {  	SI476X_PCM_FORMAT_S24_LE	= 6,  }; -static unsigned int si476x_codec_read(struct snd_soc_codec *codec, -				      unsigned int reg) -{ -	int err; -	unsigned int val; -	struct si476x_core *core = codec->control_data; - -	si476x_core_lock(core); -	if (!si476x_core_is_powered_up(core)) -		regcache_cache_only(core->regmap, true); - -	err = regmap_read(core->regmap, reg, &val); - -	if (!si476x_core_is_powered_up(core)) -		regcache_cache_only(core->regmap, false); -	si476x_core_unlock(core); - -	if (err < 0) -		return err; - -	return val; -} - -static int si476x_codec_write(struct snd_soc_codec *codec, -			      unsigned int reg, unsigned int val) -{ -	int err; -	struct si476x_core *core = codec->control_data; - -	si476x_core_lock(core); -	if (!si476x_core_is_powered_up(core)) -		regcache_cache_only(core->regmap, true); - -	err = regmap_write(core->regmap, reg, val); - -	if (!si476x_core_is_powered_up(core)) -		regcache_cache_only(core->regmap, false); -	si476x_core_unlock(core); - -	return err; -} -  static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = {  SND_SOC_DAPM_OUTPUT("LOUT"),  SND_SOC_DAPM_OUTPUT("ROUT"), @@ -115,6 +74,7 @@ static const struct snd_soc_dapm_route si476x_dapm_routes[] = {  static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,  				    unsigned int fmt)  { +	struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev);  	int err;  	u16 format = 0; @@ -178,9 +138,14 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,  		return -EINVAL;  	} +	si476x_core_lock(core); +  	err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,  				  SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK,  				  format); + +	si476x_core_unlock(core); +  	if (err < 0) {  		dev_err(codec_dai->codec->dev, "Failed to set output format\n");  		return err; @@ -193,6 +158,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,  				  struct snd_pcm_hw_params *params,  				  struct snd_soc_dai *dai)  { +	struct si476x_core *core = i2c_mfd_cell_to_core(dai->dev);  	int rate, width, err;  	rate = params_rate(params); @@ -218,11 +184,13 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,  		return -EINVAL;  	} +	si476x_core_lock(core); +  	err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE,  			    rate);  	if (err < 0) {  		dev_err(dai->codec->dev, "Failed to set sample rate\n"); -		return err; +		goto out;  	}  	err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, @@ -231,16 +199,13 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,  				  (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));  	if (err < 0) {  		dev_err(dai->codec->dev, "Failed to set output width\n"); -		return err; +		goto out;  	} -	return 0; -} +out: +	si476x_core_unlock(core); -static int si476x_codec_probe(struct snd_soc_codec *codec) -{ -	codec->control_data = i2c_mfd_cell_to_core(codec->dev); -	return 0; +	return err;  }  static struct snd_soc_dai_ops si476x_dai_ops = { @@ -266,10 +231,13 @@ static struct snd_soc_dai_driver si476x_dai = {  	.ops		= &si476x_dai_ops,  }; +static struct regmap *si476x_get_regmap(struct device *dev) +{ +	return dev_get_regmap(dev->parent, NULL); +} +  static struct snd_soc_codec_driver soc_codec_dev_si476x = { -	.probe  = si476x_codec_probe, -	.read   = si476x_codec_read, -	.write  = si476x_codec_write, +	.get_regmap = si476x_get_regmap,  	.dapm_widgets = si476x_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),  	.dapm_routes = si476x_dapm_routes, diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c new file mode 100644 index 00000000000..246081aae8c --- /dev/null +++ b/sound/soc/codecs/sigmadsp-i2c.c @@ -0,0 +1,35 @@ +/* + * Load Analog Devices SigmaStudio firmware files + * + * Copyright 2009-2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/i2c.h> +#include <linux/export.h> +#include <linux/module.h> + +#include "sigmadsp.h" + +static int sigma_action_write_i2c(void *control_data, +	const struct sigma_action *sa, size_t len) +{ +	return i2c_master_send(control_data, (const unsigned char *)&sa->addr, +		len); +} + +int process_sigma_firmware(struct i2c_client *client, const char *name) +{ +	struct sigma_firmware ssfw; + +	ssfw.control_data = client; +	ssfw.write = sigma_action_write_i2c; + +	return _process_sigma_firmware(&client->dev, &ssfw, name); +} +EXPORT_SYMBOL(process_sigma_firmware); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c new file mode 100644 index 00000000000..f78ed8d2cfb --- /dev/null +++ b/sound/soc/codecs/sigmadsp-regmap.c @@ -0,0 +1,36 @@ +/* + * Load Analog Devices SigmaStudio firmware files + * + * Copyright 2009-2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/regmap.h> +#include <linux/export.h> +#include <linux/module.h> + +#include "sigmadsp.h" + +static int sigma_action_write_regmap(void *control_data, +	const struct sigma_action *sa, size_t len) +{ +	return regmap_raw_write(control_data, be16_to_cpu(sa->addr), +		sa->payload, len - 2); +} + +int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, +	const char *name) +{ +	struct sigma_firmware ssfw; + +	ssfw.control_data = regmap; +	ssfw.write = sigma_action_write_regmap; + +	return _process_sigma_firmware(dev, &ssfw, name); +} +EXPORT_SYMBOL(process_sigma_firmware_regmap); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 4068f249123..f2de7e049bc 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -34,23 +34,6 @@ enum {  	SIGMA_ACTION_END,  }; -struct sigma_action { -	u8 instr; -	u8 len_hi; -	__le16 len; -	__be16 addr; -	unsigned char payload[]; -} __packed; - -struct sigma_firmware { -	const struct firmware *fw; -	size_t pos; - -	void *control_data; -	int (*write)(void *control_data, const struct sigma_action *sa, -			size_t len); -}; -  static inline u32 sigma_action_len(struct sigma_action *sa)  {  	return (sa->len_hi << 16) | le16_to_cpu(sa->len); @@ -138,7 +121,7 @@ process_sigma_actions(struct sigma_firmware *ssfw)  	return 0;  } -static int _process_sigma_firmware(struct device *dev, +int _process_sigma_firmware(struct device *dev,  	struct sigma_firmware *ssfw, const char *name)  {  	int ret; @@ -197,50 +180,6 @@ static int _process_sigma_firmware(struct device *dev,  	return ret;  } - -#if IS_ENABLED(CONFIG_I2C) - -static int sigma_action_write_i2c(void *control_data, -	const struct sigma_action *sa, size_t len) -{ -	return i2c_master_send(control_data, (const unsigned char *)&sa->addr, -		len); -} - -int process_sigma_firmware(struct i2c_client *client, const char *name) -{ -	struct sigma_firmware ssfw; - -	ssfw.control_data = client; -	ssfw.write = sigma_action_write_i2c; - -	return _process_sigma_firmware(&client->dev, &ssfw, name); -} -EXPORT_SYMBOL(process_sigma_firmware); - -#endif - -#if IS_ENABLED(CONFIG_REGMAP) - -static int sigma_action_write_regmap(void *control_data, -	const struct sigma_action *sa, size_t len) -{ -	return regmap_raw_write(control_data, be16_to_cpu(sa->addr), -		sa->payload, len - 2); -} - -int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, -	const char *name) -{ -	struct sigma_firmware ssfw; - -	ssfw.control_data = regmap; -	ssfw.write = sigma_action_write_regmap; - -	return _process_sigma_firmware(dev, &ssfw, name); -} -EXPORT_SYMBOL(process_sigma_firmware_regmap); - -#endif +EXPORT_SYMBOL_GPL(_process_sigma_firmware);  MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index e439cbd7af7..c47cd23e982 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h @@ -12,6 +12,26 @@  #include <linux/device.h>  #include <linux/regmap.h> +struct sigma_action { +	u8 instr; +	u8 len_hi; +	__le16 len; +	__be16 addr; +	unsigned char payload[]; +} __packed; + +struct sigma_firmware { +	const struct firmware *fw; +	size_t pos; + +	void *control_data; +	int (*write)(void *control_data, const struct sigma_action *sa, +			size_t len); +}; + +int _process_sigma_firmware(struct device *dev, +	struct sigma_firmware *ssfw, const char *name); +  struct i2c_client;  extern int process_sigma_firmware(struct i2c_client *client, const char *name); diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c new file mode 100644 index 00000000000..d90cb0fafcb --- /dev/null +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -0,0 +1,580 @@ +/* + * SiRF audio codec driver + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/soc.h> +#include <sound/dmaengine_pcm.h> + +#include "sirf-audio-codec.h" + +struct sirf_audio_codec { +	struct clk *clk; +	struct regmap *regmap; +	u32 reg_ctrl0, reg_ctrl1; +}; + +static const char * const input_mode_mux[] = {"Single-ended", +	"Differential"}; + +static const struct soc_enum input_mode_mux_enum = +	SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux); + +static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control = +	SOC_DAPM_ENUM("Route", input_mode_mux_enum); + +static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0); +static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0); +static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6, +	0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0), +	0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0), +); + +static struct snd_kcontrol_new volume_controls_atlas6[] = { +	SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14, +			0x7F, 0, playback_vol_tlv), +	SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10, +			0x3F, 0, capture_vol_tlv_atlas6), +}; + +static struct snd_kcontrol_new volume_controls_prima2[] = { +	SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14, +			0x7F, 0, playback_vol_tlv), +	SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10, +			0x1F, 0, capture_vol_tlv_prima2), +}; + +static struct snd_kcontrol_new left_input_path_controls[] = { +	SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0), +	SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0), +}; + +static struct snd_kcontrol_new right_input_path_controls[] = { +	SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0), +	SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0), +}; + +static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control = +	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0); + +static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control = +	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0); + +static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control = +	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0); + +static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control = +	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0); + +static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control = +	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0); + +static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control = +	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0); + +/* After enable adc, Delay 200ms to avoid pop noise */ +static int adc_enable_delay_event(struct snd_soc_dapm_widget *w, +		struct snd_kcontrol *kcontrol, int event) +{ +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		msleep(200); +		break; +	default: +		break; +	} + +	return 0; +} + +static void enable_and_reset_codec(struct regmap *regmap, +		u32 codec_enable_bits, u32 codec_reset_bits) +{ +	regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1, +			codec_enable_bits | codec_reset_bits, +			codec_enable_bits); +	msleep(20); +	regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1, +			codec_reset_bits, codec_reset_bits); +} + +static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, +		struct snd_kcontrol *kcontrol, int event) +{ +#define ATLAS6_CODEC_ENABLE_BITS (1 << 29) +#define ATLAS6_CODEC_RESET_BITS (1 << 28) +	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		enable_and_reset_codec(sirf_audio_codec->regmap, +			ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS); +		break; +	case SND_SOC_DAPM_POST_PMD: +		regmap_update_bits(sirf_audio_codec->regmap, +			AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0); +		break; +	default: +		break; +	} + +	return 0; +} + +static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, +		struct snd_kcontrol *kcontrol, int event) +{ +#define PRIMA2_CODEC_ENABLE_BITS (1 << 27) +#define PRIMA2_CODEC_RESET_BITS (1 << 26) +	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		enable_and_reset_codec(sirf_audio_codec->regmap, +			PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS); +		break; +	case SND_SOC_DAPM_POST_PMD: +		regmap_update_bits(sirf_audio_codec->regmap, +			AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0); +		break; +	default: +		break; +	} + +	return 0; +} + +static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = { +	SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1, +			25, 0, NULL, 0), +	SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1, +			26, 0, NULL, 0), +	SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1, +			27, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = { +	SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1, +			23, 0, NULL, 0), +	SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1, +			24, 0, NULL, 0), +	SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1, +			25, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget = +	SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0, +			atlas6_codec_enable_and_reset_event, +			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); + +static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget = +	SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0, +			prima2_codec_enable_and_reset_event, +			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); + +static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = { +	SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0), +	SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0), +	SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0, +			&left_dac_to_hp_left_amp_switch_control), +	SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0, +			&left_dac_to_hp_right_amp_switch_control), +	SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0, +			&right_dac_to_hp_left_amp_switch_control), +	SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0, +			&right_dac_to_hp_right_amp_switch_control), +	SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0, +			NULL, 0), +	SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0, +			NULL, 0), + +	SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0, +			&left_dac_to_speaker_lineout_switch_control), +	SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0, +			&right_dac_to_speaker_lineout_switch_control), +	SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0, +			NULL, 0), + +	SND_SOC_DAPM_OUTPUT("HPOUTL"), +	SND_SOC_DAPM_OUTPUT("HPOUTR"), +	SND_SOC_DAPM_OUTPUT("SPKOUT"), + +	SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0, +			adc_enable_delay_event, SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0, +			adc_enable_delay_event, SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0, +		&left_input_path_controls[0], +		ARRAY_SIZE(left_input_path_controls)), +	SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0, +		&right_input_path_controls[0], +		ARRAY_SIZE(right_input_path_controls)), + +	SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0, +			&sirf_audio_codec_input_mode_control), +	SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0), +	SND_SOC_DAPM_INPUT("MICIN1"), +	SND_SOC_DAPM_INPUT("MICIN2"), +	SND_SOC_DAPM_INPUT("LINEIN1"), +	SND_SOC_DAPM_INPUT("LINEIN2"), + +	SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0, +			30, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route sirf_audio_codec_map[] = { +	{"SPKOUT", NULL, "Speaker Driver"}, +	{"Speaker Driver", NULL, "Speaker amp driver"}, +	{"Speaker amp driver", NULL, "Left dac to speaker lineout"}, +	{"Speaker amp driver", NULL, "Right dac to speaker lineout"}, +	{"Left dac to speaker lineout", "Switch", "DAC left"}, +	{"Right dac to speaker lineout", "Switch", "DAC right"}, +	{"HPOUTL", NULL, "HP Left Driver"}, +	{"HPOUTR", NULL, "HP Right Driver"}, +	{"HP Left Driver", NULL, "HP amp left driver"}, +	{"HP Right Driver", NULL, "HP amp right driver"}, +	{"HP amp left driver", NULL, "Right dac to hp left amp"}, +	{"HP amp right driver", NULL , "Right dac to hp right amp"}, +	{"HP amp left driver", NULL, "Left dac to hp left amp"}, +	{"HP amp right driver", NULL , "Right dac to hp right amp"}, +	{"Right dac to hp left amp", "Switch", "DAC left"}, +	{"Right dac to hp right amp", "Switch", "DAC right"}, +	{"Left dac to hp left amp", "Switch", "DAC left"}, +	{"Left dac to hp right amp", "Switch", "DAC right"}, +	{"DAC left", NULL, "codecclk"}, +	{"DAC right", NULL, "codecclk"}, +	{"DAC left", NULL, "Playback"}, +	{"DAC right", NULL, "Playback"}, +	{"DAC left", NULL, "HSL Phase Opposite"}, +	{"DAC right", NULL, "HSL Phase Opposite"}, + +	{"Capture", NULL, "ADC left"}, +	{"Capture", NULL, "ADC right"}, +	{"ADC left", NULL, "codecclk"}, +	{"ADC right", NULL, "codecclk"}, +	{"ADC left", NULL, "Left PGA mixer"}, +	{"ADC right", NULL, "Right PGA mixer"}, +	{"Left PGA mixer", "Line Left Switch", "LINEIN2"}, +	{"Right PGA mixer", "Line Right Switch", "LINEIN1"}, +	{"Left PGA mixer", "Mic Left Switch", "MICIN2"}, +	{"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"}, +	{"Mic input mode mux", "Single-ended", "MICIN1"}, +	{"Mic input mode mux", "Differential", "MICIN1"}, +}; + +static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec) +{ +	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, +		AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); +	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, +		AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET); +	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0); +	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); +	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, +		AUDIO_FIFO_START, AUDIO_FIFO_START); +	regmap_update_bits(sirf_audio_codec->regmap, +		AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE); +} + +static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec) +{ +	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); +	regmap_update_bits(sirf_audio_codec->regmap, +		AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE); +} + +static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec, +	int channels) +{ +	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, +		AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); +	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, +		AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET); +	regmap_write(sirf_audio_codec->regmap, +		AUDIO_PORT_IC_RXFIFO_INT_MSK, 0); +	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0); +	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, +		AUDIO_FIFO_START, AUDIO_FIFO_START); +	if (channels == 1) +		regmap_update_bits(sirf_audio_codec->regmap, +			AUDIO_PORT_IC_CODEC_RX_CTRL, +			IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO); +	else +		regmap_update_bits(sirf_audio_codec->regmap, +			AUDIO_PORT_IC_CODEC_RX_CTRL, +			IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO); +} + +static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec) +{ +	regmap_update_bits(sirf_audio_codec->regmap, +			AUDIO_PORT_IC_CODEC_RX_CTRL, +			IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO); +} + +static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, +		int cmd, +		struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); +	int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + +	/* +	 * This is a workaround, When stop playback, +	 * need disable HP amp, avoid the current noise. +	 */ +	switch (cmd) { +	case SNDRV_PCM_TRIGGER_STOP: +	case SNDRV_PCM_TRIGGER_SUSPEND: +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +		if (playback) { +			snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, +				IC_HSLEN | IC_HSREN, 0); +			sirf_audio_codec_tx_disable(sirf_audio_codec); +		} else +			sirf_audio_codec_rx_disable(sirf_audio_codec); +		break; +	case SNDRV_PCM_TRIGGER_START: +	case SNDRV_PCM_TRIGGER_RESUME: +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +		if (playback) { +			sirf_audio_codec_tx_enable(sirf_audio_codec); +			snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, +				IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN); +		} else +			sirf_audio_codec_rx_enable(sirf_audio_codec, +				substream->runtime->channels); +		break; +	default: +		return -EINVAL; +	} + +	return 0; +} + +struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { +	.trigger = sirf_audio_codec_trigger, +}; + +struct snd_soc_dai_driver sirf_audio_codec_dai = { +	.name = "sirf-audio-codec", +	.playback = { +		.stream_name = "Playback", +		.channels_min = 2, +		.channels_max = 2, +		.rates = SNDRV_PCM_RATE_48000, +		.formats = SNDRV_PCM_FMTBIT_S16_LE, +	}, +	.capture = { +		.stream_name = "Capture", +		.channels_min = 1, +		.channels_max = 2, +		.rates = SNDRV_PCM_RATE_48000, +		.formats = SNDRV_PCM_FMTBIT_S16_LE, +	}, +	.ops = &sirf_audio_codec_dai_ops, +}; + +static int sirf_audio_codec_probe(struct snd_soc_codec *codec) +{ +	struct snd_soc_dapm_context *dapm = &codec->dapm; + +	pm_runtime_enable(codec->dev); + +	if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) { +		snd_soc_dapm_new_controls(dapm, +			prima2_output_driver_dapm_widgets, +			ARRAY_SIZE(prima2_output_driver_dapm_widgets)); +		snd_soc_dapm_new_controls(dapm, +			&prima2_codec_clock_dapm_widget, 1); +		return snd_soc_add_codec_controls(codec, +			volume_controls_prima2, +			ARRAY_SIZE(volume_controls_prima2)); +	} +	if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) { +		snd_soc_dapm_new_controls(dapm, +			atlas6_output_driver_dapm_widgets, +			ARRAY_SIZE(atlas6_output_driver_dapm_widgets)); +		snd_soc_dapm_new_controls(dapm, +			&atlas6_codec_clock_dapm_widget, 1); +		return snd_soc_add_codec_controls(codec, +			volume_controls_atlas6, +			ARRAY_SIZE(volume_controls_atlas6)); +	} + +	return -EINVAL; +} + +static int sirf_audio_codec_remove(struct snd_soc_codec *codec) +{ +	pm_runtime_disable(codec->dev); +	return 0; +} + +static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = { +	.probe = sirf_audio_codec_probe, +	.remove = sirf_audio_codec_remove, +	.dapm_widgets = sirf_audio_codec_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets), +	.dapm_routes = sirf_audio_codec_map, +	.num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map), +	.idle_bias_off = true, +}; + +static const struct of_device_id sirf_audio_codec_of_match[] = { +	{ .compatible = "sirf,prima2-audio-codec" }, +	{ .compatible = "sirf,atlas6-audio-codec" }, +	{} +}; +MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match); + +static const struct regmap_config sirf_audio_codec_regmap_config = { +	.reg_bits = 32, +	.reg_stride = 4, +	.val_bits = 32, +	.max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK, +	.cache_type = REGCACHE_NONE, +}; + +static int sirf_audio_codec_driver_probe(struct platform_device *pdev) +{ +	int ret; +	struct sirf_audio_codec *sirf_audio_codec; +	void __iomem *base; +	struct resource *mem_res; +	const struct of_device_id *match; + +	match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node); + +	sirf_audio_codec = devm_kzalloc(&pdev->dev, +		sizeof(struct sirf_audio_codec), GFP_KERNEL); +	if (!sirf_audio_codec) +		return -ENOMEM; + +	platform_set_drvdata(pdev, sirf_audio_codec); + +	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	base = devm_ioremap_resource(&pdev->dev, mem_res); +	if (base == NULL) +		return -ENOMEM; + +	sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base, +					    &sirf_audio_codec_regmap_config); +	if (IS_ERR(sirf_audio_codec->regmap)) +		return PTR_ERR(sirf_audio_codec->regmap); + +	sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(sirf_audio_codec->clk)) { +		dev_err(&pdev->dev, "Get clock failed.\n"); +		return PTR_ERR(sirf_audio_codec->clk); +	} + +	ret = clk_prepare_enable(sirf_audio_codec->clk); +	if (ret) { +		dev_err(&pdev->dev, "Enable clock failed.\n"); +		return ret; +	} + +	ret = snd_soc_register_codec(&(pdev->dev), +			&soc_codec_device_sirf_audio_codec, +			&sirf_audio_codec_dai, 1); +	if (ret) { +		dev_err(&pdev->dev, "Register Audio Codec dai failed.\n"); +		goto err_clk_put; +	} + +	/* +	 * Always open charge pump, if not, when the charge pump closed the +	 * adc will not stable +	 */ +	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, +		IC_CPFREQ, IC_CPFREQ); + +	if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec")) +		regmap_update_bits(sirf_audio_codec->regmap, +				AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN); +	return 0; + +err_clk_put: +	clk_disable_unprepare(sirf_audio_codec->clk); +	return ret; +} + +static int sirf_audio_codec_driver_remove(struct platform_device *pdev) +{ +	struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev); + +	clk_disable_unprepare(sirf_audio_codec->clk); +	snd_soc_unregister_codec(&(pdev->dev)); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int sirf_audio_codec_suspend(struct device *dev) +{ +	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev); + +	regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, +		&sirf_audio_codec->reg_ctrl0); +	regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1, +		&sirf_audio_codec->reg_ctrl1); +	clk_disable_unprepare(sirf_audio_codec->clk); + +	return 0; +} + +static int sirf_audio_codec_resume(struct device *dev) +{ +	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev); +	int ret; + +	ret = clk_prepare_enable(sirf_audio_codec->clk); +	if (ret) +		return ret; + +	regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, +		sirf_audio_codec->reg_ctrl0); +	regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1, +		sirf_audio_codec->reg_ctrl1); + +	return 0; +} +#endif + +static const struct dev_pm_ops sirf_audio_codec_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume) +}; + +static struct platform_driver sirf_audio_codec_driver = { +	.driver = { +		.name = "sirf-audio-codec", +		.owner = THIS_MODULE, +		.of_match_table = sirf_audio_codec_of_match, +		.pm = &sirf_audio_codec_pm_ops, +	}, +	.probe = sirf_audio_codec_driver_probe, +	.remove = sirf_audio_codec_driver_remove, +}; + +module_platform_driver(sirf_audio_codec_driver); + +MODULE_DESCRIPTION("SiRF audio codec driver"); +MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h new file mode 100644 index 00000000000..ba1adc03839 --- /dev/null +++ b/sound/soc/codecs/sirf-audio-codec.h @@ -0,0 +1,125 @@ +/* + * SiRF inner codec controllers define + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef _SIRF_AUDIO_CODEC_H +#define _SIRF_AUDIO_CODEC_H + + +#define AUDIO_IC_CODEC_PWR			(0x00E0) +#define AUDIO_IC_CODEC_CTRL0			(0x00E4) +#define AUDIO_IC_CODEC_CTRL1			(0x00E8) +#define AUDIO_IC_CODEC_CTRL2			(0x00EC) +#define AUDIO_IC_CODEC_CTRL3			(0x00F0) + +#define MICBIASEN		(1 << 3) + +#define IC_RDACEN		(1 << 0) +#define IC_LDACEN		(1 << 1) +#define IC_HSREN		(1 << 2) +#define IC_HSLEN		(1 << 3) +#define IC_SPEN			(1 << 4) +#define IC_CPEN			(1 << 5) + +#define IC_HPRSELR		(1 << 6) +#define IC_HPLSELR		(1 << 7) +#define IC_HPRSELL		(1 << 8) +#define IC_HPLSELL		(1 << 9) +#define IC_SPSELR		(1 << 10) +#define IC_SPSELL		(1 << 11) + +#define IC_MONOR		(1 << 12) +#define IC_MONOL		(1 << 13) + +#define IC_RXOSRSEL		(1 << 28) +#define IC_CPFREQ		(1 << 29) +#define IC_HSINVEN		(1 << 30) + +#define IC_MICINREN		(1 << 0) +#define IC_MICINLEN		(1 << 1) +#define IC_MICIN1SEL		(1 << 2) +#define IC_MICIN2SEL		(1 << 3) +#define IC_MICDIFSEL		(1 << 4) +#define	IC_LINEIN1SEL		(1 << 5) +#define	IC_LINEIN2SEL		(1 << 6) +#define	IC_RADCEN		(1 << 7) +#define	IC_LADCEN		(1 << 8) +#define	IC_ALM			(1 << 9) + +#define IC_DIGMICEN             (1 << 22) +#define IC_DIGMICFREQ           (1 << 23) +#define IC_ADC14B_12            (1 << 24) +#define IC_FIRDAC_HSL_EN        (1 << 25) +#define IC_FIRDAC_HSR_EN        (1 << 26) +#define IC_FIRDAC_LOUT_EN       (1 << 27) +#define IC_POR                  (1 << 28) +#define IC_CODEC_CLK_EN         (1 << 29) +#define IC_HP_3DB_BOOST         (1 << 30) + +#define IC_ADC_LEFT_GAIN_SHIFT	16 +#define IC_ADC_RIGHT_GAIN_SHIFT 10 +#define IC_ADC_GAIN_MASK	0x3F +#define IC_MIC_MAX_GAIN		0x39 + +#define IC_RXPGAR_MASK		0x3F +#define IC_RXPGAR_SHIFT		14 +#define IC_RXPGAL_MASK		0x3F +#define IC_RXPGAL_SHIFT		21 +#define IC_RXPGAR		0x7B +#define IC_RXPGAL		0x7B + +#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK     0x3F +#define AUDIO_PORT_TX_FIFO_SC_OFFSET    0 +#define AUDIO_PORT_TX_FIFO_LC_OFFSET    10 +#define AUDIO_PORT_TX_FIFO_HC_OFFSET    20 + +#define TX_FIFO_SC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ +				<< AUDIO_PORT_TX_FIFO_SC_OFFSET) +#define TX_FIFO_LC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ +				<< AUDIO_PORT_TX_FIFO_LC_OFFSET) +#define TX_FIFO_HC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ +				<< AUDIO_PORT_TX_FIFO_HC_OFFSET) + +#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK     0x0F +#define AUDIO_PORT_RX_FIFO_SC_OFFSET    0 +#define AUDIO_PORT_RX_FIFO_LC_OFFSET    10 +#define AUDIO_PORT_RX_FIFO_HC_OFFSET    20 + +#define RX_FIFO_SC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ +				<< AUDIO_PORT_RX_FIFO_SC_OFFSET) +#define RX_FIFO_LC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ +				<< AUDIO_PORT_RX_FIFO_LC_OFFSET) +#define RX_FIFO_HC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ +				<< AUDIO_PORT_RX_FIFO_HC_OFFSET) +#define AUDIO_PORT_IC_CODEC_TX_CTRL		(0x00F4) +#define AUDIO_PORT_IC_CODEC_RX_CTRL		(0x00F8) + +#define AUDIO_PORT_IC_TXFIFO_OP			(0x00FC) +#define AUDIO_PORT_IC_TXFIFO_LEV_CHK		(0x0100) +#define AUDIO_PORT_IC_TXFIFO_STS		(0x0104) +#define AUDIO_PORT_IC_TXFIFO_INT		(0x0108) +#define AUDIO_PORT_IC_TXFIFO_INT_MSK		(0x010C) + +#define AUDIO_PORT_IC_RXFIFO_OP			(0x0110) +#define AUDIO_PORT_IC_RXFIFO_LEV_CHK		(0x0114) +#define AUDIO_PORT_IC_RXFIFO_STS		(0x0118) +#define AUDIO_PORT_IC_RXFIFO_INT		(0x011C) +#define AUDIO_PORT_IC_RXFIFO_INT_MSK		(0x0120) + +#define AUDIO_FIFO_START		(1 << 0) +#define AUDIO_FIFO_RESET		(1 << 1) + +#define AUDIO_FIFO_FULL			(1 << 0) +#define AUDIO_FIFO_EMPTY		(1 << 1) +#define AUDIO_FIFO_OFLOW		(1 << 2) +#define AUDIO_FIFO_UFLOW		(1 << 3) + +#define IC_TX_ENABLE		(0x03) +#define IC_RX_ENABLE_MONO	(0x01) +#define IC_RX_ENABLE_STEREO	(0x03) + +#endif /*__SIRF_AUDIO_CODEC_H*/ diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index dba26e63844..42dff26b3a2 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -164,30 +164,28 @@ static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)  }  /*end - adc helper functions */ -static inline unsigned int sn95031_read(struct snd_soc_codec *codec, -			unsigned int reg) +static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val)  {  	u8 value = 0;  	int ret;  	ret = intel_scu_ipc_ioread8(reg, &value); -	if (ret) -		pr_err("read of %x failed, err %d\n", reg, ret); -	return value; +	if (ret == 0) +		*val = value; +	return ret;  } -static inline int sn95031_write(struct snd_soc_codec *codec, -			unsigned int reg, unsigned int value) +static int sn95031_write(void *ctx, unsigned int reg, unsigned int value)  { -	int ret; - -	ret = intel_scu_ipc_iowrite8(reg, value); -	if (ret) -		pr_err("write of %x failed, err %d\n", reg, ret); -	return ret; +	return intel_scu_ipc_iowrite8(reg, value);  } +static const struct regmap_config sn95031_regmap = { +	.reg_read = sn95031_read, +	.reg_write = sn95031_write, +}; +  static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,  		enum snd_soc_bias_level level)  { @@ -314,14 +312,14 @@ static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,  /* mux controls */  static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" }; -static const struct soc_enum sn95031_micl_enum = -	SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 1, 2, sn95031_mic_texts); +static SOC_ENUM_SINGLE_DECL(sn95031_micl_enum, +			    SN95031_ADCCONFIG, 1, sn95031_mic_texts);  static const struct snd_kcontrol_new sn95031_micl_mux_control =  	SOC_DAPM_ENUM("Route", sn95031_micl_enum); -static const struct soc_enum sn95031_micr_enum = -	SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 3, 2, sn95031_mic_texts); +static SOC_ENUM_SINGLE_DECL(sn95031_micr_enum, +			    SN95031_ADCCONFIG, 3, sn95031_mic_texts);  static const struct snd_kcontrol_new sn95031_micr_mux_control =  	SOC_DAPM_ENUM("Route", sn95031_micr_enum); @@ -330,26 +328,26 @@ static const char *sn95031_input_texts[] = {	"DMIC1", "DMIC2", "DMIC3",  						"DMIC4", "DMIC5", "DMIC6",  						"ADC Left", "ADC Right" }; -static const struct soc_enum sn95031_input1_enum = -	SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 0, 8, sn95031_input_texts); +static SOC_ENUM_SINGLE_DECL(sn95031_input1_enum, +			    SN95031_AUDIOMUX12, 0, sn95031_input_texts);  static const struct snd_kcontrol_new sn95031_input1_mux_control =  	SOC_DAPM_ENUM("Route", sn95031_input1_enum); -static const struct soc_enum sn95031_input2_enum = -	SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 4, 8, sn95031_input_texts); +static SOC_ENUM_SINGLE_DECL(sn95031_input2_enum, +			    SN95031_AUDIOMUX12, 4, sn95031_input_texts);  static const struct snd_kcontrol_new sn95031_input2_mux_control =  	SOC_DAPM_ENUM("Route", sn95031_input2_enum); -static const struct soc_enum sn95031_input3_enum = -	SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 0, 8, sn95031_input_texts); +static SOC_ENUM_SINGLE_DECL(sn95031_input3_enum, +			    SN95031_AUDIOMUX34, 0, sn95031_input_texts);  static const struct snd_kcontrol_new sn95031_input3_mux_control =  	SOC_DAPM_ENUM("Route", sn95031_input3_enum); -static const struct soc_enum sn95031_input4_enum = -	SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 4, 8, sn95031_input_texts); +static SOC_ENUM_SINGLE_DECL(sn95031_input4_enum, +			    SN95031_AUDIOMUX34, 4, sn95031_input_texts);  static const struct snd_kcontrol_new sn95031_input4_mux_control =  	SOC_DAPM_ENUM("Route", sn95031_input4_enum); @@ -361,19 +359,19 @@ static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"};  /* 0dB to 30dB in 10dB steps */  static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0); -static const struct soc_enum sn95031_micmode1_enum = -	SOC_ENUM_SINGLE(SN95031_MICAMP1, 1, 2, sn95031_micmode_text); -static const struct soc_enum sn95031_micmode2_enum = -	SOC_ENUM_SINGLE(SN95031_MICAMP2, 1, 2, sn95031_micmode_text); +static SOC_ENUM_SINGLE_DECL(sn95031_micmode1_enum, +			    SN95031_MICAMP1, 1, sn95031_micmode_text); +static SOC_ENUM_SINGLE_DECL(sn95031_micmode2_enum, +			    SN95031_MICAMP2, 1, sn95031_micmode_text);  static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"}; -static const struct soc_enum sn95031_dmic12_cfg_enum = -	SOC_ENUM_SINGLE(SN95031_DMICMUX, 0, 2, sn95031_dmic_cfg_text); -static const struct soc_enum sn95031_dmic34_cfg_enum = -	SOC_ENUM_SINGLE(SN95031_DMICMUX, 1, 2, sn95031_dmic_cfg_text); -static const struct soc_enum sn95031_dmic56_cfg_enum = -	SOC_ENUM_SINGLE(SN95031_DMICMUX, 2, 2, sn95031_dmic_cfg_text); +static SOC_ENUM_SINGLE_DECL(sn95031_dmic12_cfg_enum, +			    SN95031_DMICMUX, 0, sn95031_dmic_cfg_text); +static SOC_ENUM_SINGLE_DECL(sn95031_dmic34_cfg_enum, +			    SN95031_DMICMUX, 1, sn95031_dmic_cfg_text); +static SOC_ENUM_SINGLE_DECL(sn95031_dmic56_cfg_enum, +			    SN95031_DMICMUX, 2, sn95031_dmic_cfg_text);  static const struct snd_kcontrol_new sn95031_snd_controls[] = {  	SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum), @@ -886,8 +884,6 @@ static int sn95031_codec_remove(struct snd_soc_codec *codec)  static struct snd_soc_codec_driver sn95031_codec = {  	.probe		= sn95031_codec_probe,  	.remove		= sn95031_codec_remove, -	.read		= sn95031_read, -	.write		= sn95031_write,  	.set_bias_level	= sn95031_set_vaud_bias,  	.idle_bias_off	= true,  	.dapm_widgets	= sn95031_dapm_widgets, @@ -898,7 +894,14 @@ static struct snd_soc_codec_driver sn95031_codec = {  static int sn95031_device_probe(struct platform_device *pdev)  { +	struct regmap *regmap; +  	pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev)); + +	regmap = devm_regmap_init(&pdev->dev, NULL, NULL, &sn95031_regmap); +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); +  	return snd_soc_register_codec(&pdev->dev, &sn95031_codec,  			sn95031_dais, ARRAY_SIZE(sn95031_dais));  } diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 95aed552139..56adb3e2def 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -169,19 +169,19 @@ static const char * const ssm2518_drc_hold_time_text[] = {  	"682.24 ms", "1364 ms",  }; -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum,  	SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum,  	SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum,  	SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum,  	SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum,  	SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum,  	SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum,  	SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text);  static const struct snd_kcontrol_new ssm2518_snd_controls[] = { @@ -549,13 +549,13 @@ static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,  		right_slot = 0;  	} else {  		/* We assume the left channel < right channel */ -		left_slot = ffs(tx_mask); -		tx_mask &= ~(1 << tx_mask); +		left_slot = __ffs(tx_mask); +		tx_mask &= ~(1 << left_slot);  		if (tx_mask == 0) {  			right_slot = left_slot;  		} else { -			right_slot = ffs(tx_mask); -			tx_mask &= ~(1 << tx_mask); +			right_slot = __ffs(tx_mask); +			tx_mask &= ~(1 << right_slot);  		}  	} @@ -648,16 +648,6 @@ static struct snd_soc_dai_driver ssm2518_dai = {  static int ssm2518_probe(struct snd_soc_codec *codec)  { -	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = ssm2518->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);  } diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c new file mode 100644 index 00000000000..abd63d53717 --- /dev/null +++ b/sound/soc/codecs/ssm2602-i2c.c @@ -0,0 +1,57 @@ +/* + * SSM2602/SSM2603/SSM2604 I2C audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "ssm2602.h" + +/* + * ssm2602 2 wire address is determined by GPIO5 + * state during powerup. + *    low  = 0x1a + *    high = 0x1b + */ +static int ssm2602_i2c_probe(struct i2c_client *client, +			     const struct i2c_device_id *id) +{ +	return ssm2602_probe(&client->dev, id->driver_data, +		devm_regmap_init_i2c(client, &ssm2602_regmap_config)); +} + +static int ssm2602_i2c_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static const struct i2c_device_id ssm2602_i2c_id[] = { +	{ "ssm2602", SSM2602 }, +	{ "ssm2603", SSM2602 }, +	{ "ssm2604", SSM2604 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); + +static struct i2c_driver ssm2602_i2c_driver = { +	.driver = { +		.name = "ssm2602", +		.owner = THIS_MODULE, +	}, +	.probe = ssm2602_i2c_probe, +	.remove = ssm2602_i2c_remove, +	.id_table = ssm2602_i2c_id, +}; +module_i2c_driver(ssm2602_i2c_driver); + +MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 I2C driver"); +MODULE_AUTHOR("Cliff Cai"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c new file mode 100644 index 00000000000..2bf55e24a7b --- /dev/null +++ b/sound/soc/codecs/ssm2602-spi.c @@ -0,0 +1,41 @@ +/* + * SSM2602 SPI audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "ssm2602.h" + +static int ssm2602_spi_probe(struct spi_device *spi) +{ +	return ssm2602_probe(&spi->dev, SSM2602, +		devm_regmap_init_spi(spi, &ssm2602_regmap_config)); +} + +static int ssm2602_spi_remove(struct spi_device *spi) +{ +	snd_soc_unregister_codec(&spi->dev); +	return 0; +} + +static struct spi_driver ssm2602_spi_driver = { +	.driver = { +		.name	= "ssm2602", +		.owner	= THIS_MODULE, +	}, +	.probe		= ssm2602_spi_probe, +	.remove		= ssm2602_spi_remove, +}; +module_spi_driver(ssm2602_spi_driver); + +MODULE_DESCRIPTION("ASoC SSM2602 SPI driver"); +MODULE_AUTHOR("Cliff Cai"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 492644e67ac..97b0454eb34 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -27,34 +27,20 @@   */  #include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/i2c.h> -#include <linux/spi/spi.h>  #include <linux/regmap.h>  #include <linux/slab.h> -#include <sound/core.h> +  #include <sound/pcm.h>  #include <sound/pcm_params.h>  #include <sound/soc.h> -#include <sound/initval.h>  #include <sound/tlv.h>  #include "ssm2602.h" -enum ssm2602_type { -	SSM2602, -	SSM2604, -}; -  /* codec private data */  struct ssm2602_priv {  	unsigned int sysclk; -	struct snd_pcm_hw_constraint_list *sysclk_constraints; -	struct snd_pcm_substream *master_substream; -	struct snd_pcm_substream *slave_substream; +	const struct snd_pcm_hw_constraint_list *sysclk_constraints;  	struct regmap *regmap; @@ -77,15 +63,16 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {  /*Appending several "None"s just for OSS mixer use*/  static const char *ssm2602_input_select[] = { -	"Line", "Mic", "None", "None", "None", -	"None", "None", "None", +	"Line", "Mic",  };  static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};  static const struct soc_enum ssm2602_enum[] = { -	SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select), -	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), +	SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select), +			ssm2602_input_select), +	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph), +			ssm2602_deemph),  };  static const unsigned int ssm260x_outmix_tlv[] = { @@ -196,10 +183,10 @@ static const struct snd_soc_dapm_route ssm2604_routes[] = {  };  static const unsigned int ssm2602_rates_12288000[] = { -	8000, 32000, 48000, 96000, +	8000, 16000, 32000, 48000, 96000,  }; -static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = { +static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {  	.list = ssm2602_rates_12288000,  	.count = ARRAY_SIZE(ssm2602_rates_12288000),  }; @@ -208,7 +195,7 @@ static const unsigned int ssm2602_rates_11289600[] = {  	8000, 44100, 88200,  }; -static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { +static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {  	.list = ssm2602_rates_11289600,  	.count = ARRAY_SIZE(ssm2602_rates_11289600),  }; @@ -233,6 +220,11 @@ static const struct ssm2602_coeff ssm2602_coeff_table[] = {  	{18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},  	{12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)}, +	/* 16k */ +	{12288000, 16000, SSM2602_COEFF_SRATE(0x5, 0x0, 0x0)}, +	{18432000, 16000, SSM2602_COEFF_SRATE(0x5, 0x1, 0x0)}, +	{12000000, 16000, SSM2602_COEFF_SRATE(0xa, 0x0, 0x1)}, +  	/* 8k */  	{12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},  	{18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)}, @@ -277,11 +269,6 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,  	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));  	unsigned int iface; -	if (substream == ssm2602->slave_substream) { -		dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n"); -		return 0; -	} -  	if (srate < 0)  		return srate; @@ -314,33 +301,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,  {  	struct snd_soc_codec *codec = dai->codec;  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); -	struct snd_pcm_runtime *master_runtime; - -	/* The DAI has shared clocks so if we already have a playback or -	 * capture going then constrain this substream to match it. -	 * TODO: the ssm2602 allows pairs of non-matching PB/REC rates -	 */ -	if (ssm2602->master_substream) { -		master_runtime = ssm2602->master_substream->runtime; -		dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n", -			master_runtime->sample_bits, -			master_runtime->rate); - -		if (master_runtime->rate != 0) -			snd_pcm_hw_constraint_minmax(substream->runtime, -						     SNDRV_PCM_HW_PARAM_RATE, -						     master_runtime->rate, -						     master_runtime->rate); - -		if (master_runtime->sample_bits != 0) -			snd_pcm_hw_constraint_minmax(substream->runtime, -						     SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -						     master_runtime->sample_bits, -						     master_runtime->sample_bits); - -		ssm2602->slave_substream = substream; -	} else -		ssm2602->master_substream = substream;  	if (ssm2602->sysclk_constraints) {  		snd_pcm_hw_constraint_list(substream->runtime, 0, @@ -351,19 +311,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,  	return 0;  } -static void ssm2602_shutdown(struct snd_pcm_substream *substream, -			     struct snd_soc_dai *dai) -{ -	struct snd_soc_codec *codec = dai->codec; -	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); - -	if (ssm2602->master_substream == substream) -		ssm2602->master_substream = ssm2602->slave_substream; - -	ssm2602->slave_substream = NULL; -} - -  static int ssm2602_mute(struct snd_soc_dai *dai, int mute)  {  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec); @@ -520,9 +467,10 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,  	return 0;  } -#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\ -		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ -		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) +#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ +		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ +		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ +		SNDRV_PCM_RATE_96000)  #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\  		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -530,7 +478,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,  static const struct snd_soc_dai_ops ssm2602_dai_ops = {  	.startup	= ssm2602_startup,  	.hw_params	= ssm2602_hw_params, -	.shutdown	= ssm2602_shutdown,  	.digital_mute	= ssm2602_mute,  	.set_sysclk	= ssm2602_set_dai_sysclk,  	.set_fmt	= ssm2602_set_dai_fmt, @@ -551,6 +498,8 @@ static struct snd_soc_dai_driver ssm2602_dai = {  		.rates = SSM2602_RATES,  		.formats = SSM2602_FORMATS,},  	.ops = &ssm2602_dai_ops, +	.symmetric_rates = 1, +	.symmetric_samplebits = 1,  };  static int ssm2602_suspend(struct snd_soc_codec *codec) @@ -569,7 +518,7 @@ static int ssm2602_resume(struct snd_soc_codec *codec)  	return 0;  } -static int ssm2602_probe(struct snd_soc_codec *codec) +static int ssm2602_codec_probe(struct snd_soc_codec *codec)  {  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);  	struct snd_soc_dapm_context *dapm = &codec->dapm; @@ -594,7 +543,7 @@ static int ssm2602_probe(struct snd_soc_codec *codec)  			ARRAY_SIZE(ssm2602_routes));  } -static int ssm2604_probe(struct snd_soc_codec *codec) +static int ssm2604_codec_probe(struct snd_soc_codec *codec)  {  	struct snd_soc_dapm_context *dapm = &codec->dapm;  	int ret; @@ -608,18 +557,11 @@ static int ssm2604_probe(struct snd_soc_codec *codec)  			ARRAY_SIZE(ssm2604_routes));  } -static int ssm260x_probe(struct snd_soc_codec *codec) +static int ssm260x_codec_probe(struct snd_soc_codec *codec)  {  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);  	int ret; -	codec->control_data = ssm2602->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset: %d\n", ret); @@ -637,10 +579,10 @@ static int ssm260x_probe(struct snd_soc_codec *codec)  	switch (ssm2602->type) {  	case SSM2602: -		ret = ssm2602_probe(codec); +		ret = ssm2602_codec_probe(codec);  		break;  	case SSM2604: -		ret = ssm2604_probe(codec); +		ret = ssm2604_codec_probe(codec);  		break;  	} @@ -660,7 +602,7 @@ static int ssm2602_remove(struct snd_soc_codec *codec)  }  static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { -	.probe =	ssm260x_probe, +	.probe =	ssm260x_codec_probe,  	.remove =	ssm2602_remove,  	.suspend =	ssm2602_suspend,  	.resume =	ssm2602_resume, @@ -679,7 +621,7 @@ static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)  	return reg == SSM2602_RESET;  } -static const struct regmap_config ssm2602_regmap_config = { +const struct regmap_config ssm2602_regmap_config = {  	.val_bits = 9,  	.reg_bits = 7, @@ -690,134 +632,28 @@ static const struct regmap_config ssm2602_regmap_config = {  	.reg_defaults_raw = ssm2602_reg,  	.num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),  }; +EXPORT_SYMBOL_GPL(ssm2602_regmap_config); -#if defined(CONFIG_SPI_MASTER) -static int ssm2602_spi_probe(struct spi_device *spi) +int ssm2602_probe(struct device *dev, enum ssm2602_type type, +	struct regmap *regmap)  {  	struct ssm2602_priv *ssm2602; -	int ret; - -	ssm2602 = devm_kzalloc(&spi->dev, sizeof(struct ssm2602_priv), -			       GFP_KERNEL); -	if (ssm2602 == NULL) -		return -ENOMEM; - -	spi_set_drvdata(spi, ssm2602); -	ssm2602->type = SSM2602; - -	ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config); -	if (IS_ERR(ssm2602->regmap)) -		return PTR_ERR(ssm2602->regmap); - -	ret = snd_soc_register_codec(&spi->dev, -			&soc_codec_dev_ssm2602, &ssm2602_dai, 1); -	return ret; -} - -static int ssm2602_spi_remove(struct spi_device *spi) -{ -	snd_soc_unregister_codec(&spi->dev); -	return 0; -} -static struct spi_driver ssm2602_spi_driver = { -	.driver = { -		.name	= "ssm2602", -		.owner	= THIS_MODULE, -	}, -	.probe		= ssm2602_spi_probe, -	.remove		= ssm2602_spi_remove, -}; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -/* - * ssm2602 2 wire address is determined by GPIO5 - * state during powerup. - *    low  = 0x1a - *    high = 0x1b - */ -static int ssm2602_i2c_probe(struct i2c_client *i2c, -			     const struct i2c_device_id *id) -{ -	struct ssm2602_priv *ssm2602; -	int ret; +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); -	ssm2602 = devm_kzalloc(&i2c->dev, sizeof(struct ssm2602_priv), -			       GFP_KERNEL); +	ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL);  	if (ssm2602 == NULL)  		return -ENOMEM; -	i2c_set_clientdata(i2c, ssm2602); -	ssm2602->type = id->driver_data; - -	ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config); -	if (IS_ERR(ssm2602->regmap)) -		return PTR_ERR(ssm2602->regmap); - -	ret = snd_soc_register_codec(&i2c->dev, -			&soc_codec_dev_ssm2602, &ssm2602_dai, 1); -	return ret; -} - -static int ssm2602_i2c_remove(struct i2c_client *client) -{ -	snd_soc_unregister_codec(&client->dev); -	return 0; -} - -static const struct i2c_device_id ssm2602_i2c_id[] = { -	{ "ssm2602", SSM2602 }, -	{ "ssm2603", SSM2602 }, -	{ "ssm2604", SSM2604 }, -	{ } -}; -MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); - -/* corgi i2c codec control layer */ -static struct i2c_driver ssm2602_i2c_driver = { -	.driver = { -		.name = "ssm2602", -		.owner = THIS_MODULE, -	}, -	.probe = ssm2602_i2c_probe, -	.remove = ssm2602_i2c_remove, -	.id_table = ssm2602_i2c_id, -}; -#endif - - -static int __init ssm2602_modinit(void) -{ -	int ret = 0; - -#if defined(CONFIG_SPI_MASTER) -	ret = spi_register_driver(&ssm2602_spi_driver); -	if (ret) -		return ret; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	ret = i2c_add_driver(&ssm2602_i2c_driver); -	if (ret) -		return ret; -#endif - -	return ret; -} -module_init(ssm2602_modinit); - -static void __exit ssm2602_exit(void) -{ -#if defined(CONFIG_SPI_MASTER) -	spi_unregister_driver(&ssm2602_spi_driver); -#endif +	dev_set_drvdata(dev, ssm2602); +	ssm2602->type = SSM2602; +	ssm2602->regmap = regmap; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	i2c_del_driver(&ssm2602_i2c_driver); -#endif +	return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, +		&ssm2602_dai, 1);  } -module_exit(ssm2602_exit); +EXPORT_SYMBOL_GPL(ssm2602_probe);  MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");  MODULE_AUTHOR("Cliff Cai"); diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h index fbd07d7b73c..74753884768 100644 --- a/sound/soc/codecs/ssm2602.h +++ b/sound/soc/codecs/ssm2602.h @@ -28,6 +28,20 @@  #ifndef _SSM2602_H  #define _SSM2602_H +#include <linux/regmap.h> + +struct device; + +enum ssm2602_type { +	SSM2602, +	SSM2604, +}; + +extern const struct regmap_config ssm2602_regmap_config; + +int ssm2602_probe(struct device *dev, enum ssm2602_type type, +	struct regmap *regmap); +  /* SSM2602 Codec Register definitions */  #define SSM2602_LINVOL   0x00 diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 06edb396e73..0579d187135 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -187,42 +187,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = {  	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),  }; -static const struct soc_enum sta32x_drc_ac_enum = -	SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, -			2, sta32x_drc_ac); -static const struct soc_enum sta32x_auto_eq_enum = -	SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, -			3, sta32x_auto_eq_mode); -static const struct soc_enum sta32x_auto_gc_enum = -	SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, -			4, sta32x_auto_gc_mode); -static const struct soc_enum sta32x_auto_xo_enum = -	SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, -			16, sta32x_auto_xo_mode); -static const struct soc_enum sta32x_preset_eq_enum = -	SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, -			32, sta32x_preset_eq_mode); -static const struct soc_enum sta32x_limiter_ch1_enum = -	SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, -			3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch2_enum = -	SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, -			3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch3_enum = -	SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, -			3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter1_attack_rate_enum = -	SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, -			16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter2_attack_rate_enum = -	SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, -			16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter1_release_rate_enum = -	SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, -			16, sta32x_limiter_release_rate); -static const struct soc_enum sta32x_limiter2_release_rate_enum = -	SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, -			16, sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum, +			    STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, +			    sta32x_drc_ac); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum, +			    STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, +			    sta32x_auto_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum, +			    STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, +			    sta32x_auto_gc_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum, +			    STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, +			    sta32x_auto_xo_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum, +			    STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, +			    sta32x_preset_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum, +			    STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, +			    sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum, +			    STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, +			    sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum, +			    STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, +			    sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum, +			    STA32X_L1AR, STA32X_LxA_SHIFT, +			    sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum, +			    STA32X_L2AR, STA32X_LxA_SHIFT, +			    sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum, +			    STA32X_L1AR, STA32X_LxR_SHIFT, +			    sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum, +			    STA32X_L2AR, STA32X_LxR_SHIFT, +			    sta32x_limiter_release_rate);  /* byte array controls for setting biquad, mixer, scaling coefficients;   * for biquads all five coefficients need to be set in one go, @@ -243,7 +243,7 @@ static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,  static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,  				  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	int numcoef = kcontrol->private_value >> 16;  	int index = kcontrol->private_value & 0xffff;  	unsigned int cfud; @@ -272,7 +272,7 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,  static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,  				  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);  	int numcoef = kcontrol->private_value >> 16;  	int index = kcontrol->private_value & 0xffff; @@ -331,7 +331,7 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)  static int sta32x_cache_sync(struct snd_soc_codec *codec)  { -	struct sta32x_priv *sta32x = codec->control_data; +	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);  	unsigned int mute;  	int rc; @@ -434,7 +434,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0,  SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),  SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),  SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), -SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), +SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),  /* depending on mode, the attack/release thresholds have   * two different enum definitions; provide both @@ -872,16 +872,6 @@ static int sta32x_probe(struct snd_soc_codec *codec)  		return ret;  	} -	/* Tell ASoC what kind of I/O to use to read the registers.  ASoC will -	 * then do the I2C transactions itself. -	 */ -	codec->control_data = sta32x->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); -		goto err; -	} -  	/* Chip documentation explicitly requires that the reset values  	 * of reserved register bits are left untouched.  	 * Write the register default value to cache for reserved registers, @@ -946,10 +936,6 @@ static int sta32x_probe(struct snd_soc_codec *codec)  	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);  	return 0; - -err: -	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); -	return ret;  }  static int sta32x_remove(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c new file mode 100644 index 00000000000..cc97dd52aa9 --- /dev/null +++ b/sound/soc/codecs/sta350.c @@ -0,0 +1,1311 @@ +/* + * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system + * + * Copyright: 2014 Raumfeld GmbH + * Author: Sven Brandau <info@brandau.biz> + * + * based on code from: + *	Raumfeld GmbH + *	  Johannes Stezenbach <js@sig21.net> + *	Wolfson Microelectronics PLC. + *	  Mark Brown <broonie@opensource.wolfsonmicro.com> + *	Freescale Semiconductor, Inc. + *	  Timur Tabi <timur@freescale.com> + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include <sound/sta350.h> +#include "sta350.h" + +#define STA350_RATES (SNDRV_PCM_RATE_32000 | \ +		      SNDRV_PCM_RATE_44100 | \ +		      SNDRV_PCM_RATE_48000 | \ +		      SNDRV_PCM_RATE_88200 | \ +		      SNDRV_PCM_RATE_96000 | \ +		      SNDRV_PCM_RATE_176400 | \ +		      SNDRV_PCM_RATE_192000) + +#define STA350_FORMATS \ +	(SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \ +	 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ +	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ +	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ +	 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \ +	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE) + +/* Power-up register defaults */ +static const struct reg_default sta350_regs[] = { +	{  0x0, 0x63 }, +	{  0x1, 0x80 }, +	{  0x2, 0xdf }, +	{  0x3, 0x40 }, +	{  0x4, 0xc2 }, +	{  0x5, 0x5c }, +	{  0x6, 0x00 }, +	{  0x7, 0xff }, +	{  0x8, 0x60 }, +	{  0x9, 0x60 }, +	{  0xa, 0x60 }, +	{  0xb, 0x00 }, +	{  0xc, 0x00 }, +	{  0xd, 0x00 }, +	{  0xe, 0x00 }, +	{  0xf, 0x40 }, +	{ 0x10, 0x80 }, +	{ 0x11, 0x77 }, +	{ 0x12, 0x6a }, +	{ 0x13, 0x69 }, +	{ 0x14, 0x6a }, +	{ 0x15, 0x69 }, +	{ 0x16, 0x00 }, +	{ 0x17, 0x00 }, +	{ 0x18, 0x00 }, +	{ 0x19, 0x00 }, +	{ 0x1a, 0x00 }, +	{ 0x1b, 0x00 }, +	{ 0x1c, 0x00 }, +	{ 0x1d, 0x00 }, +	{ 0x1e, 0x00 }, +	{ 0x1f, 0x00 }, +	{ 0x20, 0x00 }, +	{ 0x21, 0x00 }, +	{ 0x22, 0x00 }, +	{ 0x23, 0x00 }, +	{ 0x24, 0x00 }, +	{ 0x25, 0x00 }, +	{ 0x26, 0x00 }, +	{ 0x27, 0x2a }, +	{ 0x28, 0xc0 }, +	{ 0x29, 0xf3 }, +	{ 0x2a, 0x33 }, +	{ 0x2b, 0x00 }, +	{ 0x2c, 0x0c }, +	{ 0x31, 0x00 }, +	{ 0x36, 0x00 }, +	{ 0x37, 0x00 }, +	{ 0x38, 0x00 }, +	{ 0x39, 0x01 }, +	{ 0x3a, 0xee }, +	{ 0x3b, 0xff }, +	{ 0x3c, 0x7e }, +	{ 0x3d, 0xc0 }, +	{ 0x3e, 0x26 }, +	{ 0x3f, 0x00 }, +	{ 0x48, 0x00 }, +	{ 0x49, 0x00 }, +	{ 0x4a, 0x00 }, +	{ 0x4b, 0x04 }, +	{ 0x4c, 0x00 }, +}; + +static const struct regmap_range sta350_write_regs_range[] = { +	regmap_reg_range(STA350_CONFA,  STA350_AUTO2), +	regmap_reg_range(STA350_C1CFG,  STA350_FDRC2), +	regmap_reg_range(STA350_EQCFG,  STA350_EVOLRES), +	regmap_reg_range(STA350_NSHAPE, STA350_MISC2), +}; + +static const struct regmap_range sta350_read_regs_range[] = { +	regmap_reg_range(STA350_CONFA,  STA350_AUTO2), +	regmap_reg_range(STA350_C1CFG,  STA350_STATUS), +	regmap_reg_range(STA350_EQCFG,  STA350_EVOLRES), +	regmap_reg_range(STA350_NSHAPE, STA350_MISC2), +}; + +static const struct regmap_range sta350_volatile_regs_range[] = { +	regmap_reg_range(STA350_CFADDR2, STA350_CFUD), +	regmap_reg_range(STA350_STATUS,  STA350_STATUS), +}; + +static const struct regmap_access_table sta350_write_regs = { +	.yes_ranges =	sta350_write_regs_range, +	.n_yes_ranges =	ARRAY_SIZE(sta350_write_regs_range), +}; + +static const struct regmap_access_table sta350_read_regs = { +	.yes_ranges =	sta350_read_regs_range, +	.n_yes_ranges =	ARRAY_SIZE(sta350_read_regs_range), +}; + +static const struct regmap_access_table sta350_volatile_regs = { +	.yes_ranges =	sta350_volatile_regs_range, +	.n_yes_ranges =	ARRAY_SIZE(sta350_volatile_regs_range), +}; + +/* regulator power supply names */ +static const char * const sta350_supply_names[] = { +	"vdd-dig",	/* digital supply, 3.3V */ +	"vdd-pll",	/* pll supply, 3.3V */ +	"vcc"		/* power amp supply, 5V - 26V */ +}; + +/* codec private data */ +struct sta350_priv { +	struct regmap *regmap; +	struct regulator_bulk_data supplies[ARRAY_SIZE(sta350_supply_names)]; +	struct sta350_platform_data *pdata; + +	unsigned int mclk; +	unsigned int format; + +	u32 coef_shadow[STA350_COEF_COUNT]; +	int shutdown; + +	struct gpio_desc *gpiod_nreset; +	struct gpio_desc *gpiod_power_down; + +	struct mutex coeff_lock; +}; + +static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); +static const DECLARE_TLV_DB_SCALE(tone_tlv, -1200, 200, 0); + +static const char * const sta350_drc_ac[] = { +	"Anti-Clipping", "Dynamic Range Compression" +}; +static const char * const sta350_auto_gc_mode[] = { +	"User", "AC no clipping", "AC limited clipping (10%)", +	"DRC nighttime listening mode" +}; +static const char * const sta350_auto_xo_mode[] = { +	"User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", +	"200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", +	"340Hz", "360Hz" +}; +static const char * const sta350_binary_output[] = { +	"FFX 3-state output - normal operation", "Binary output" +}; +static const char * const sta350_limiter_select[] = { +	"Limiter Disabled", "Limiter #1", "Limiter #2" +}; +static const char * const sta350_limiter_attack_rate[] = { +	"3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", +	"0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", +	"0.0645", "0.0564", "0.0501", "0.0451" +}; +static const char * const sta350_limiter_release_rate[] = { +	"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", +	"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", +	"0.0134", "0.0117", "0.0110", "0.0104" +}; +static const char * const sta350_noise_shaper_type[] = { +	"Third order", "Fourth order" +}; + +static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv, +	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), +	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_release_tlv, +	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), +	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), +	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), +	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), +	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_attack_tlv, +	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), +	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), +	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_release_tlv, +	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), +	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), +	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), +	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), +	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), +); + +static SOC_ENUM_SINGLE_DECL(sta350_drc_ac_enum, +			    STA350_CONFD, STA350_CONFD_DRC_SHIFT, +			    sta350_drc_ac); +static SOC_ENUM_SINGLE_DECL(sta350_noise_shaper_enum, +			    STA350_CONFE, STA350_CONFE_NSBW_SHIFT, +			    sta350_noise_shaper_type); +static SOC_ENUM_SINGLE_DECL(sta350_auto_gc_enum, +			    STA350_AUTO1, STA350_AUTO1_AMGC_SHIFT, +			    sta350_auto_gc_mode); +static SOC_ENUM_SINGLE_DECL(sta350_auto_xo_enum, +			    STA350_AUTO2, STA350_AUTO2_XO_SHIFT, +			    sta350_auto_xo_mode); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch1_enum, +			    STA350_C1CFG, STA350_CxCFG_BO_SHIFT, +			    sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch2_enum, +			    STA350_C2CFG, STA350_CxCFG_BO_SHIFT, +			    sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch3_enum, +			    STA350_C3CFG, STA350_CxCFG_BO_SHIFT, +			    sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch1_enum, +			    STA350_C1CFG, STA350_CxCFG_LS_SHIFT, +			    sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch2_enum, +			    STA350_C2CFG, STA350_CxCFG_LS_SHIFT, +			    sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch3_enum, +			    STA350_C3CFG, STA350_CxCFG_LS_SHIFT, +			    sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter1_attack_rate_enum, +			    STA350_L1AR, STA350_LxA_SHIFT, +			    sta350_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter2_attack_rate_enum, +			    STA350_L2AR, STA350_LxA_SHIFT, +			    sta350_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter1_release_rate_enum, +			    STA350_L1AR, STA350_LxR_SHIFT, +			    sta350_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter2_release_rate_enum, +			    STA350_L2AR, STA350_LxR_SHIFT, +			    sta350_limiter_release_rate); + +/* + * byte array controls for setting biquad, mixer, scaling coefficients; + * for biquads all five coefficients need to be set in one go, + * mixer and pre/postscale coefs can be set individually; + * each coef is 24bit, the bytes are ordered in the same way + * as given in the STA350 data sheet (big endian; b1, b2, a1, a2, b0) + */ + +static int sta350_coefficient_info(struct snd_kcontrol *kcontrol, +				   struct snd_ctl_elem_info *uinfo) +{ +	int numcoef = kcontrol->private_value >> 16; +	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; +	uinfo->count = 3 * numcoef; +	return 0; +} + +static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, +				  struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	int numcoef = kcontrol->private_value >> 16; +	int index = kcontrol->private_value & 0xffff; +	unsigned int cfud, val; +	int i, ret = 0; + +	mutex_lock(&sta350->coeff_lock); + +	/* preserve reserved bits in STA350_CFUD */ +	regmap_read(sta350->regmap, STA350_CFUD, &cfud); +	cfud &= 0xf0; +	/* +	 * chip documentation does not say if the bits are self clearing, +	 * so do it explicitly +	 */ +	regmap_write(sta350->regmap, STA350_CFUD, cfud); + +	regmap_write(sta350->regmap, STA350_CFADDR2, index); +	if (numcoef == 1) { +		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04); +	} else if (numcoef == 5) { +		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08); +	} else { +		ret = -EINVAL; +		goto exit_unlock; +	} + +	for (i = 0; i < 3 * numcoef; i++) { +		regmap_read(sta350->regmap, STA350_B1CF1 + i, &val); +		ucontrol->value.bytes.data[i] = val; +	} + +exit_unlock: +	mutex_unlock(&sta350->coeff_lock); + +	return ret; +} + +static int sta350_coefficient_put(struct snd_kcontrol *kcontrol, +				  struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	int numcoef = kcontrol->private_value >> 16; +	int index = kcontrol->private_value & 0xffff; +	unsigned int cfud; +	int i; + +	/* preserve reserved bits in STA350_CFUD */ +	regmap_read(sta350->regmap, STA350_CFUD, &cfud); +	cfud &= 0xf0; +	/* +	 * chip documentation does not say if the bits are self clearing, +	 * so do it explicitly +	 */ +	regmap_write(sta350->regmap, STA350_CFUD, cfud); + +	regmap_write(sta350->regmap, STA350_CFADDR2, index); +	for (i = 0; i < numcoef && (index + i < STA350_COEF_COUNT); i++) +		sta350->coef_shadow[index + i] = +			  (ucontrol->value.bytes.data[3 * i] << 16) +			| (ucontrol->value.bytes.data[3 * i + 1] << 8) +			| (ucontrol->value.bytes.data[3 * i + 2]); +	for (i = 0; i < 3 * numcoef; i++) +		regmap_write(sta350->regmap, STA350_B1CF1 + i, +			     ucontrol->value.bytes.data[i]); +	if (numcoef == 1) +		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01); +	else if (numcoef == 5) +		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x02); +	else +		return -EINVAL; + +	return 0; +} + +static int sta350_sync_coef_shadow(struct snd_soc_codec *codec) +{ +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	unsigned int cfud; +	int i; + +	/* preserve reserved bits in STA350_CFUD */ +	regmap_read(sta350->regmap, STA350_CFUD, &cfud); +	cfud &= 0xf0; + +	for (i = 0; i < STA350_COEF_COUNT; i++) { +		regmap_write(sta350->regmap, STA350_CFADDR2, i); +		regmap_write(sta350->regmap, STA350_B1CF1, +			     (sta350->coef_shadow[i] >> 16) & 0xff); +		regmap_write(sta350->regmap, STA350_B1CF2, +			     (sta350->coef_shadow[i] >> 8) & 0xff); +		regmap_write(sta350->regmap, STA350_B1CF3, +			     (sta350->coef_shadow[i]) & 0xff); +		/* +		 * chip documentation does not say if the bits are +		 * self-clearing, so do it explicitly +		 */ +		regmap_write(sta350->regmap, STA350_CFUD, cfud); +		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01); +	} +	return 0; +} + +static int sta350_cache_sync(struct snd_soc_codec *codec) +{ +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	unsigned int mute; +	int rc; + +	/* mute during register sync */ +	regmap_read(sta350->regmap, STA350_CFUD, &mute); +	regmap_write(sta350->regmap, STA350_MMUTE, mute | STA350_MMUTE_MMUTE); +	sta350_sync_coef_shadow(codec); +	rc = regcache_sync(sta350->regmap); +	regmap_write(sta350->regmap, STA350_MMUTE, mute); +	return rc; +} + +#define SINGLE_COEF(xname, index) \ +{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ +	.info = sta350_coefficient_info, \ +	.get = sta350_coefficient_get,\ +	.put = sta350_coefficient_put, \ +	.private_value = index | (1 << 16) } + +#define BIQUAD_COEFS(xname, index) \ +{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ +	.info = sta350_coefficient_info, \ +	.get = sta350_coefficient_get,\ +	.put = sta350_coefficient_put, \ +	.private_value = index | (5 << 16) } + +static const struct snd_kcontrol_new sta350_snd_controls[] = { +SOC_SINGLE_TLV("Master Volume", STA350_MVOL, 0, 0xff, 1, mvol_tlv), +/* VOL */ +SOC_SINGLE_TLV("Ch1 Volume", STA350_C1VOL, 0, 0xff, 1, chvol_tlv), +SOC_SINGLE_TLV("Ch2 Volume", STA350_C2VOL, 0, 0xff, 1, chvol_tlv), +SOC_SINGLE_TLV("Ch3 Volume", STA350_C3VOL, 0, 0xff, 1, chvol_tlv), +/* CONFD */ +SOC_SINGLE("High Pass Filter Bypass Switch", +	   STA350_CONFD, STA350_CONFD_HPB_SHIFT, 1, 1), +SOC_SINGLE("De-emphasis Filter Switch", +	   STA350_CONFD, STA350_CONFD_DEMP_SHIFT, 1, 0), +SOC_SINGLE("DSP Bypass Switch", +	   STA350_CONFD, STA350_CONFD_DSPB_SHIFT, 1, 0), +SOC_SINGLE("Post-scale Link Switch", +	   STA350_CONFD, STA350_CONFD_PSL_SHIFT, 1, 0), +SOC_SINGLE("Biquad Coefficient Link Switch", +	   STA350_CONFD, STA350_CONFD_BQL_SHIFT, 1, 0), +SOC_ENUM("Compressor/Limiter Switch", sta350_drc_ac_enum), +SOC_ENUM("Noise Shaper Bandwidth", sta350_noise_shaper_enum), +SOC_SINGLE("Zero-detect Mute Enable Switch", +	   STA350_CONFD, STA350_CONFD_ZDE_SHIFT, 1, 0), +SOC_SINGLE("Submix Mode Switch", +	   STA350_CONFD, STA350_CONFD_SME_SHIFT, 1, 0), +/* CONFE */ +SOC_SINGLE("Zero Cross Switch", STA350_CONFE, STA350_CONFE_ZCE_SHIFT, 1, 0), +SOC_SINGLE("Soft Ramp Switch", STA350_CONFE, STA350_CONFE_SVE_SHIFT, 1, 0), +/* MUTE */ +SOC_SINGLE("Master Switch", STA350_MMUTE, STA350_MMUTE_MMUTE_SHIFT, 1, 1), +SOC_SINGLE("Ch1 Switch", STA350_MMUTE, STA350_MMUTE_C1M_SHIFT, 1, 1), +SOC_SINGLE("Ch2 Switch", STA350_MMUTE, STA350_MMUTE_C2M_SHIFT, 1, 1), +SOC_SINGLE("Ch3 Switch", STA350_MMUTE, STA350_MMUTE_C3M_SHIFT, 1, 1), +/* AUTOx */ +SOC_ENUM("Automode GC", sta350_auto_gc_enum), +SOC_ENUM("Automode XO", sta350_auto_xo_enum), +/* CxCFG */ +SOC_SINGLE("Ch1 Tone Control Bypass Switch", +	   STA350_C1CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), +SOC_SINGLE("Ch2 Tone Control Bypass Switch", +	   STA350_C2CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), +SOC_SINGLE("Ch1 EQ Bypass Switch", +	   STA350_C1CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), +SOC_SINGLE("Ch2 EQ Bypass Switch", +	   STA350_C2CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), +SOC_SINGLE("Ch1 Master Volume Bypass Switch", +	   STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_SINGLE("Ch2 Master Volume Bypass Switch", +	   STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_SINGLE("Ch3 Master Volume Bypass Switch", +	   STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_ENUM("Ch1 Binary Output Select", sta350_binary_output_ch1_enum), +SOC_ENUM("Ch2 Binary Output Select", sta350_binary_output_ch2_enum), +SOC_ENUM("Ch3 Binary Output Select", sta350_binary_output_ch3_enum), +SOC_ENUM("Ch1 Limiter Select", sta350_limiter_ch1_enum), +SOC_ENUM("Ch2 Limiter Select", sta350_limiter_ch2_enum), +SOC_ENUM("Ch3 Limiter Select", sta350_limiter_ch3_enum), +/* TONE */ +SOC_SINGLE_RANGE_TLV("Bass Tone Control Volume", +		     STA350_TONE, STA350_TONE_BTC_SHIFT, 1, 13, 0, tone_tlv), +SOC_SINGLE_RANGE_TLV("Treble Tone Control Volume", +		     STA350_TONE, STA350_TONE_TTC_SHIFT, 1, 13, 0, tone_tlv), +SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta350_limiter1_attack_rate_enum), +SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta350_limiter2_attack_rate_enum), +SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta350_limiter1_release_rate_enum), +SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta350_limiter2_release_rate_enum), + +/* + * depending on mode, the attack/release thresholds have + * two different enum definitions; provide both + */ +SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", +	       STA350_L1ATRT, STA350_LxA_SHIFT, +	       16, 0, sta350_limiter_ac_attack_tlv), +SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", +	       STA350_L2ATRT, STA350_LxA_SHIFT, +	       16, 0, sta350_limiter_ac_attack_tlv), +SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", +	       STA350_L1ATRT, STA350_LxR_SHIFT, +	       16, 0, sta350_limiter_ac_release_tlv), +SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", +	       STA350_L2ATRT, STA350_LxR_SHIFT, +	       16, 0, sta350_limiter_ac_release_tlv), +SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", +	       STA350_L1ATRT, STA350_LxA_SHIFT, +	       16, 0, sta350_limiter_drc_attack_tlv), +SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", +	       STA350_L2ATRT, STA350_LxA_SHIFT, +	       16, 0, sta350_limiter_drc_attack_tlv), +SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", +	       STA350_L1ATRT, STA350_LxR_SHIFT, +	       16, 0, sta350_limiter_drc_release_tlv), +SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", +	       STA350_L2ATRT, STA350_LxR_SHIFT, +	       16, 0, sta350_limiter_drc_release_tlv), + +BIQUAD_COEFS("Ch1 - Biquad 1", 0), +BIQUAD_COEFS("Ch1 - Biquad 2", 5), +BIQUAD_COEFS("Ch1 - Biquad 3", 10), +BIQUAD_COEFS("Ch1 - Biquad 4", 15), +BIQUAD_COEFS("Ch2 - Biquad 1", 20), +BIQUAD_COEFS("Ch2 - Biquad 2", 25), +BIQUAD_COEFS("Ch2 - Biquad 3", 30), +BIQUAD_COEFS("Ch2 - Biquad 4", 35), +BIQUAD_COEFS("High-pass", 40), +BIQUAD_COEFS("Low-pass", 45), +SINGLE_COEF("Ch1 - Prescale", 50), +SINGLE_COEF("Ch2 - Prescale", 51), +SINGLE_COEF("Ch1 - Postscale", 52), +SINGLE_COEF("Ch2 - Postscale", 53), +SINGLE_COEF("Ch3 - Postscale", 54), +SINGLE_COEF("Thermal warning - Postscale", 55), +SINGLE_COEF("Ch1 - Mix 1", 56), +SINGLE_COEF("Ch1 - Mix 2", 57), +SINGLE_COEF("Ch2 - Mix 1", 58), +SINGLE_COEF("Ch2 - Mix 2", 59), +SINGLE_COEF("Ch3 - Mix 1", 60), +SINGLE_COEF("Ch3 - Mix 2", 61), +}; + +static const struct snd_soc_dapm_widget sta350_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("LEFT"), +SND_SOC_DAPM_OUTPUT("RIGHT"), +SND_SOC_DAPM_OUTPUT("SUB"), +}; + +static const struct snd_soc_dapm_route sta350_dapm_routes[] = { +	{ "LEFT", NULL, "DAC" }, +	{ "RIGHT", NULL, "DAC" }, +	{ "SUB", NULL, "DAC" }, +	{ "DAC", NULL, "Playback" }, +}; + +/* MCLK interpolation ratio per fs */ +static struct { +	int fs; +	int ir; +} interpolation_ratios[] = { +	{ 32000, 0 }, +	{ 44100, 0 }, +	{ 48000, 0 }, +	{ 88200, 1 }, +	{ 96000, 1 }, +	{ 176400, 2 }, +	{ 192000, 2 }, +}; + +/* MCLK to fs clock ratios */ +static int mcs_ratio_table[3][6] = { +	{ 768, 512, 384, 256, 128, 576 }, +	{ 384, 256, 192, 128,  64,   0 }, +	{ 192, 128,  96,  64,  32,   0 }, +}; + +/** + * sta350_set_dai_sysclk - configure MCLK + * @codec_dai: the codec DAI + * @clk_id: the clock ID (ignored) + * @freq: the MCLK input frequency + * @dir: the clock direction (ignored) + * + * The value of MCLK is used to determine which sample rates are supported + * by the STA350, based on the mcs_ratio_table. + * + * This function must be called by the machine driver's 'startup' function, + * otherwise the list of supported sample rates will not be available in + * time for ALSA. + */ +static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai, +				 int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + +	dev_dbg(codec->dev, "mclk=%u\n", freq); +	sta350->mclk = freq; + +	return 0; +} + +/** + * sta350_set_dai_fmt - configure the codec for the selected audio format + * @codec_dai: the codec DAI + * @fmt: a SND_SOC_DAIFMT_x value indicating the data format + * + * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the + * codec accordingly. + */ +static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai, +			      unsigned int fmt) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	unsigned int confb = 0; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBS_CFS: +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +	case SND_SOC_DAIFMT_RIGHT_J: +	case SND_SOC_DAIFMT_LEFT_J: +		sta350->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		confb |= STA350_CONFB_C2IM; +		break; +	case SND_SOC_DAIFMT_NB_IF: +		confb |= STA350_CONFB_C1IM; +		break; +	default: +		return -EINVAL; +	} + +	return regmap_update_bits(sta350->regmap, STA350_CONFB, +				  STA350_CONFB_C1IM | STA350_CONFB_C2IM, confb); +} + +/** + * sta350_hw_params - program the STA350 with the given hardware parameters. + * @substream: the audio stream + * @params: the hardware parameters to set + * @dai: the SOC DAI (ignored) + * + * This function programs the hardware with the values provided. + * Specifically, the sample rate and the data format. + */ +static int sta350_hw_params(struct snd_pcm_substream *substream, +			    struct snd_pcm_hw_params *params, +			    struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	int i, mcs = -EINVAL, ir = -EINVAL; +	unsigned int confa, confb; +	unsigned int rate, ratio; +	int ret; + +	if (!sta350->mclk) { +		dev_err(codec->dev, +			"sta350->mclk is unset. Unable to determine ratio\n"); +		return -EIO; +	} + +	rate = params_rate(params); +	ratio = sta350->mclk / rate; +	dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio); + +	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { +		if (interpolation_ratios[i].fs == rate) { +			ir = interpolation_ratios[i].ir; +			break; +		} +	} + +	if (ir < 0) { +		dev_err(codec->dev, "Unsupported samplerate: %u\n", rate); +		return -EINVAL; +	} + +	for (i = 0; i < 6; i++) { +		if (mcs_ratio_table[ir][i] == ratio) { +			mcs = i; +			break; +		} +	} + +	if (mcs < 0) { +		dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio); +		return -EINVAL; +	} + +	confa = (ir << STA350_CONFA_IR_SHIFT) | +		(mcs << STA350_CONFA_MCS_SHIFT); +	confb = 0; + +	switch (params_width(params)) { +	case 24: +		dev_dbg(codec->dev, "24bit\n"); +		/* fall through */ +	case 32: +		dev_dbg(codec->dev, "24bit or 32bit\n"); +		switch (sta350->format) { +		case SND_SOC_DAIFMT_I2S: +			confb |= 0x0; +			break; +		case SND_SOC_DAIFMT_LEFT_J: +			confb |= 0x1; +			break; +		case SND_SOC_DAIFMT_RIGHT_J: +			confb |= 0x2; +			break; +		} + +		break; +	case 20: +		dev_dbg(codec->dev, "20bit\n"); +		switch (sta350->format) { +		case SND_SOC_DAIFMT_I2S: +			confb |= 0x4; +			break; +		case SND_SOC_DAIFMT_LEFT_J: +			confb |= 0x5; +			break; +		case SND_SOC_DAIFMT_RIGHT_J: +			confb |= 0x6; +			break; +		} + +		break; +	case 18: +		dev_dbg(codec->dev, "18bit\n"); +		switch (sta350->format) { +		case SND_SOC_DAIFMT_I2S: +			confb |= 0x8; +			break; +		case SND_SOC_DAIFMT_LEFT_J: +			confb |= 0x9; +			break; +		case SND_SOC_DAIFMT_RIGHT_J: +			confb |= 0xa; +			break; +		} + +		break; +	case 16: +		dev_dbg(codec->dev, "16bit\n"); +		switch (sta350->format) { +		case SND_SOC_DAIFMT_I2S: +			confb |= 0x0; +			break; +		case SND_SOC_DAIFMT_LEFT_J: +			confb |= 0xd; +			break; +		case SND_SOC_DAIFMT_RIGHT_J: +			confb |= 0xe; +			break; +		} + +		break; +	default: +		return -EINVAL; +	} + +	ret = regmap_update_bits(sta350->regmap, STA350_CONFA, +				 STA350_CONFA_MCS_MASK | STA350_CONFA_IR_MASK, +				 confa); +	if (ret < 0) +		return ret; + +	ret = regmap_update_bits(sta350->regmap, STA350_CONFB, +				 STA350_CONFB_SAI_MASK | STA350_CONFB_SAIFB, +				 confb); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int sta350_startup_sequence(struct sta350_priv *sta350) +{ +	if (sta350->gpiod_power_down) +		gpiod_set_value(sta350->gpiod_power_down, 1); + +	if (sta350->gpiod_nreset) { +		gpiod_set_value(sta350->gpiod_nreset, 0); +		mdelay(1); +		gpiod_set_value(sta350->gpiod_nreset, 1); +		mdelay(1); +	} + +	return 0; +} + +/** + * sta350_set_bias_level - DAPM callback + * @codec: the codec device + * @level: DAPM power level + * + * This is called by ALSA to put the codec into low power mode + * or to wake it up.  If the codec is powered off completely + * all registers must be restored after power on. + */ +static int sta350_set_bias_level(struct snd_soc_codec *codec, +				 enum snd_soc_bias_level level) +{ +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	int ret; + +	dev_dbg(codec->dev, "level = %d\n", level); +	switch (level) { +	case SND_SOC_BIAS_ON: +		break; + +	case SND_SOC_BIAS_PREPARE: +		/* Full power on */ +		regmap_update_bits(sta350->regmap, STA350_CONFF, +				   STA350_CONFF_PWDN | STA350_CONFF_EAPD, +				   STA350_CONFF_PWDN | STA350_CONFF_EAPD); +		break; + +	case SND_SOC_BIAS_STANDBY: +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { +			ret = regulator_bulk_enable( +				ARRAY_SIZE(sta350->supplies), +				sta350->supplies); +			if (ret < 0) { +				dev_err(codec->dev, +					"Failed to enable supplies: %d\n", +					ret); +				return ret; +			} +			sta350_startup_sequence(sta350); +			sta350_cache_sync(codec); +		} + +		/* Power down */ +		regmap_update_bits(sta350->regmap, STA350_CONFF, +				   STA350_CONFF_PWDN | STA350_CONFF_EAPD, +				   0); + +		break; + +	case SND_SOC_BIAS_OFF: +		/* The chip runs through the power down sequence for us */ +		regmap_update_bits(sta350->regmap, STA350_CONFF, +				   STA350_CONFF_PWDN | STA350_CONFF_EAPD, 0); + +		/* power down: low */ +		if (sta350->gpiod_power_down) +			gpiod_set_value(sta350->gpiod_power_down, 0); + +		if (sta350->gpiod_nreset) +			gpiod_set_value(sta350->gpiod_nreset, 0); + +		regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), +				       sta350->supplies); +		break; +	} +	codec->dapm.bias_level = level; +	return 0; +} + +static const struct snd_soc_dai_ops sta350_dai_ops = { +	.hw_params	= sta350_hw_params, +	.set_sysclk	= sta350_set_dai_sysclk, +	.set_fmt	= sta350_set_dai_fmt, +}; + +static struct snd_soc_dai_driver sta350_dai = { +	.name = "sta350-hifi", +	.playback = { +		.stream_name = "Playback", +		.channels_min = 2, +		.channels_max = 2, +		.rates = STA350_RATES, +		.formats = STA350_FORMATS, +	}, +	.ops = &sta350_dai_ops, +}; + +#ifdef CONFIG_PM +static int sta350_suspend(struct snd_soc_codec *codec) +{ +	sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); +	return 0; +} + +static int sta350_resume(struct snd_soc_codec *codec) +{ +	sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +	return 0; +} +#else +#define sta350_suspend NULL +#define sta350_resume NULL +#endif + +static int sta350_probe(struct snd_soc_codec *codec) +{ +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); +	struct sta350_platform_data *pdata = sta350->pdata; +	int i, ret = 0, thermal = 0; + +	ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies), +				    sta350->supplies); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); +		return ret; +	} + +	ret = sta350_startup_sequence(sta350); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to startup device\n"); +		return ret; +	} + +	/* CONFA */ +	if (!pdata->thermal_warning_recovery) +		thermal |= STA350_CONFA_TWAB; +	if (!pdata->thermal_warning_adjustment) +		thermal |= STA350_CONFA_TWRB; +	if (!pdata->fault_detect_recovery) +		thermal |= STA350_CONFA_FDRB; +	regmap_update_bits(sta350->regmap, STA350_CONFA, +			   STA350_CONFA_TWAB | STA350_CONFA_TWRB | +			   STA350_CONFA_FDRB, +			   thermal); + +	/* CONFC */ +	regmap_update_bits(sta350->regmap, STA350_CONFC, +			   STA350_CONFC_OM_MASK, +			   pdata->ffx_power_output_mode +				<< STA350_CONFC_OM_SHIFT); +	regmap_update_bits(sta350->regmap, STA350_CONFC, +			   STA350_CONFC_CSZ_MASK, +			   pdata->drop_compensation_ns +				<< STA350_CONFC_CSZ_SHIFT); +	regmap_update_bits(sta350->regmap, +			   STA350_CONFC, +			   STA350_CONFC_OCRB, +			   pdata->oc_warning_adjustment ? +				STA350_CONFC_OCRB : 0); + +	/* CONFE */ +	regmap_update_bits(sta350->regmap, STA350_CONFE, +			   STA350_CONFE_MPCV, +			   pdata->max_power_use_mpcc ? +				STA350_CONFE_MPCV : 0); +	regmap_update_bits(sta350->regmap, STA350_CONFE, +			   STA350_CONFE_MPC, +			   pdata->max_power_correction ? +				STA350_CONFE_MPC : 0); +	regmap_update_bits(sta350->regmap, STA350_CONFE, +			   STA350_CONFE_AME, +			   pdata->am_reduction_mode ? +				STA350_CONFE_AME : 0); +	regmap_update_bits(sta350->regmap, STA350_CONFE, +			   STA350_CONFE_PWMS, +			   pdata->odd_pwm_speed_mode ? +				STA350_CONFE_PWMS : 0); +	regmap_update_bits(sta350->regmap, STA350_CONFE, +			   STA350_CONFE_DCCV, +			   pdata->distortion_compensation ? +				STA350_CONFE_DCCV : 0); +	/*  CONFF */ +	regmap_update_bits(sta350->regmap, STA350_CONFF, +			   STA350_CONFF_IDE, +			   pdata->invalid_input_detect_mute ? +				STA350_CONFF_IDE : 0); +	regmap_update_bits(sta350->regmap, STA350_CONFF, +			   STA350_CONFF_OCFG_MASK, +			   pdata->output_conf +				<< STA350_CONFF_OCFG_SHIFT); + +	/* channel to output mapping */ +	regmap_update_bits(sta350->regmap, STA350_C1CFG, +			   STA350_CxCFG_OM_MASK, +			   pdata->ch1_output_mapping +				<< STA350_CxCFG_OM_SHIFT); +	regmap_update_bits(sta350->regmap, STA350_C2CFG, +			   STA350_CxCFG_OM_MASK, +			   pdata->ch2_output_mapping +				<< STA350_CxCFG_OM_SHIFT); +	regmap_update_bits(sta350->regmap, STA350_C3CFG, +			   STA350_CxCFG_OM_MASK, +			   pdata->ch3_output_mapping +				<< STA350_CxCFG_OM_SHIFT); + +	/* miscellaneous registers */ +	regmap_update_bits(sta350->regmap, STA350_MISC1, +			   STA350_MISC1_CPWMEN, +			   pdata->activate_mute_output ? +				STA350_MISC1_CPWMEN : 0); +	regmap_update_bits(sta350->regmap, STA350_MISC1, +			   STA350_MISC1_BRIDGOFF, +			   pdata->bridge_immediate_off ? +				STA350_MISC1_BRIDGOFF : 0); +	regmap_update_bits(sta350->regmap, STA350_MISC1, +			   STA350_MISC1_NSHHPEN, +			   pdata->noise_shape_dc_cut ? +				STA350_MISC1_NSHHPEN : 0); +	regmap_update_bits(sta350->regmap, STA350_MISC1, +			   STA350_MISC1_RPDNEN, +			   pdata->powerdown_master_vol ? +				STA350_MISC1_RPDNEN: 0); + +	regmap_update_bits(sta350->regmap, STA350_MISC2, +			   STA350_MISC2_PNDLSL_MASK, +			   pdata->powerdown_delay_divider +				<< STA350_MISC2_PNDLSL_SHIFT); + +	/* initialize coefficient shadow RAM with reset values */ +	for (i = 4; i <= 49; i += 5) +		sta350->coef_shadow[i] = 0x400000; +	for (i = 50; i <= 54; i++) +		sta350->coef_shadow[i] = 0x7fffff; +	sta350->coef_shadow[55] = 0x5a9df7; +	sta350->coef_shadow[56] = 0x7fffff; +	sta350->coef_shadow[59] = 0x7fffff; +	sta350->coef_shadow[60] = 0x400000; +	sta350->coef_shadow[61] = 0x400000; + +	sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +	/* Bias level configuration will have done an extra enable */ +	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); + +	return 0; +} + +static int sta350_remove(struct snd_soc_codec *codec) +{ +	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + +	sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); +	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); + +	return 0; +} + +static const struct snd_soc_codec_driver sta350_codec = { +	.probe =		sta350_probe, +	.remove =		sta350_remove, +	.suspend =		sta350_suspend, +	.resume =		sta350_resume, +	.set_bias_level =	sta350_set_bias_level, +	.controls =		sta350_snd_controls, +	.num_controls =		ARRAY_SIZE(sta350_snd_controls), +	.dapm_widgets =		sta350_dapm_widgets, +	.num_dapm_widgets =	ARRAY_SIZE(sta350_dapm_widgets), +	.dapm_routes =		sta350_dapm_routes, +	.num_dapm_routes =	ARRAY_SIZE(sta350_dapm_routes), +}; + +static const struct regmap_config sta350_regmap = { +	.reg_bits =		8, +	.val_bits =		8, +	.max_register =		STA350_MISC2, +	.reg_defaults =		sta350_regs, +	.num_reg_defaults =	ARRAY_SIZE(sta350_regs), +	.cache_type =		REGCACHE_RBTREE, +	.wr_table =		&sta350_write_regs, +	.rd_table =		&sta350_read_regs, +	.volatile_table =	&sta350_volatile_regs, +}; + +#ifdef CONFIG_OF +static const struct of_device_id st350_dt_ids[] = { +	{ .compatible = "st,sta350", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, st350_dt_ids); + +static const char * const sta350_ffx_modes[] = { +	[STA350_FFX_PM_DROP_COMP]		= "drop-compensation", +	[STA350_FFX_PM_TAPERED_COMP]		= "tapered-compensation", +	[STA350_FFX_PM_FULL_POWER]		= "full-power-mode", +	[STA350_FFX_PM_VARIABLE_DROP_COMP]	= "variable-drop-compensation", +}; + +static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350) +{ +	struct device_node *np = dev->of_node; +	struct sta350_platform_data *pdata; +	const char *ffx_power_mode; +	u16 tmp; +	u8 tmp8; + +	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return -ENOMEM; + +	of_property_read_u8(np, "st,output-conf", +			    &pdata->output_conf); +	of_property_read_u8(np, "st,ch1-output-mapping", +			    &pdata->ch1_output_mapping); +	of_property_read_u8(np, "st,ch2-output-mapping", +			    &pdata->ch2_output_mapping); +	of_property_read_u8(np, "st,ch3-output-mapping", +			    &pdata->ch3_output_mapping); + +	if (of_get_property(np, "st,thermal-warning-recovery", NULL)) +		pdata->thermal_warning_recovery = 1; +	if (of_get_property(np, "st,thermal-warning-adjustment", NULL)) +		pdata->thermal_warning_adjustment = 1; +	if (of_get_property(np, "st,fault-detect-recovery", NULL)) +		pdata->fault_detect_recovery = 1; + +	pdata->ffx_power_output_mode = STA350_FFX_PM_VARIABLE_DROP_COMP; +	if (!of_property_read_string(np, "st,ffx-power-output-mode", +				     &ffx_power_mode)) { +		int i, mode = -EINVAL; + +		for (i = 0; i < ARRAY_SIZE(sta350_ffx_modes); i++) +			if (!strcasecmp(ffx_power_mode, sta350_ffx_modes[i])) +				mode = i; + +		if (mode < 0) +			dev_warn(dev, "Unsupported ffx output mode: %s\n", +				 ffx_power_mode); +		else +			pdata->ffx_power_output_mode = mode; +	} + +	tmp = 140; +	of_property_read_u16(np, "st,drop-compensation-ns", &tmp); +	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20; + +	if (of_get_property(np, "st,overcurrent-warning-adjustment", NULL)) +		pdata->oc_warning_adjustment = 1; + +	/* CONFE */ +	if (of_get_property(np, "st,max-power-use-mpcc", NULL)) +		pdata->max_power_use_mpcc = 1; + +	if (of_get_property(np, "st,max-power-correction", NULL)) +		pdata->max_power_correction = 1; + +	if (of_get_property(np, "st,am-reduction-mode", NULL)) +		pdata->am_reduction_mode = 1; + +	if (of_get_property(np, "st,odd-pwm-speed-mode", NULL)) +		pdata->odd_pwm_speed_mode = 1; + +	if (of_get_property(np, "st,distortion-compensation", NULL)) +		pdata->distortion_compensation = 1; + +	/* CONFF */ +	if (of_get_property(np, "st,invalid-input-detect-mute", NULL)) +		pdata->invalid_input_detect_mute = 1; + +	/* MISC */ +	if (of_get_property(np, "st,activate-mute-output", NULL)) +		pdata->activate_mute_output = 1; + +	if (of_get_property(np, "st,bridge-immediate-off", NULL)) +		pdata->bridge_immediate_off = 1; + +	if (of_get_property(np, "st,noise-shape-dc-cut", NULL)) +		pdata->noise_shape_dc_cut = 1; + +	if (of_get_property(np, "st,powerdown-master-volume", NULL)) +		pdata->powerdown_master_vol = 1; + +	if (!of_property_read_u8(np, "st,powerdown-delay-divider", &tmp8)) { +		if (is_power_of_2(tmp8) && tmp8 >= 1 && tmp8 <= 128) +			pdata->powerdown_delay_divider = ilog2(tmp8); +		else +			dev_warn(dev, "Unsupported powerdown delay divider %d\n", +				 tmp8); +	} + +	sta350->pdata = pdata; + +	return 0; +} +#endif + +static int sta350_i2c_probe(struct i2c_client *i2c, +			    const struct i2c_device_id *id) +{ +	struct device *dev = &i2c->dev; +	struct sta350_priv *sta350; +	int ret, i; + +	sta350 = devm_kzalloc(dev, sizeof(struct sta350_priv), GFP_KERNEL); +	if (!sta350) +		return -ENOMEM; + +	mutex_init(&sta350->coeff_lock); +	sta350->pdata = dev_get_platdata(dev); + +#ifdef CONFIG_OF +	if (dev->of_node) { +		ret = sta350_probe_dt(dev, sta350); +		if (ret < 0) +			return ret; +	} +#endif + +	/* GPIOs */ +	sta350->gpiod_nreset = devm_gpiod_get(dev, "reset"); +	if (IS_ERR(sta350->gpiod_nreset)) { +		ret = PTR_ERR(sta350->gpiod_nreset); +		if (ret != -ENOENT && ret != -ENOSYS) +			return ret; + +		sta350->gpiod_nreset = NULL; +	} else { +		gpiod_direction_output(sta350->gpiod_nreset, 0); +	} + +	sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down"); +	if (IS_ERR(sta350->gpiod_power_down)) { +		ret = PTR_ERR(sta350->gpiod_power_down); +		if (ret != -ENOENT && ret != -ENOSYS) +			return ret; + +		sta350->gpiod_power_down = NULL; +	} else { +		gpiod_direction_output(sta350->gpiod_power_down, 0); +	} + +	/* regulators */ +	for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++) +		sta350->supplies[i].supply = sta350_supply_names[i]; + +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sta350->supplies), +				      sta350->supplies); +	if (ret < 0) { +		dev_err(dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	sta350->regmap = devm_regmap_init_i2c(i2c, &sta350_regmap); +	if (IS_ERR(sta350->regmap)) { +		ret = PTR_ERR(sta350->regmap); +		dev_err(dev, "Failed to init regmap: %d\n", ret); +		return ret; +	} + +	i2c_set_clientdata(i2c, sta350); + +	ret = snd_soc_register_codec(dev, &sta350_codec, &sta350_dai, 1); +	if (ret < 0) +		dev_err(dev, "Failed to register codec (%d)\n", ret); + +	return ret; +} + +static int sta350_i2c_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static const struct i2c_device_id sta350_i2c_id[] = { +	{ "sta350", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, sta350_i2c_id); + +static struct i2c_driver sta350_i2c_driver = { +	.driver = { +		.name = "sta350", +		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(st350_dt_ids), +	}, +	.probe =    sta350_i2c_probe, +	.remove =   sta350_i2c_remove, +	.id_table = sta350_i2c_id, +}; + +module_i2c_driver(sta350_i2c_driver); + +MODULE_DESCRIPTION("ASoC STA350 driver"); +MODULE_AUTHOR("Sven Brandau <info@brandau.biz>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sta350.h b/sound/soc/codecs/sta350.h new file mode 100644 index 00000000000..fb728529077 --- /dev/null +++ b/sound/soc/codecs/sta350.h @@ -0,0 +1,238 @@ +/* + * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system + * + * Copyright: 2011 Raumfeld GmbH + * Author: Sven Brandau <info@brandau.biz> + * + * based on code from: + *      Raumfeld GmbH + *        Johannes Stezenbach <js@sig21.net> + *	Wolfson Microelectronics PLC. + *	  Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + */ +#ifndef _ASOC_STA_350_H +#define _ASOC_STA_350_H + +/* STA50 register addresses */ + +#define STA350_REGISTER_COUNT	0x4D +#define STA350_COEF_COUNT 62 + +#define STA350_CONFA	0x00 +#define STA350_CONFB    0x01 +#define STA350_CONFC    0x02 +#define STA350_CONFD    0x03 +#define STA350_CONFE    0x04 +#define STA350_CONFF    0x05 +#define STA350_MMUTE    0x06 +#define STA350_MVOL     0x07 +#define STA350_C1VOL    0x08 +#define STA350_C2VOL    0x09 +#define STA350_C3VOL    0x0a +#define STA350_AUTO1    0x0b +#define STA350_AUTO2    0x0c +#define STA350_AUTO3    0x0d +#define STA350_C1CFG    0x0e +#define STA350_C2CFG    0x0f +#define STA350_C3CFG    0x10 +#define STA350_TONE     0x11 +#define STA350_L1AR     0x12 +#define STA350_L1ATRT   0x13 +#define STA350_L2AR     0x14 +#define STA350_L2ATRT   0x15 +#define STA350_CFADDR2  0x16 +#define STA350_B1CF1    0x17 +#define STA350_B1CF2    0x18 +#define STA350_B1CF3    0x19 +#define STA350_B2CF1    0x1a +#define STA350_B2CF2    0x1b +#define STA350_B2CF3    0x1c +#define STA350_A1CF1    0x1d +#define STA350_A1CF2    0x1e +#define STA350_A1CF3    0x1f +#define STA350_A2CF1    0x20 +#define STA350_A2CF2    0x21 +#define STA350_A2CF3    0x22 +#define STA350_B0CF1    0x23 +#define STA350_B0CF2    0x24 +#define STA350_B0CF3    0x25 +#define STA350_CFUD     0x26 +#define STA350_MPCC1    0x27 +#define STA350_MPCC2    0x28 +#define STA350_DCC1     0x29 +#define STA350_DCC2     0x2a +#define STA350_FDRC1    0x2b +#define STA350_FDRC2    0x2c +#define STA350_STATUS   0x2d +/* reserved: 0x2d - 0x30 */ +#define STA350_EQCFG    0x31 +#define STA350_EATH1    0x32 +#define STA350_ERTH1    0x33 +#define STA350_EATH2    0x34 +#define STA350_ERTH2    0x35 +#define STA350_CONFX    0x36 +#define STA350_SVCA     0x37 +#define STA350_SVCB     0x38 +#define STA350_RMS0A    0x39 +#define STA350_RMS0B    0x3a +#define STA350_RMS0C    0x3b +#define STA350_RMS1A    0x3c +#define STA350_RMS1B    0x3d +#define STA350_RMS1C    0x3e +#define STA350_EVOLRES  0x3f +/* reserved: 0x40 - 0x47 */ +#define STA350_NSHAPE   0x48 +#define STA350_CTXB4B1  0x49 +#define STA350_CTXB7B5  0x4a +#define STA350_MISC1    0x4b +#define STA350_MISC2    0x4c + +/* 0x00 CONFA */ +#define STA350_CONFA_MCS_MASK	0x03 +#define STA350_CONFA_MCS_SHIFT	0 +#define STA350_CONFA_IR_MASK	0x18 +#define STA350_CONFA_IR_SHIFT	3 +#define STA350_CONFA_TWRB	BIT(5) +#define STA350_CONFA_TWAB	BIT(6) +#define STA350_CONFA_FDRB	BIT(7) + +/* 0x01 CONFB */ +#define STA350_CONFB_SAI_MASK	0x0f +#define STA350_CONFB_SAI_SHIFT	0 +#define STA350_CONFB_SAIFB	BIT(4) +#define STA350_CONFB_DSCKE	BIT(5) +#define STA350_CONFB_C1IM	BIT(6) +#define STA350_CONFB_C2IM	BIT(7) + +/* 0x02 CONFC */ +#define STA350_CONFC_OM_MASK	0x03 +#define STA350_CONFC_OM_SHIFT	0 +#define STA350_CONFC_CSZ_MASK	0x3c +#define STA350_CONFC_CSZ_SHIFT	2 +#define STA350_CONFC_OCRB	BIT(7) + +/* 0x03 CONFD */ +#define STA350_CONFD_HPB_SHIFT	0 +#define STA350_CONFD_DEMP_SHIFT	1 +#define STA350_CONFD_DSPB_SHIFT	2 +#define STA350_CONFD_PSL_SHIFT	3 +#define STA350_CONFD_BQL_SHIFT	4 +#define STA350_CONFD_DRC_SHIFT	5 +#define STA350_CONFD_ZDE_SHIFT	6 +#define STA350_CONFD_SME_SHIFT	7 + +/* 0x04 CONFE */ +#define STA350_CONFE_MPCV	BIT(0) +#define STA350_CONFE_MPCV_SHIFT	0 +#define STA350_CONFE_MPC	BIT(1) +#define STA350_CONFE_MPC_SHIFT	1 +#define STA350_CONFE_NSBW	BIT(2) +#define STA350_CONFE_NSBW_SHIFT	2 +#define STA350_CONFE_AME	BIT(3) +#define STA350_CONFE_AME_SHIFT	3 +#define STA350_CONFE_PWMS	BIT(4) +#define STA350_CONFE_PWMS_SHIFT	4 +#define STA350_CONFE_DCCV	BIT(5) +#define STA350_CONFE_DCCV_SHIFT	5 +#define STA350_CONFE_ZCE	BIT(6) +#define STA350_CONFE_ZCE_SHIFT	6 +#define STA350_CONFE_SVE	BIT(7) +#define STA350_CONFE_SVE_SHIFT	7 + +/* 0x05 CONFF */ +#define STA350_CONFF_OCFG_MASK	0x03 +#define STA350_CONFF_OCFG_SHIFT	0 +#define STA350_CONFF_IDE	BIT(2) +#define STA350_CONFF_BCLE	BIT(3) +#define STA350_CONFF_LDTE	BIT(4) +#define STA350_CONFF_ECLE	BIT(5) +#define STA350_CONFF_PWDN	BIT(6) +#define STA350_CONFF_EAPD	BIT(7) + +/* 0x06 MMUTE */ +#define STA350_MMUTE_MMUTE		0x01 +#define STA350_MMUTE_MMUTE_SHIFT	0 +#define STA350_MMUTE_C1M		0x02 +#define STA350_MMUTE_C1M_SHIFT		1 +#define STA350_MMUTE_C2M		0x04 +#define STA350_MMUTE_C2M_SHIFT		2 +#define STA350_MMUTE_C3M		0x08 +#define STA350_MMUTE_C3M_SHIFT		3 +#define STA350_MMUTE_LOC_MASK		0xC0 +#define STA350_MMUTE_LOC_SHIFT		6 + +/* 0x0b AUTO1 */ +#define STA350_AUTO1_AMGC_MASK	0x30 +#define STA350_AUTO1_AMGC_SHIFT	4 + +/* 0x0c AUTO2 */ +#define STA350_AUTO2_AMAME	0x01 +#define STA350_AUTO2_AMAM_MASK	0x0e +#define STA350_AUTO2_AMAM_SHIFT	1 +#define STA350_AUTO2_XO_MASK	0xf0 +#define STA350_AUTO2_XO_SHIFT	4 + +/* 0x0d AUTO3 */ +#define STA350_AUTO3_PEQ_MASK	0x1f +#define STA350_AUTO3_PEQ_SHIFT	0 + +/* 0x0e 0x0f 0x10 CxCFG */ +#define STA350_CxCFG_TCB_SHIFT	0 +#define STA350_CxCFG_EQBP_SHIFT	1 +#define STA350_CxCFG_VBP_SHIFT	2 +#define STA350_CxCFG_BO_SHIFT	3 +#define STA350_CxCFG_LS_SHIFT	4 +#define STA350_CxCFG_OM_MASK	0xc0 +#define STA350_CxCFG_OM_SHIFT	6 + +/* 0x11 TONE */ +#define STA350_TONE_BTC_SHIFT	0 +#define STA350_TONE_TTC_SHIFT	4 + +/* 0x12 0x13 0x14 0x15 limiter attack/release */ +#define STA350_LxA_SHIFT	0 +#define STA350_LxR_SHIFT	4 + +/* 0x26 CFUD */ +#define STA350_CFUD_W1		0x01 +#define STA350_CFUD_WA		0x02 +#define STA350_CFUD_R1		0x04 +#define STA350_CFUD_RA		0x08 + + +/* biquad filter coefficient table offsets */ +#define STA350_C1_BQ_BASE	0 +#define STA350_C2_BQ_BASE	20 +#define STA350_CH_BQ_NUM	4 +#define STA350_BQ_NUM_COEF	5 +#define STA350_XO_HP_BQ_BASE	40 +#define STA350_XO_LP_BQ_BASE	45 +#define STA350_C1_PRESCALE	50 +#define STA350_C2_PRESCALE	51 +#define STA350_C1_POSTSCALE	52 +#define STA350_C2_POSTSCALE	53 +#define STA350_C3_POSTSCALE	54 +#define STA350_TW_POSTSCALE	55 +#define STA350_C1_MIX1		56 +#define STA350_C1_MIX2		57 +#define STA350_C2_MIX1		58 +#define STA350_C2_MIX2		59 +#define STA350_C3_MIX1		60 +#define STA350_C3_MIX2		61 + +/* miscellaneous register 1 */ +#define STA350_MISC1_CPWMEN	BIT(2) +#define STA350_MISC1_BRIDGOFF	BIT(5) +#define STA350_MISC1_NSHHPEN	BIT(6) +#define STA350_MISC1_RPDNEN	BIT(7) + +/* miscellaneous register 2 */ +#define STA350_MISC2_PNDLSL_MASK	0x1c +#define STA350_MISC2_PNDLSL_SHIFT	2 + +#endif /* _ASOC_STA_350_H */ diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 40c07be9b58..a40c4b0196a 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -141,7 +141,7 @@ static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary",  static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0);  static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0); -static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); +static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);  static const struct snd_kcontrol_new sta529_snd_controls[] = {  	SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0, @@ -193,8 +193,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,  		struct snd_pcm_hw_params *params,  		struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	int pdata, play_freq_val, record_freq_val;  	int bclk_to_fs_ratio; @@ -322,16 +321,6 @@ static struct snd_soc_dai_driver sta529_dai = {  static int sta529_probe(struct snd_soc_codec *codec)  { -	struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = sta529->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); - -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  	return 0; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index a5455c1aea4..53b810d23fe 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -62,25 +62,25 @@ static const char *stac9766_boost1[] = {"0dB", "10dB"};  static const char *stac9766_boost2[] = {"0dB", "20dB"};  static const char *stac9766_stereo_mic[] = {"Off", "On"}; -static const struct soc_enum stac9766_record_enum = -	SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux); -static const struct soc_enum stac9766_mono_enum = -	SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux); -static const struct soc_enum stac9766_mic_enum = -	SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux); -static const struct soc_enum stac9766_SPDIF_enum = -	SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux); -static const struct soc_enum stac9766_popbypass_enum = -	SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux); -static const struct soc_enum stac9766_record_all_enum = -	SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2, -			stac9766_record_all_mux); -static const struct soc_enum stac9766_boost1_enum = -	SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */ -static const struct soc_enum stac9766_boost2_enum = -	SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */ -static const struct soc_enum stac9766_stereo_mic_enum = -	SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic); +static SOC_ENUM_DOUBLE_DECL(stac9766_record_enum, +			    AC97_REC_SEL, 8, 0, stac9766_record_mux); +static SOC_ENUM_SINGLE_DECL(stac9766_mono_enum, +			    AC97_GENERAL_PURPOSE, 9, stac9766_mono_mux); +static SOC_ENUM_SINGLE_DECL(stac9766_mic_enum, +			    AC97_GENERAL_PURPOSE, 8, stac9766_mic_mux); +static SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum, +			    AC97_STAC_DA_CONTROL, 1, stac9766_SPDIF_mux); +static SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum, +			    AC97_GENERAL_PURPOSE, 15, stac9766_popbypass_mux); +static SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum, +			    AC97_STAC_ANALOG_SPECIAL, 12, +			    stac9766_record_all_mux); +static SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum, +			    AC97_MIC, 6, stac9766_boost1); /* 0/10dB */ +static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum, +			    AC97_STAC_ANALOG_SPECIAL, 2, stac9766_boost2); /* 0/20dB */ +static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum, +			    AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic);  static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0);  static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 6d31d88f720..d48491a4a19 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -37,6 +37,7 @@  #include <linux/i2c.h>  #include <linux/regmap.h>  #include <linux/spi/spi.h> +#include <linux/of.h>  #include <linux/of_device.h>  #include <linux/of_gpio.h>  #include <sound/pcm.h> @@ -244,6 +245,8 @@ struct tas5086_private {  	unsigned int	mclk, sclk;  	unsigned int	format;  	bool		deemph; +	unsigned int	charge_period; +	unsigned int	pwm_start_mid_z;  	/* Current sample rate for de-emphasis control */  	int		rate;  	/* GPIO driving Reset pin, if any */ @@ -269,7 +272,7 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec)  static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = priv->deemph; @@ -280,7 +283,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,  static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);  	priv->deemph = ucontrol->value.enumerated.item[0]; @@ -429,7 +432,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,  	default:  		dev_err(codec->dev, "Invalid bit width\n");  		return -EINVAL; -	}; +	}  	ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);  	if (ret < 0) @@ -456,6 +459,75 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)  	return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);  } +static void tas5086_reset(struct tas5086_private *priv) +{ +	if (gpio_is_valid(priv->gpio_nreset)) { +		/* Reset codec - minimum assertion time is 400ns */ +		gpio_direction_output(priv->gpio_nreset, 0); +		udelay(1); +		gpio_set_value(priv->gpio_nreset, 1); + +		/* Codec needs ~15ms to wake up */ +		msleep(15); +	} +} + +/* charge period values in microseconds */ +static const int tas5086_charge_period[] = { +	  13000,  16900,   23400,   31200,   41600,   54600,   72800,   96200, +	 130000, 156000,  234000,  312000,  416000,  546000,  728000,  962000, +	1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, +}; + +static int tas5086_init(struct device *dev, struct tas5086_private *priv) +{ +	int ret, i; + +	/* +	 * If any of the channels is configured to start in Mid-Z mode, +	 * configure 'part 1' of the PWM starts to use Mid-Z, and tell +	 * all configured mid-z channels to start start under 'part 1'. +	 */ +	if (priv->pwm_start_mid_z) +		regmap_write(priv->regmap, TAS5086_PWM_START, +			     TAS5086_PWM_START_MIDZ_FOR_START_1 | +				priv->pwm_start_mid_z); + +	/* lookup and set split-capacitor charge period */ +	if (priv->charge_period == 0) { +		regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); +	} else { +		i = index_in_array(tas5086_charge_period, +				   ARRAY_SIZE(tas5086_charge_period), +				   priv->charge_period); +		if (i >= 0) +			regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, +				     i + 0x08); +		else +			dev_warn(dev, +				 "Invalid split-cap charge period of %d ns.\n", +				 priv->charge_period); +	} + +	/* enable factory trim */ +	ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); +	if (ret < 0) +		return ret; + +	/* start all channels */ +	ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); +	if (ret < 0) +		return ret; + +	/* mute all channels for now */ +	ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, +			   TAS5086_SOFT_MUTE_ALL); +	if (ret < 0) +		return ret; + +	return 0; +} +  /* TAS5086 controls */  static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); @@ -691,14 +763,39 @@ static struct snd_soc_dai_driver tas5086_dai = {  };  #ifdef CONFIG_PM +static int tas5086_soc_suspend(struct snd_soc_codec *codec) +{ +	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); +	int ret; + +	/* Shut down all channels */ +	ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60); +	if (ret < 0) +		return ret; + +	return 0; +} +  static int tas5086_soc_resume(struct snd_soc_codec *codec)  {  	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); +	int ret; + +	tas5086_reset(priv); +	regcache_mark_dirty(priv->regmap); + +	ret = tas5086_init(codec->dev, priv); +	if (ret < 0) +		return ret; + +	ret = regcache_sync(priv->regmap); +	if (ret < 0) +		return ret; -	/* Restore codec state */ -	return regcache_sync(priv->regmap); +	return 0;  }  #else +#define tas5086_soc_suspend	NULL  #define tas5086_soc_resume	NULL  #endif /* CONFIG_PM */ @@ -710,23 +807,19 @@ static const struct of_device_id tas5086_dt_ids[] = {  MODULE_DEVICE_TABLE(of, tas5086_dt_ids);  #endif -/* charge period values in microseconds */ -static const int tas5086_charge_period[] = { -	  13000,  16900,   23400,   31200,   41600,   54600,   72800,   96200, -	 130000, 156000,  234000,  312000,  416000,  546000,  728000,  962000, -	1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, -}; -  static int tas5086_probe(struct snd_soc_codec *codec)  {  	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); -	int charge_period = 1300000; /* hardware default is 1300 ms */ -	u8 pwm_start_mid_z = 0;  	int i, ret; +	priv->pwm_start_mid_z = 0; +	priv->charge_period = 1300000; /* hardware default is 1300 ms */ +  	if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {  		struct device_node *of_node = codec->dev->of_node; -		of_property_read_u32(of_node, "ti,charge-period", &charge_period); + +		of_property_read_u32(of_node, "ti,charge-period", +				     &priv->charge_period);  		for (i = 0; i < 6; i++) {  			char name[25]; @@ -735,43 +828,11 @@ static int tas5086_probe(struct snd_soc_codec *codec)  				 "ti,mid-z-channel-%d", i + 1);  			if (of_get_property(of_node, name, NULL) != NULL) -				pwm_start_mid_z |= 1 << i; +				priv->pwm_start_mid_z |= 1 << i;  		}  	} -	/* -	 * If any of the channels is configured to start in Mid-Z mode, -	 * configure 'part 1' of the PWM starts to use Mid-Z, and tell -	 * all configured mid-z channels to start start under 'part 1'. -	 */ -	if (pwm_start_mid_z) -		regmap_write(priv->regmap, TAS5086_PWM_START, -			     TAS5086_PWM_START_MIDZ_FOR_START_1 | -				pwm_start_mid_z); - -	/* lookup and set split-capacitor charge period */ -	if (charge_period == 0) { -		regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); -	} else { -		i = index_in_array(tas5086_charge_period, -				   ARRAY_SIZE(tas5086_charge_period), -				   charge_period); -		if (i >= 0) -			regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, -				     i + 0x08); -		else -			dev_warn(codec->dev, -				 "Invalid split-cap charge period of %d ns.\n", -				 charge_period); -	} - -	/* enable factory trim */ -	ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); -	if (ret < 0) -		return ret; - -	/* start all channels */ -	ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); +	ret = tas5086_init(codec->dev, priv);  	if (ret < 0)  		return ret; @@ -780,12 +841,6 @@ static int tas5086_probe(struct snd_soc_codec *codec)  	if (ret < 0)  		return ret; -	/* mute all channels for now */ -	ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, -			   TAS5086_SOFT_MUTE_ALL); -	if (ret < 0) -		return ret; -  	return 0;  } @@ -803,6 +858,7 @@ static int tas5086_remove(struct snd_soc_codec *codec)  static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {  	.probe			= tas5086_probe,  	.remove			= tas5086_remove, +	.suspend		= tas5086_soc_suspend,  	.resume			= tas5086_soc_resume,  	.controls		= tas5086_controls,  	.num_controls		= ARRAY_SIZE(tas5086_controls), @@ -862,17 +918,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,  		if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))  			gpio_nreset = -EINVAL; -	if (gpio_is_valid(gpio_nreset)) { -		/* Reset codec - minimum assertion time is 400ns */ -		gpio_direction_output(gpio_nreset, 0); -		udelay(1); -		gpio_set_value(gpio_nreset, 1); - -		/* Codec needs ~15ms to wake up */ -		msleep(15); -	} -  	priv->gpio_nreset = gpio_nreset; +	tas5086_reset(priv);  	/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */  	ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c new file mode 100644 index 00000000000..f1370199548 --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -0,0 +1,67 @@ +/* + * ALSA SoC TLV320AIC23 codec driver I2C interface + * + * Author:      Arun KS, <arunks@mistralsolutions.com> + * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd., + * + * Based on sound/soc/codecs/wm8731.c by Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "tlv320aic23.h" + +static int tlv320aic23_i2c_probe(struct i2c_client *i2c, +				 const struct i2c_device_id *i2c_id) +{ +	struct regmap *regmap; + +	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) +		return -EINVAL; + +	regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); +	return tlv320aic23_probe(&i2c->dev, regmap); +} + +static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); +	return 0; +} + +static const struct i2c_device_id tlv320aic23_id[] = { +	{"tlv320aic23", 0}, +	{} +}; + +MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); + +static const struct of_device_id tlv320aic23_of_match[] = { +	{ .compatible = "ti,tlv320aic23", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, tlv320aic23_of_match); + +static struct i2c_driver tlv320aic23_i2c_driver = { +	.driver = { +		   .name = "tlv320aic23-codec", +		   .of_match_table = of_match_ptr(tlv320aic23_of_match), +		   }, +	.probe = tlv320aic23_i2c_probe, +	.remove = __exit_p(tlv320aic23_i2c_remove), +	.id_table = tlv320aic23_id, +}; + +module_i2c_driver(tlv320aic23_i2c_driver); + +MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C"); +MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c new file mode 100644 index 00000000000..3b387e41d75 --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-spi.c @@ -0,0 +1,56 @@ +/* + * ALSA SoC TLV320AIC23 codec driver SPI interface + * + * Author:      Arun KS, <arunks@mistralsolutions.com> + * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd., + * + * Based on sound/soc/codecs/wm8731.c by Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <sound/soc.h> + +#include "tlv320aic23.h" + +static int aic23_spi_probe(struct spi_device *spi) +{ +	int ret; +	struct regmap *regmap; + +	dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n"); + +	spi->mode = SPI_MODE_0; +	ret = spi_setup(spi); +	if (ret < 0) +		return ret; + +	regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap); +	return tlv320aic23_probe(&spi->dev, regmap); +} + +static int aic23_spi_remove(struct spi_device *spi) +{ +	snd_soc_unregister_codec(&spi->dev); +	return 0; +} + +static struct spi_driver aic23_spi = { +	.driver = { +		.name = "tlv320aic23", +		.owner = THIS_MODULE, +	}, +	.probe = aic23_spi_probe, +	.remove = aic23_spi_remove, +}; + +module_spi_driver(aic23_spi); + +MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI"); +MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 31762ebdd77..686b8b85b95 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -23,7 +23,7 @@  #include <linux/init.h>  #include <linux/delay.h>  #include <linux/pm.h> -#include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -37,26 +37,43 @@  /*   * AIC23 register cache   */ -static const u16 tlv320aic23_reg[] = { -	0x0097, 0x0097, 0x00F9, 0x00F9,	/* 0 */ -	0x001A, 0x0004, 0x0007, 0x0001,	/* 4 */ -	0x0020, 0x0000, 0x0000, 0x0000,	/* 8 */ -	0x0000, 0x0000, 0x0000, 0x0000,	/* 12 */ +static const struct reg_default tlv320aic23_reg[] = { +	{  0, 0x0097 }, +	{  1, 0x0097 }, +	{  2, 0x00F9 }, +	{  3, 0x00F9 }, +	{  4, 0x001A }, +	{  5, 0x0004 }, +	{  6, 0x0007 }, +	{  7, 0x0001 }, +	{  8, 0x0020 }, +	{  9, 0x0000 },  }; +const struct regmap_config tlv320aic23_regmap = { +	.reg_bits = 7, +	.val_bits = 9, + +	.max_register = TLV320AIC23_RESET, +	.reg_defaults = tlv320aic23_reg, +	.num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg), +	.cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL(tlv320aic23_regmap); +  static const char *rec_src_text[] = { "Line", "Mic" };  static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const struct soc_enum rec_src_enum = -	SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); +static SOC_ENUM_SINGLE_DECL(rec_src_enum, +			    TLV320AIC23_ANLG, 2, rec_src_text);  static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =  SOC_DAPM_ENUM("Input Select", rec_src_enum); -static const struct soc_enum tlv320aic23_rec_src = -	SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); -static const struct soc_enum tlv320aic23_deemph = -	SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text); +static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src, +			    TLV320AIC23_ANLG, 2, rec_src_text); +static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph, +			    TLV320AIC23_DIGT, 1, deemph_text);  static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);  static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); @@ -65,7 +82,7 @@ static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);  static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	u16 val, reg;  	val = (ucontrol->value.integer.value[0] & 0x07); @@ -88,7 +105,7 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,  static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	u16 val;  	val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0); @@ -171,7 +188,7 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {  /* AIC23 driver data */  struct aic23 { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	int mclk;  	int requested_adc;  	int requested_dac; @@ -383,7 +400,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,  	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);  	/* deactivate */ -	if (!codec->active) { +	if (!snd_soc_codec_is_active(codec)) {  		udelay(50);  		snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);  	} @@ -532,36 +549,19 @@ static int tlv320aic23_suspend(struct snd_soc_codec *codec)  static int tlv320aic23_resume(struct snd_soc_codec *codec)  { -	snd_soc_cache_sync(codec); +	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); +	regcache_mark_dirty(aic23->regmap); +	regcache_sync(aic23->regmap);  	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  	return 0;  } -static int tlv320aic23_probe(struct snd_soc_codec *codec) +static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)  { -	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Reset codec */  	snd_soc_write(codec, TLV320AIC23_RESET, 0); -	/* Write the register default value to cache for reserved registers, -	 * so the write to the these registers are suppressed by the cache -	 * restore code when it skips writes of default registers. -	 */ -	snd_soc_cache_write(codec, 0x0A, 0); -	snd_soc_cache_write(codec, 0x0B, 0); -	snd_soc_cache_write(codec, 0x0C, 0); -	snd_soc_cache_write(codec, 0x0D, 0); -	snd_soc_cache_write(codec, 0x0E, 0); -  	/* power on device */  	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -586,9 +586,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)  	snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1); -	snd_soc_add_codec_controls(codec, tlv320aic23_snd_controls, -				ARRAY_SIZE(tlv320aic23_snd_controls)); -  	return 0;  } @@ -599,90 +596,38 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec)  }  static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { -	.reg_cache_size = ARRAY_SIZE(tlv320aic23_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = tlv320aic23_reg, -	.probe = tlv320aic23_probe, +	.probe = tlv320aic23_codec_probe,  	.remove = tlv320aic23_remove,  	.suspend = tlv320aic23_suspend,  	.resume = tlv320aic23_resume,  	.set_bias_level = tlv320aic23_set_bias_level, +	.controls = tlv320aic23_snd_controls, +	.num_controls = ARRAY_SIZE(tlv320aic23_snd_controls),  	.dapm_widgets = tlv320aic23_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),  	.dapm_routes = tlv320aic23_intercon,  	.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -/* - * If the i2c layer weren't so broken, we could pass this kind of data - * around - */ -static int tlv320aic23_codec_probe(struct i2c_client *i2c, -				   const struct i2c_device_id *i2c_id) +int tlv320aic23_probe(struct device *dev, struct regmap *regmap)  {  	struct aic23 *aic23; -	int ret; -	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) -		return -EINVAL; +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); -	aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL); +	aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL);  	if (aic23 == NULL)  		return -ENOMEM; -	i2c_set_clientdata(i2c, aic23); -	aic23->control_type = SND_SOC_I2C; - -	ret =  snd_soc_register_codec(&i2c->dev, -			&soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); -	return ret; -} -static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) -{ -	snd_soc_unregister_codec(&i2c->dev); -	return 0; -} - -static const struct i2c_device_id tlv320aic23_id[] = { -	{"tlv320aic23", 0}, -	{} -}; +	aic23->regmap = regmap; -MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); +	dev_set_drvdata(dev, aic23); -static struct i2c_driver tlv320aic23_i2c_driver = { -	.driver = { -		   .name = "tlv320aic23-codec", -		   }, -	.probe = tlv320aic23_codec_probe, -	.remove = __exit_p(tlv320aic23_i2c_remove), -	.id_table = tlv320aic23_id, -}; - -#endif - -static int __init tlv320aic23_modinit(void) -{ -	int ret; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	ret = i2c_add_driver(&tlv320aic23_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n", -		       ret); -	} -#endif -	return ret; -} -module_init(tlv320aic23_modinit); - -static void __exit tlv320aic23_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	i2c_del_driver(&tlv320aic23_i2c_driver); -#endif +	return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23, +				      &tlv320aic23_dai, 1);  } -module_exit(tlv320aic23_exit); +EXPORT_SYMBOL(tlv320aic23_probe);  MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");  MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h index e804120bd3d..3a7235a04a8 100644 --- a/sound/soc/codecs/tlv320aic23.h +++ b/sound/soc/codecs/tlv320aic23.h @@ -12,6 +12,12 @@  #ifndef _TLV320AIC23_H  #define _TLV320AIC23_H +struct device; +struct regmap_config; + +extern const struct regmap_config tlv320aic23_regmap; +int tlv320aic23_probe(struct device *dev, struct regmap *regmap); +  /* Codec TLV320AIC23 */  #define TLV320AIC23_LINVOL		0x00  #define TLV320AIC23_RINVOL		0x01 diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 7b8f3d965f4..43069de3d56 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");  /* AIC26 driver private data */  struct aic26 {  	struct spi_device *spi; +	struct regmap *regmap;  	struct snd_soc_codec *codec;  	int master;  	int datfm; @@ -40,85 +41,6 @@ struct aic26 {  	int keyclick_len;  }; -/* --------------------------------------------------------------------- - * Register access routines - */ -static unsigned int aic26_reg_read(struct snd_soc_codec *codec, -				   unsigned int reg) -{ -	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec); -	u16 *cache = codec->reg_cache; -	u16 cmd, value; -	u8 buffer[2]; -	int rc; - -	if (reg >= AIC26_NUM_REGS) { -		WARN_ON_ONCE(1); -		return 0; -	} - -	/* Do SPI transfer; first 16bits are command; remaining is -	 * register contents */ -	cmd = AIC26_READ_COMMAND_WORD(reg); -	buffer[0] = (cmd >> 8) & 0xff; -	buffer[1] = cmd & 0xff; -	rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2); -	if (rc) { -		dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); -		return -EIO; -	} -	value = (buffer[0] << 8) | buffer[1]; - -	/* Update the cache before returning with the value */ -	cache[reg] = value; -	return value; -} - -static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec, -					 unsigned int reg) -{ -	u16 *cache = codec->reg_cache; - -	if (reg >= AIC26_NUM_REGS) { -		WARN_ON_ONCE(1); -		return 0; -	} - -	return cache[reg]; -} - -static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, -			   unsigned int value) -{ -	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec); -	u16 *cache = codec->reg_cache; -	u16 cmd; -	u8 buffer[4]; -	int rc; - -	if (reg >= AIC26_NUM_REGS) { -		WARN_ON_ONCE(1); -		return -EINVAL; -	} - -	/* Do SPI transfer; first 16bits are command; remaining is data -	 * to write into register */ -	cmd = AIC26_WRITE_COMMAND_WORD(reg); -	buffer[0] = (cmd >> 8) & 0xff; -	buffer[1] = cmd & 0xff; -	buffer[2] = value >> 8; -	buffer[3] = value; -	rc = spi_write(aic26->spi, buffer, 4); -	if (rc) { -		dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); -		return -EIO; -	} - -	/* update cache before returning */ -	cache[reg] = value; -	return 0; -} -  static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = {  SND_SOC_DAPM_INPUT("MICIN"),  SND_SOC_DAPM_INPUT("AUX"), @@ -195,19 +117,15 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,  	snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg);  	/* Audio Control 3 (master mode, fsref rate) */ -	reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3); -	reg &= ~0xf800;  	if (aic26->master) -		reg |= 0x0800; +		reg = 0x0800;  	if (fsref == 48000) -		reg |= 0x2000; -	snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg); +		reg = 0x2000; +	snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL3, 0xf800, reg);  	/* Audio Control 1 (FSref divisor) */ -	reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1); -	reg &= ~0x0fff; -	reg |= wlen | aic26->datfm | (divisor << 3) | divisor; -	snd_soc_write(codec, AIC26_REG_AUDIO_CTRL1, reg); +	reg = wlen | aic26->datfm | (divisor << 3) | divisor; +	snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL1, 0xfff, reg);  	return 0;  } @@ -219,16 +137,16 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute)  {  	struct snd_soc_codec *codec = dai->codec;  	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec); -	u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN); +	u16 reg;  	dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",  		dai, mute);  	if (mute) -		reg |= 0x8080; +		reg = 0x8080;  	else -		reg &= ~0x8080; -	snd_soc_write(codec, AIC26_REG_DAC_GAIN, reg); +		reg = 0; +	snd_soc_update_bits(codec, AIC26_REG_DAC_GAIN, 0x8000, reg);  	return 0;  } @@ -320,8 +238,9 @@ static struct snd_soc_dai_driver aic26_dai = {   * ALSA controls   */  static const char *aic26_capture_src_text[] = {"Mic", "Aux"}; -static const struct soc_enum aic26_capture_src_enum = -	SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text); +static SOC_ENUM_SINGLE_DECL(aic26_capture_src_enum, +			    AIC26_REG_AUDIO_CTRL1, 12, +			    aic26_capture_src_text);  static const struct snd_kcontrol_new aic26_snd_controls[] = {  	/* Output */ @@ -346,7 +265,7 @@ static ssize_t aic26_keyclick_show(struct device *dev,  	struct aic26 *aic26 = dev_get_drvdata(dev);  	int val, amp, freq, len; -	val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2); +	val = snd_soc_read(aic26->codec, AIC26_REG_AUDIO_CTRL2);  	amp = (val >> 12) & 0x7;  	freq = (125 << ((val >> 8) & 0x7)) >> 1;  	len = 2 * (1 + ((val >> 4) & 0xf)); @@ -360,11 +279,9 @@ static ssize_t aic26_keyclick_set(struct device *dev,  				  const char *buf, size_t count)  {  	struct aic26 *aic26 = dev_get_drvdata(dev); -	int val; -	val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2); -	val |= 0x8000; -	snd_soc_write(aic26->codec, AIC26_REG_AUDIO_CTRL2, val); +	snd_soc_update_bits(aic26->codec, AIC26_REG_AUDIO_CTRL2, +			    0x8000, 0x800);  	return count;  } @@ -377,7 +294,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);  static int aic26_probe(struct snd_soc_codec *codec)  {  	struct aic26 *aic26 = dev_get_drvdata(codec->dev); -	int ret, err, i, reg; +	int ret, reg;  	aic26->codec = codec; @@ -393,37 +310,30 @@ static int aic26_probe(struct snd_soc_codec *codec)  	reg |= 0x0800; /* set master mode */  	snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg); -	/* Fill register cache */ -	for (i = 0; i < codec->driver->reg_cache_size; i++) -		snd_soc_read(codec, i); -  	/* Register the sysfs files for debugging */  	/* Create SysFS files */  	ret = device_create_file(codec->dev, &dev_attr_keyclick);  	if (ret)  		dev_info(codec->dev, "error creating sysfs files\n"); -	/* register controls */ -	dev_dbg(codec->dev, "Registering controls\n"); -	err = snd_soc_add_codec_controls(codec, aic26_snd_controls, -			ARRAY_SIZE(aic26_snd_controls)); -	WARN_ON(err < 0); -  	return 0;  }  static struct snd_soc_codec_driver aic26_soc_codec_dev = {  	.probe = aic26_probe, -	.read = aic26_reg_read, -	.write = aic26_reg_write, -	.reg_cache_size = AIC26_NUM_REGS, -	.reg_word_size = sizeof(u16), +	.controls = aic26_snd_controls, +	.num_controls = ARRAY_SIZE(aic26_snd_controls),  	.dapm_widgets = tlv320aic26_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets),  	.dapm_routes = tlv320aic26_dapm_routes,  	.num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes),  }; +static const struct regmap_config aic26_regmap = { +	.reg_bits = 16, +	.val_bits = 16, +}; +  /* ---------------------------------------------------------------------   * SPI device portion of driver: probe and release routines and SPI   * 				 driver registration. @@ -440,6 +350,10 @@ static int aic26_spi_probe(struct spi_device *spi)  	if (!aic26)  		return -ENOMEM; +	aic26->regmap = devm_regmap_init_spi(spi, &aic26_regmap); +	if (IS_ERR(aic26->regmap)) +		return PTR_ERR(aic26->regmap); +  	/* Initialize the driver data */  	aic26->spi = spi;  	dev_set_drvdata(&spi->dev, aic26); diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h index 67f19c3bebe..629b85e7540 100644 --- a/sound/soc/codecs/tlv320aic26.h +++ b/sound/soc/codecs/tlv320aic26.h @@ -9,10 +9,7 @@  #define _TLV320AIC16_H_  /* AIC26 Registers */ -#define AIC26_READ_COMMAND_WORD(addr)	((1 << 15) | (addr << 5)) -#define AIC26_WRITE_COMMAND_WORD(addr)	((0 << 15) | (addr << 5)) -#define AIC26_PAGE_ADDR(page, offset)	((page << 6) | offset) -#define AIC26_NUM_REGS			AIC26_PAGE_ADDR(3, 0) +#define AIC26_PAGE_ADDR(page, offset)	((page << 11) | offset << 5)  /* Page 0: Auxiliary data registers */  #define AIC26_REG_BAT1			AIC26_PAGE_ADDR(0, 0x05) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c new file mode 100644 index 00000000000..23419109eca --- /dev/null +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -0,0 +1,1281 @@ +/* + * ALSA SoC TLV320AIC31XX codec driver + * + * Copyright (C) 2014 Texas Instruments, Inc. + * + * Author: Jyri Sarha <jsarha@ti.com> + * + * Based on ground work by: Ajit Kulkarni <x0175765@ti.com> + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * The TLV320AIC31xx series of audio codec is a low-power, highly integrated + * high performance codec which provides a stereo DAC, a mono ADC, + * and mono/stereo Class-D speaker driver. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <dt-bindings/sound/tlv320aic31xx-micbias.h> + +#include "tlv320aic31xx.h" + +static const struct reg_default aic31xx_reg_defaults[] = { +	{ AIC31XX_CLKMUX, 0x00 }, +	{ AIC31XX_PLLPR, 0x11 }, +	{ AIC31XX_PLLJ, 0x04 }, +	{ AIC31XX_PLLDMSB, 0x00 }, +	{ AIC31XX_PLLDLSB, 0x00 }, +	{ AIC31XX_NDAC, 0x01 }, +	{ AIC31XX_MDAC, 0x01 }, +	{ AIC31XX_DOSRMSB, 0x00 }, +	{ AIC31XX_DOSRLSB, 0x80 }, +	{ AIC31XX_NADC, 0x01 }, +	{ AIC31XX_MADC, 0x01 }, +	{ AIC31XX_AOSR, 0x80 }, +	{ AIC31XX_IFACE1, 0x00 }, +	{ AIC31XX_DATA_OFFSET, 0x00 }, +	{ AIC31XX_IFACE2, 0x00 }, +	{ AIC31XX_BCLKN, 0x01 }, +	{ AIC31XX_DACSETUP, 0x14 }, +	{ AIC31XX_DACMUTE, 0x0c }, +	{ AIC31XX_LDACVOL, 0x00 }, +	{ AIC31XX_RDACVOL, 0x00 }, +	{ AIC31XX_ADCSETUP, 0x00 }, +	{ AIC31XX_ADCFGA, 0x80 }, +	{ AIC31XX_ADCVOL, 0x00 }, +	{ AIC31XX_HPDRIVER, 0x04 }, +	{ AIC31XX_SPKAMP, 0x06 }, +	{ AIC31XX_DACMIXERROUTE, 0x00 }, +	{ AIC31XX_LANALOGHPL, 0x7f }, +	{ AIC31XX_RANALOGHPR, 0x7f }, +	{ AIC31XX_LANALOGSPL, 0x7f }, +	{ AIC31XX_RANALOGSPR, 0x7f }, +	{ AIC31XX_HPLGAIN, 0x02 }, +	{ AIC31XX_HPRGAIN, 0x02 }, +	{ AIC31XX_SPLGAIN, 0x00 }, +	{ AIC31XX_SPRGAIN, 0x00 }, +	{ AIC31XX_MICBIAS, 0x00 }, +	{ AIC31XX_MICPGA, 0x80 }, +	{ AIC31XX_MICPGAPI, 0x00 }, +	{ AIC31XX_MICPGAMI, 0x00 }, +}; + +static bool aic31xx_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case AIC31XX_PAGECTL: /* regmap implementation requires this */ +	case AIC31XX_RESET: /* always clears after write */ +	case AIC31XX_OT_FLAG: +	case AIC31XX_ADCFLAG: +	case AIC31XX_DACFLAG1: +	case AIC31XX_DACFLAG2: +	case AIC31XX_OFFLAG: /* Sticky interrupt flags */ +	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */ +	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */ +	case AIC31XX_INTRDACFLAG2: +	case AIC31XX_INTRADCFLAG2: +		return true; +	} +	return false; +} + +static bool aic31xx_writeable(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case AIC31XX_OT_FLAG: +	case AIC31XX_ADCFLAG: +	case AIC31XX_DACFLAG1: +	case AIC31XX_DACFLAG2: +	case AIC31XX_OFFLAG: /* Sticky interrupt flags */ +	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */ +	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */ +	case AIC31XX_INTRDACFLAG2: +	case AIC31XX_INTRADCFLAG2: +		return false; +	} +	return true; +} + +static const struct regmap_range_cfg aic31xx_ranges[] = { +	{ +		.range_min = 0, +		.range_max = 12 * 128, +		.selector_reg = AIC31XX_PAGECTL, +		.selector_mask = 0xff, +		.selector_shift = 0, +		.window_start = 0, +		.window_len = 128, +	}, +}; + +static const struct regmap_config aic31xx_i2c_regmap = { +	.reg_bits = 8, +	.val_bits = 8, +	.writeable_reg = aic31xx_writeable, +	.volatile_reg = aic31xx_volatile, +	.reg_defaults = aic31xx_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(aic31xx_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +	.ranges = aic31xx_ranges, +	.num_ranges = ARRAY_SIZE(aic31xx_ranges), +	.max_register = 12 * 128, +}; + +#define AIC31XX_NUM_SUPPLIES	6 +static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = { +	"HPVDD", +	"SPRVDD", +	"SPLVDD", +	"AVDD", +	"IOVDD", +	"DVDD", +}; + +struct aic31xx_disable_nb { +	struct notifier_block nb; +	struct aic31xx_priv *aic31xx; +}; + +struct aic31xx_priv { +	struct snd_soc_codec *codec; +	u8 i2c_regs_status; +	struct device *dev; +	struct regmap *regmap; +	struct aic31xx_pdata pdata; +	struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; +	struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; +	unsigned int sysclk; +	int rate_div_line; +}; + +struct aic31xx_rate_divs { +	u32 mclk; +	u32 rate; +	u8 p_val; +	u8 pll_j; +	u16 pll_d; +	u16 dosr; +	u8 ndac; +	u8 mdac; +	u8 aosr; +	u8 nadc; +	u8 madc; +}; + +/* ADC dividers can be disabled by cofiguring them to 0 */ +static const struct aic31xx_rate_divs aic31xx_divs[] = { +	/* mclk      rate  pll: p  j	 d     dosr ndac mdac  aors nadc madc */ +	/* 8k rate */ +	{12000000,   8000,	1, 8, 1920,	128,  48,  2,	128,  48,  2}, +	{24000000,   8000,	2, 8, 1920,	128,  48,  2,	128,  48,  2}, +	{25000000,   8000,	2, 7, 8643,	128,  48,  2,	128,  48,  2}, +	/* 11.025k rate */ +	{12000000,  11025,	1, 7, 5264,	128,  32,  2,	128,  32,  2}, +	{24000000,  11025,	2, 7, 5264,	128,  32,  2,	128,  32,  2}, +	{25000000,  11025,	2, 7, 2253,	128,  32,  2,	128,  32,  2}, +	/* 16k rate */ +	{12000000,  16000,	1, 8, 1920,	128,  24,  2,	128,  24,  2}, +	{24000000,  16000,	2, 8, 1920,	128,  24,  2,	128,  24,  2}, +	{25000000,  16000,	2, 7, 8643,	128,  24,  2,	128,  24,  2}, +	/* 22.05k rate */ +	{12000000,  22050,	1, 7, 5264,	128,  16,  2,	128,  16,  2}, +	{24000000,  22050,	2, 7, 5264,	128,  16,  2,	128,  16,  2}, +	{25000000,  22050,	2, 7, 2253,	128,  16,  2,	128,  16,  2}, +	/* 32k rate */ +	{12000000,  32000,	1, 8, 1920,	128,  12,  2,	128,  12,  2}, +	{24000000,  32000,	2, 8, 1920,	128,  12,  2,	128,  12,  2}, +	{25000000,  32000,	2, 7, 8643,	128,  12,  2,	128,  12,  2}, +	/* 44.1k rate */ +	{12000000,  44100,	1, 7, 5264,	128,   8,  2,	128,   8,  2}, +	{24000000,  44100,	2, 7, 5264,	128,   8,  2,	128,   8,  2}, +	{25000000,  44100,	2, 7, 2253,	128,   8,  2,	128,   8,  2}, +	/* 48k rate */ +	{12000000,  48000,	1, 8, 1920,	128,   8,  2,	128,   8,  2}, +	{24000000,  48000,	2, 8, 1920,	128,   8,  2,	128,   8,  2}, +	{25000000,  48000,	2, 7, 8643,	128,   8,  2,	128,   8,  2}, +	/* 88.2k rate */ +	{12000000,  88200,	1, 7, 5264,	 64,   8,  2,	 64,   8,  2}, +	{24000000,  88200,	2, 7, 5264,	 64,   8,  2,	 64,   8,  2}, +	{25000000,  88200,	2, 7, 2253,	 64,   8,  2,	 64,   8,  2}, +	/* 96k rate */ +	{12000000,  96000,	1, 8, 1920,	 64,   8,  2,	 64,   8,  2}, +	{24000000,  96000,	2, 8, 1920,	 64,   8,  2,	 64,   8,  2}, +	{25000000,  96000,	2, 7, 8643,	 64,   8,  2,	 64,   8,  2}, +	/* 176.4k rate */ +	{12000000, 176400,	1, 7, 5264,	 32,   8,  2,	 32,   8,  2}, +	{24000000, 176400,	2, 7, 5264,	 32,   8,  2,	 32,   8,  2}, +	{25000000, 176400,	2, 7, 2253,	 32,   8,  2,	 32,   8,  2}, +	/* 192k rate */ +	{12000000, 192000,	1, 8, 1920,	 32,   8,  2,	 32,   8,  2}, +	{24000000, 192000,	2, 8, 1920,	 32,   8,  2,	 32,   8,  2}, +	{25000000, 192000,	2, 7, 8643,	 32,   8,  2,	 32,   8,  2}, +}; + +static const char * const ldac_in_text[] = { +	"Off", "Left Data", "Right Data", "Mono" +}; + +static const char * const rdac_in_text[] = { +	"Off", "Right Data", "Left Data", "Mono" +}; + +static SOC_ENUM_SINGLE_DECL(ldac_in_enum, AIC31XX_DACSETUP, 4, ldac_in_text); + +static SOC_ENUM_SINGLE_DECL(rdac_in_enum, AIC31XX_DACSETUP, 2, rdac_in_text); + +static const char * const mic_select_text[] = { +	"Off", "FFR 10 Ohm", "FFR 20 Ohm", "FFR 40 Ohm" +}; + +static const +SOC_ENUM_SINGLE_DECL(mic1lp_p_enum, AIC31XX_MICPGAPI, 6, mic_select_text); +static const +SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4, mic_select_text); +static const +SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2, mic_select_text); + +static const +SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text); +static const +SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4, mic_select_text); + +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0); +static const DECLARE_TLV_DB_SCALE(adc_fgain_tlv, 0, 10, 0); +static const DECLARE_TLV_DB_SCALE(adc_cgain_tlv, -2000, 50, 0); +static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 0, 50, 0); +static const DECLARE_TLV_DB_SCALE(hp_drv_tlv, 0, 100, 0); +static const DECLARE_TLV_DB_SCALE(class_D_drv_tlv, 600, 600, 0); +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -6350, 50, 0); +static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0); + +/* + * controls to be exported to the user space + */ +static const struct snd_kcontrol_new aic31xx_snd_controls[] = { +	SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL, +			   AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv), + +	SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1, +		       adc_fgain_tlv), + +	SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1), +	SOC_DOUBLE_R_S_TLV("ADC Capture Volume", AIC31XX_ADCVOL, AIC31XX_ADCVOL, +			   0, -24, 40, 6, 0, adc_cgain_tlv), + +	SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0, +		       119, 0, mic_pga_tlv), + +	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN, +		     AIC31XX_HPRGAIN, 2, 1, 0), +	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN, +			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv), + +	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL, +			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv), +}; + +static const struct snd_kcontrol_new aic311x_snd_controls[] = { +	SOC_DOUBLE_R("Speaker Driver Playback Switch", AIC31XX_SPLGAIN, +		     AIC31XX_SPRGAIN, 2, 1, 0), +	SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN, +			 AIC31XX_SPRGAIN, 3, 3, 0, class_D_drv_tlv), + +	SOC_DOUBLE_R_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL, +			 AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv), +}; + +static const struct snd_kcontrol_new aic310x_snd_controls[] = { +	SOC_SINGLE("Speaker Driver Playback Switch", AIC31XX_SPLGAIN, +		   2, 1, 0), +	SOC_SINGLE_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN, +		       3, 3, 0, class_D_drv_tlv), + +	SOC_SINGLE_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL, +		       0, 0x7F, 1, sp_vol_tlv), +}; + +static const struct snd_kcontrol_new ldac_in_control = +	SOC_DAPM_ENUM("DAC Left Input", ldac_in_enum); + +static const struct snd_kcontrol_new rdac_in_control = +	SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum); + +static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg, +			     unsigned int mask, unsigned int wbits, int sleep, +			     int count) +{ +	unsigned int bits; +	int counter = count; +	int ret = regmap_read(aic31xx->regmap, reg, &bits); +	while ((bits & mask) != wbits && counter && !ret) { +		usleep_range(sleep, sleep * 2); +		ret = regmap_read(aic31xx->regmap, reg, &bits); +		counter--; +	} +	if ((bits & mask) != wbits) { +		dev_err(aic31xx->dev, +			"%s: Failed! 0x%x was 0x%x expected 0x%x (%d, 0x%x, %d us)\n", +			__func__, reg, bits, wbits, ret, mask, +			(count - counter) * sleep); +		ret = -1; +	} +	return ret; +} + +#define WIDGET_BIT(reg, shift) (((shift) << 8) | (reg)) + +static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, +				    struct snd_kcontrol *kcontrol, int event) +{ +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec); +	unsigned int reg = AIC31XX_DACFLAG1; +	unsigned int mask; + +	switch (WIDGET_BIT(w->reg, w->shift)) { +	case WIDGET_BIT(AIC31XX_DACSETUP, 7): +		mask = AIC31XX_LDACPWRSTATUS_MASK; +		break; +	case WIDGET_BIT(AIC31XX_DACSETUP, 6): +		mask = AIC31XX_RDACPWRSTATUS_MASK; +		break; +	case WIDGET_BIT(AIC31XX_HPDRIVER, 7): +		mask = AIC31XX_HPLDRVPWRSTATUS_MASK; +		break; +	case WIDGET_BIT(AIC31XX_HPDRIVER, 6): +		mask = AIC31XX_HPRDRVPWRSTATUS_MASK; +		break; +	case WIDGET_BIT(AIC31XX_SPKAMP, 7): +		mask = AIC31XX_SPLDRVPWRSTATUS_MASK; +		break; +	case WIDGET_BIT(AIC31XX_SPKAMP, 6): +		mask = AIC31XX_SPRDRVPWRSTATUS_MASK; +		break; +	case WIDGET_BIT(AIC31XX_ADCSETUP, 7): +		mask = AIC31XX_ADCPWRSTATUS_MASK; +		reg = AIC31XX_ADCFLAG; +		break; +	default: +		dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n", +			w->name, __func__); +		return -EINVAL; +	} + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100); +	case SND_SOC_DAPM_POST_PMD: +		return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100); +	default: +		dev_dbg(w->codec->dev, +			"Unhandled dapm widget event %d from %s\n", +			event, w->name); +	} +	return 0; +} + +static const struct snd_kcontrol_new left_output_switches[] = { +	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0), +	SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0), +	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0), +}; + +static const struct snd_kcontrol_new right_output_switches[] = { +	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0), +	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0), +}; + +static const struct snd_kcontrol_new p_term_mic1lp = +	SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum); + +static const struct snd_kcontrol_new p_term_mic1rp = +	SOC_DAPM_ENUM("MIC1RP P-Terminal", mic1rp_p_enum); + +static const struct snd_kcontrol_new p_term_mic1lm = +	SOC_DAPM_ENUM("MIC1LM P-Terminal", mic1lm_p_enum); + +static const struct snd_kcontrol_new m_term_mic1lm = +	SOC_DAPM_ENUM("MIC1LM M-Terminal", mic1lm_m_enum); + +static const struct snd_kcontrol_new aic31xx_dapm_hpl_switch = +	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGHPL, 7, 1, 0); + +static const struct snd_kcontrol_new aic31xx_dapm_hpr_switch = +	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGHPR, 7, 1, 0); + +static const struct snd_kcontrol_new aic31xx_dapm_spl_switch = +	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGSPL, 7, 1, 0); + +static const struct snd_kcontrol_new aic31xx_dapm_spr_switch = +	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGSPR, 7, 1, 0); + +static int mic_bias_event(struct snd_soc_dapm_widget *w, +			  struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		/* change mic bias voltage to user defined */ +		snd_soc_update_bits(codec, AIC31XX_MICBIAS, +				    AIC31XX_MICBIAS_MASK, +				    aic31xx->pdata.micbias_vg << +				    AIC31XX_MICBIAS_SHIFT); +		dev_dbg(codec->dev, "%s: turned on\n", __func__); +		break; +	case SND_SOC_DAPM_PRE_PMD: +		/* turn mic bias off */ +		snd_soc_update_bits(codec, AIC31XX_MICBIAS, +				    AIC31XX_MICBIAS_MASK, 0); +		dev_dbg(codec->dev, "%s: turned off\n", __func__); +		break; +	} +	return 0; +} + +static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { +	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_MUX("DAC Left Input", +			 SND_SOC_NOPM, 0, 0, &ldac_in_control), +	SND_SOC_DAPM_MUX("DAC Right Input", +			 SND_SOC_NOPM, 0, 0, &rdac_in_control), +	/* DACs */ +	SND_SOC_DAPM_DAC_E("DAC Left", "Left Playback", +			   AIC31XX_DACSETUP, 7, 0, aic31xx_dapm_power_event, +			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + +	SND_SOC_DAPM_DAC_E("DAC Right", "Right Playback", +			   AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event, +			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + +	/* Output Mixers */ +	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0, +			   left_output_switches, +			   ARRAY_SIZE(left_output_switches)), +	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0, +			   right_output_switches, +			   ARRAY_SIZE(right_output_switches)), + +	SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0, +			    &aic31xx_dapm_hpl_switch), +	SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0, +			    &aic31xx_dapm_hpr_switch), + +	/* Output drivers */ +	SND_SOC_DAPM_OUT_DRV_E("HPL Driver", AIC31XX_HPDRIVER, 7, 0, +			       NULL, 0, aic31xx_dapm_power_event, +			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_OUT_DRV_E("HPR Driver", AIC31XX_HPDRIVER, 6, 0, +			       NULL, 0, aic31xx_dapm_power_event, +			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + +	/* ADC */ +	SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0, +			   aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_POST_PMD), + +	/* Input Selection to MIC_PGA */ +	SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0, +			 &p_term_mic1lp), +	SND_SOC_DAPM_MUX("MIC1RP P-Terminal", SND_SOC_NOPM, 0, 0, +			 &p_term_mic1rp), +	SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0, +			 &p_term_mic1lm), + +	SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0, +			 &m_term_mic1lm), +	/* Enabling & Disabling MIC Gain Ctl */ +	SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA, +			 7, 1, NULL, 0), + +	/* Mic Bias */ +	SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event, +			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +	/* Outputs */ +	SND_SOC_DAPM_OUTPUT("HPL"), +	SND_SOC_DAPM_OUTPUT("HPR"), + +	/* Inputs */ +	SND_SOC_DAPM_INPUT("MIC1LP"), +	SND_SOC_DAPM_INPUT("MIC1RP"), +	SND_SOC_DAPM_INPUT("MIC1LM"), +}; + +static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = { +	/* AIC3111 and AIC3110 have stereo class-D amplifier */ +	SND_SOC_DAPM_OUT_DRV_E("SPL ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0, +			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | +			       SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_OUT_DRV_E("SPR ClassD", AIC31XX_SPKAMP, 6, 0, NULL, 0, +			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | +			       SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_SWITCH("Speaker Left", SND_SOC_NOPM, 0, 0, +			    &aic31xx_dapm_spl_switch), +	SND_SOC_DAPM_SWITCH("Speaker Right", SND_SOC_NOPM, 0, 0, +			    &aic31xx_dapm_spr_switch), +	SND_SOC_DAPM_OUTPUT("SPL"), +	SND_SOC_DAPM_OUTPUT("SPR"), +}; + +/* AIC3100 and AIC3120 have only mono class-D amplifier */ +static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = { +	SND_SOC_DAPM_OUT_DRV_E("SPK ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0, +			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | +			       SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_SWITCH("Speaker", SND_SOC_NOPM, 0, 0, +			    &aic31xx_dapm_spl_switch), +	SND_SOC_DAPM_OUTPUT("SPK"), +}; + +static const struct snd_soc_dapm_route +aic31xx_audio_map[] = { +	/* DAC Input Routing */ +	{"DAC Left Input", "Left Data", "DAC IN"}, +	{"DAC Left Input", "Right Data", "DAC IN"}, +	{"DAC Left Input", "Mono", "DAC IN"}, +	{"DAC Right Input", "Left Data", "DAC IN"}, +	{"DAC Right Input", "Right Data", "DAC IN"}, +	{"DAC Right Input", "Mono", "DAC IN"}, +	{"DAC Left", NULL, "DAC Left Input"}, +	{"DAC Right", NULL, "DAC Right Input"}, + +	/* Mic input */ +	{"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"}, +	{"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"}, +	{"MIC1LP P-Terminal", "FFR 40 Ohm", "MIC1LP"}, +	{"MIC1RP P-Terminal", "FFR 10 Ohm", "MIC1RP"}, +	{"MIC1RP P-Terminal", "FFR 20 Ohm", "MIC1RP"}, +	{"MIC1RP P-Terminal", "FFR 40 Ohm", "MIC1RP"}, +	{"MIC1LM P-Terminal", "FFR 10 Ohm", "MIC1LM"}, +	{"MIC1LM P-Terminal", "FFR 20 Ohm", "MIC1LM"}, +	{"MIC1LM P-Terminal", "FFR 40 Ohm", "MIC1LM"}, + +	{"MIC1LM M-Terminal", "FFR 10 Ohm", "MIC1LM"}, +	{"MIC1LM M-Terminal", "FFR 20 Ohm", "MIC1LM"}, +	{"MIC1LM M-Terminal", "FFR 40 Ohm", "MIC1LM"}, + +	{"MIC_GAIN_CTL", NULL, "MIC1LP P-Terminal"}, +	{"MIC_GAIN_CTL", NULL, "MIC1RP P-Terminal"}, +	{"MIC_GAIN_CTL", NULL, "MIC1LM P-Terminal"}, +	{"MIC_GAIN_CTL", NULL, "MIC1LM M-Terminal"}, + +	{"ADC", NULL, "MIC_GAIN_CTL"}, + +	/* Left Output */ +	{"Output Left", "From Left DAC", "DAC Left"}, +	{"Output Left", "From MIC1LP", "MIC1LP"}, +	{"Output Left", "From MIC1RP", "MIC1RP"}, + +	/* Right Output */ +	{"Output Right", "From Right DAC", "DAC Right"}, +	{"Output Right", "From MIC1RP", "MIC1RP"}, + +	/* HPL path */ +	{"HP Left", "Switch", "Output Left"}, +	{"HPL Driver", NULL, "HP Left"}, +	{"HPL", NULL, "HPL Driver"}, + +	/* HPR path */ +	{"HP Right", "Switch", "Output Right"}, +	{"HPR Driver", NULL, "HP Right"}, +	{"HPR", NULL, "HPR Driver"}, +}; + +static const struct snd_soc_dapm_route +aic311x_audio_map[] = { +	/* SP L path */ +	{"Speaker Left", "Switch", "Output Left"}, +	{"SPL ClassD", NULL, "Speaker Left"}, +	{"SPL", NULL, "SPL ClassD"}, + +	/* SP R path */ +	{"Speaker Right", "Switch", "Output Right"}, +	{"SPR ClassD", NULL, "Speaker Right"}, +	{"SPR", NULL, "SPR ClassD"}, +}; + +static const struct snd_soc_dapm_route +aic310x_audio_map[] = { +	/* SP L path */ +	{"Speaker", "Switch", "Output Left"}, +	{"SPK ClassD", NULL, "Speaker"}, +	{"SPK", NULL, "SPK ClassD"}, +}; + +static int aic31xx_add_controls(struct snd_soc_codec *codec) +{ +	int ret = 0; +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); + +	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) +		ret = snd_soc_add_codec_controls( +			codec, aic311x_snd_controls, +			ARRAY_SIZE(aic311x_snd_controls)); +	else +		ret = snd_soc_add_codec_controls( +			codec, aic310x_snd_controls, +			ARRAY_SIZE(aic310x_snd_controls)); + +	return ret; +} + +static int aic31xx_add_widgets(struct snd_soc_codec *codec) +{ +	struct snd_soc_dapm_context *dapm = &codec->dapm; +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	int ret = 0; + +	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { +		ret = snd_soc_dapm_new_controls( +			dapm, aic311x_dapm_widgets, +			ARRAY_SIZE(aic311x_dapm_widgets)); +		if (ret) +			return ret; + +		ret = snd_soc_dapm_add_routes(dapm, aic311x_audio_map, +					      ARRAY_SIZE(aic311x_audio_map)); +		if (ret) +			return ret; +	} else { +		ret = snd_soc_dapm_new_controls( +			dapm, aic310x_dapm_widgets, +			ARRAY_SIZE(aic310x_dapm_widgets)); +		if (ret) +			return ret; + +		ret = snd_soc_dapm_add_routes(dapm, aic310x_audio_map, +					      ARRAY_SIZE(aic310x_audio_map)); +		if (ret) +			return ret; +	} + +	return 0; +} + +static int aic31xx_setup_pll(struct snd_soc_codec *codec, +			     struct snd_pcm_hw_params *params) +{ +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	int bclk_n = 0; +	int i; + +	/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */ +	snd_soc_update_bits(codec, AIC31XX_CLKMUX, +			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL); +	snd_soc_update_bits(codec, AIC31XX_IFACE2, +			    AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK); + +	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) { +		if (aic31xx_divs[i].rate == params_rate(params) && +		    aic31xx_divs[i].mclk == aic31xx->sysclk) +			break; +	} + +	if (i == ARRAY_SIZE(aic31xx_divs)) { +		dev_err(codec->dev, "%s: Sampling rate %u not supported\n", +			__func__, params_rate(params)); +		return -EINVAL; +	} + +	/* PLL configuration */ +	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK, +			    (aic31xx_divs[i].p_val << 4) | 0x01); +	snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j); + +	snd_soc_write(codec, AIC31XX_PLLDMSB, +		      aic31xx_divs[i].pll_d >> 8); +	snd_soc_write(codec, AIC31XX_PLLDLSB, +		      aic31xx_divs[i].pll_d & 0xff); + +	/* DAC dividers configuration */ +	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK, +			    aic31xx_divs[i].ndac); +	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK, +			    aic31xx_divs[i].mdac); + +	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8); +	snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff); + +	/* ADC dividers configuration. Write reset value 1 if not used. */ +	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK, +			    aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1); +	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK, +			    aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1); + +	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr); + +	/* Bit clock divider configuration. */ +	bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) +		/ snd_soc_params_to_frame_size(params); +	if (bclk_n == 0) { +		dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n", +			__func__); +		return -EINVAL; +	} + +	snd_soc_update_bits(codec, AIC31XX_BCLKN, +			    AIC31XX_PLL_MASK, bclk_n); + +	aic31xx->rate_div_line = i; + +	dev_dbg(codec->dev, +		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n", +		aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d, +		aic31xx_divs[i].p_val, aic31xx_divs[i].dosr, +		aic31xx_divs[i].ndac, aic31xx_divs[i].mdac, +		aic31xx_divs[i].aosr, aic31xx_divs[i].nadc, +		aic31xx_divs[i].madc, bclk_n); + +	return 0; +} + +static int aic31xx_hw_params(struct snd_pcm_substream *substream, +			     struct snd_pcm_hw_params *params, +			     struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	u8 data = 0; + +	dev_dbg(codec->dev, "## %s: format %d width %d rate %d\n", +		__func__, params_format(params), params_width(params), +		params_rate(params)); + +	switch (params_width(params)) { +	case 16: +		break; +	case 20: +		data = (AIC31XX_WORD_LEN_20BITS << +			AIC31XX_IFACE1_DATALEN_SHIFT); +		break; +	case 24: +		data = (AIC31XX_WORD_LEN_24BITS << +			AIC31XX_IFACE1_DATALEN_SHIFT); +		break; +	case 32: +		data = (AIC31XX_WORD_LEN_32BITS << +			AIC31XX_IFACE1_DATALEN_SHIFT); +		break; +	default: +		dev_err(codec->dev, "%s: Unsupported format %d\n", +			__func__, params_format(params)); +		return -EINVAL; +	} + +	snd_soc_update_bits(codec, AIC31XX_IFACE1, +			    AIC31XX_IFACE1_DATALEN_MASK, +			    data); + +	return aic31xx_setup_pll(codec, params); +} + +static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute) +{ +	struct snd_soc_codec *codec = codec_dai->codec; + +	if (mute) { +		snd_soc_update_bits(codec, AIC31XX_DACMUTE, +				    AIC31XX_DACMUTE_MASK, +				    AIC31XX_DACMUTE_MASK); +	} else { +		snd_soc_update_bits(codec, AIC31XX_DACMUTE, +				    AIC31XX_DACMUTE_MASK, 0x0); +	} + +	return 0; +} + +static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, +			       unsigned int fmt) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	u8 iface_reg1 = 0; +	u8 iface_reg3 = 0; +	u8 dsp_a_val = 0; + +	dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt); + +	/* set master/slave audio interface */ +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER; +		break; +	default: +		dev_alert(codec->dev, "Invalid DAI master/slave interface\n"); +		return -EINVAL; +	} + +	/* interface format */ +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		break; +	case SND_SOC_DAIFMT_DSP_A: +		dsp_a_val = 0x1; +	case SND_SOC_DAIFMT_DSP_B: +		/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */ +		switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +		case SND_SOC_DAIFMT_NB_NF: +			iface_reg3 |= AIC31XX_BCLKINV_MASK; +			break; +		case SND_SOC_DAIFMT_IB_NF: +			break; +		default: +			return -EINVAL; +		} +		iface_reg1 |= (AIC31XX_DSP_MODE << +			       AIC31XX_IFACE1_DATATYPE_SHIFT); +		break; +	case SND_SOC_DAIFMT_RIGHT_J: +		iface_reg1 |= (AIC31XX_RIGHT_JUSTIFIED_MODE << +			       AIC31XX_IFACE1_DATATYPE_SHIFT); +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		iface_reg1 |= (AIC31XX_LEFT_JUSTIFIED_MODE << +			       AIC31XX_IFACE1_DATATYPE_SHIFT); +		break; +	default: +		dev_err(codec->dev, "Invalid DAI interface format\n"); +		return -EINVAL; +	} + +	snd_soc_update_bits(codec, AIC31XX_IFACE1, +			    AIC31XX_IFACE1_DATATYPE_MASK | +			    AIC31XX_IFACE1_MASTER_MASK, +			    iface_reg1); +	snd_soc_update_bits(codec, AIC31XX_DATA_OFFSET, +			    AIC31XX_DATA_OFFSET_MASK, +			    dsp_a_val); +	snd_soc_update_bits(codec, AIC31XX_IFACE2, +			    AIC31XX_BCLKINV_MASK, +			    iface_reg3); + +	return 0; +} + +static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, +				  int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	int i; + +	dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n", +		__func__, clk_id, freq, dir); + +	for (i = 0; aic31xx_divs[i].mclk != freq; i++) { +		if (i == ARRAY_SIZE(aic31xx_divs)) { +			dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", +				__func__, freq); +			return -EINVAL; +		} +	} + +	/* set clock on MCLK, BCLK, or GPIO1 as PLL input */ +	snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK, +			    clk_id << AIC31XX_PLL_CLKIN_SHIFT); + +	aic31xx->sysclk = freq; +	return 0; +} + +static int aic31xx_regulator_event(struct notifier_block *nb, +				   unsigned long event, void *data) +{ +	struct aic31xx_disable_nb *disable_nb = +		container_of(nb, struct aic31xx_disable_nb, nb); +	struct aic31xx_priv *aic31xx = disable_nb->aic31xx; + +	if (event & REGULATOR_EVENT_DISABLE) { +		/* +		 * Put codec to reset and as at least one of the +		 * supplies was disabled. +		 */ +		if (gpio_is_valid(aic31xx->pdata.gpio_reset)) +			gpio_set_value(aic31xx->pdata.gpio_reset, 0); + +		regcache_mark_dirty(aic31xx->regmap); +		dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__); +	} + +	return 0; +} + +static void aic31xx_clk_on(struct snd_soc_codec *codec) +{ +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	u8 mask = AIC31XX_PM_MASK; +	u8 on = AIC31XX_PM_MASK; + +	dev_dbg(codec->dev, "codec clock -> on (rate %d)\n", +		aic31xx_divs[aic31xx->rate_div_line].rate); +	snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, on); +	mdelay(10); +	snd_soc_update_bits(codec, AIC31XX_NDAC, mask, on); +	snd_soc_update_bits(codec, AIC31XX_MDAC, mask, on); +	if (aic31xx_divs[aic31xx->rate_div_line].nadc) +		snd_soc_update_bits(codec, AIC31XX_NADC, mask, on); +	if (aic31xx_divs[aic31xx->rate_div_line].madc) +		snd_soc_update_bits(codec, AIC31XX_MADC, mask, on); +	snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, on); +} + +static void aic31xx_clk_off(struct snd_soc_codec *codec) +{ +	u8 mask = AIC31XX_PM_MASK; +	u8 off = 0; + +	dev_dbg(codec->dev, "codec clock -> off\n"); +	snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, off); +	snd_soc_update_bits(codec, AIC31XX_MADC, mask, off); +	snd_soc_update_bits(codec, AIC31XX_NADC, mask, off); +	snd_soc_update_bits(codec, AIC31XX_MDAC, mask, off); +	snd_soc_update_bits(codec, AIC31XX_NDAC, mask, off); +	snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, off); +} + +static int aic31xx_power_on(struct snd_soc_codec *codec) +{ +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	int ret = 0; + +	ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies), +				    aic31xx->supplies); +	if (ret) +		return ret; + +	if (gpio_is_valid(aic31xx->pdata.gpio_reset)) { +		gpio_set_value(aic31xx->pdata.gpio_reset, 1); +		udelay(100); +	} +	regcache_cache_only(aic31xx->regmap, false); +	ret = regcache_sync(aic31xx->regmap); +	if (ret != 0) { +		dev_err(codec->dev, +			"Failed to restore cache: %d\n", ret); +		regcache_cache_only(aic31xx->regmap, true); +		regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies), +				       aic31xx->supplies); +		return ret; +	} +	return 0; +} + +static int aic31xx_power_off(struct snd_soc_codec *codec) +{ +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	int ret = 0; + +	regcache_cache_only(aic31xx->regmap, true); +	ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies), +				     aic31xx->supplies); + +	return ret; +} + +static int aic31xx_set_bias_level(struct snd_soc_codec *codec, +				  enum snd_soc_bias_level level) +{ +	dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__, +		codec->dapm.bias_level, level); + +	switch (level) { +	case SND_SOC_BIAS_ON: +		break; +	case SND_SOC_BIAS_PREPARE: +		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) +			aic31xx_clk_on(codec); +		break; +	case SND_SOC_BIAS_STANDBY: +		switch (codec->dapm.bias_level) { +		case SND_SOC_BIAS_OFF: +			aic31xx_power_on(codec); +			break; +		case SND_SOC_BIAS_PREPARE: +			aic31xx_clk_off(codec); +			break; +		default: +			BUG(); +		} +		break; +	case SND_SOC_BIAS_OFF: +		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) +			aic31xx_power_off(codec); +		break; +	} +	codec->dapm.bias_level = level; + +	return 0; +} + +static int aic31xx_suspend(struct snd_soc_codec *codec) +{ +	aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); +	return 0; +} + +static int aic31xx_resume(struct snd_soc_codec *codec) +{ +	aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +	return 0; +} + +static int aic31xx_codec_probe(struct snd_soc_codec *codec) +{ +	int ret = 0; +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	int i; + +	dev_dbg(aic31xx->dev, "## %s\n", __func__); + +	aic31xx = snd_soc_codec_get_drvdata(codec); + +	aic31xx->codec = codec; + +	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) { +		aic31xx->disable_nb[i].nb.notifier_call = +			aic31xx_regulator_event; +		aic31xx->disable_nb[i].aic31xx = aic31xx; +		ret = regulator_register_notifier(aic31xx->supplies[i].consumer, +						  &aic31xx->disable_nb[i].nb); +		if (ret) { +			dev_err(codec->dev, +				"Failed to request regulator notifier: %d\n", +				ret); +			return ret; +		} +	} + +	regcache_cache_only(aic31xx->regmap, true); +	regcache_mark_dirty(aic31xx->regmap); + +	ret = aic31xx_add_controls(codec); +	if (ret) +		return ret; + +	ret = aic31xx_add_widgets(codec); + +	return ret; +} + +static int aic31xx_codec_remove(struct snd_soc_codec *codec) +{ +	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); +	int i; +	/* power down chip */ +	aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); + +	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) +		regulator_unregister_notifier(aic31xx->supplies[i].consumer, +					      &aic31xx->disable_nb[i].nb); + +	return 0; +} + +static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { +	.probe			= aic31xx_codec_probe, +	.remove			= aic31xx_codec_remove, +	.suspend		= aic31xx_suspend, +	.resume			= aic31xx_resume, +	.set_bias_level		= aic31xx_set_bias_level, +	.controls		= aic31xx_snd_controls, +	.num_controls		= ARRAY_SIZE(aic31xx_snd_controls), +	.dapm_widgets		= aic31xx_dapm_widgets, +	.num_dapm_widgets	= ARRAY_SIZE(aic31xx_dapm_widgets), +	.dapm_routes		= aic31xx_audio_map, +	.num_dapm_routes	= ARRAY_SIZE(aic31xx_audio_map), +}; + +static struct snd_soc_dai_ops aic31xx_dai_ops = { +	.hw_params	= aic31xx_hw_params, +	.set_sysclk	= aic31xx_set_dai_sysclk, +	.set_fmt	= aic31xx_set_dai_fmt, +	.digital_mute	= aic31xx_dac_mute, +}; + +static struct snd_soc_dai_driver aic31xx_dai_driver[] = { +	{ +		.name = "tlv320aic31xx-hifi", +		.playback = { +			.stream_name	 = "Playback", +			.channels_min	 = 1, +			.channels_max	 = 2, +			.rates		 = AIC31XX_RATES, +			.formats	 = AIC31XX_FORMATS, +		}, +		.capture = { +			.stream_name	 = "Capture", +			.channels_min	 = 1, +			.channels_max	 = 2, +			.rates		 = AIC31XX_RATES, +			.formats	 = AIC31XX_FORMATS, +		}, +		.ops = &aic31xx_dai_ops, +		.symmetric_rates = 1, +	} +}; + +#if defined(CONFIG_OF) +static const struct of_device_id tlv320aic31xx_of_match[] = { +	{ .compatible = "ti,tlv320aic310x" }, +	{ .compatible = "ti,tlv320aic311x" }, +	{ .compatible = "ti,tlv320aic3100" }, +	{ .compatible = "ti,tlv320aic3110" }, +	{ .compatible = "ti,tlv320aic3120" }, +	{ .compatible = "ti,tlv320aic3111" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); + +static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) +{ +	struct device_node *np = aic31xx->dev->of_node; +	unsigned int value = MICBIAS_2_0V; +	int ret; + +	of_property_read_u32(np, "ai31xx-micbias-vg", &value); +	switch (value) { +	case MICBIAS_2_0V: +	case MICBIAS_2_5V: +	case MICBIAS_AVDDV: +		aic31xx->pdata.micbias_vg = value; +		break; +	default: +		dev_err(aic31xx->dev, +			"Bad ai31xx-micbias-vg value %d DT\n", +			value); +		aic31xx->pdata.micbias_vg = MICBIAS_2_0V; +	} + +	ret = of_get_named_gpio(np, "gpio-reset", 0); +	if (ret > 0) +		aic31xx->pdata.gpio_reset = ret; +} +#else /* CONFIG_OF */ +static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) +{ +} +#endif /* CONFIG_OF */ + +static void aic31xx_device_init(struct aic31xx_priv *aic31xx) +{ +	int ret, i; + +	dev_set_drvdata(aic31xx->dev, aic31xx); + +	if (dev_get_platdata(aic31xx->dev)) +		memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), +		       sizeof(aic31xx->pdata)); +	else if (aic31xx->dev->of_node) +		aic31xx_pdata_from_of(aic31xx); + +	if (aic31xx->pdata.gpio_reset) { +		ret = devm_gpio_request_one(aic31xx->dev, +					    aic31xx->pdata.gpio_reset, +					    GPIOF_OUT_INIT_HIGH, +					    "aic31xx-reset-pin"); +		if (ret < 0) { +			dev_err(aic31xx->dev, "not able to acquire gpio\n"); +			return; +		} +	} + +	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) +		aic31xx->supplies[i].supply = aic31xx_supply_names[i]; + +	ret = devm_regulator_bulk_get(aic31xx->dev, +				      ARRAY_SIZE(aic31xx->supplies), +				      aic31xx->supplies); +	if (ret != 0) +		dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret); + +} + +static int aic31xx_i2c_probe(struct i2c_client *i2c, +			     const struct i2c_device_id *id) +{ +	struct aic31xx_priv *aic31xx; +	int ret; +	const struct regmap_config *regmap_config; + +	dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, +		id->name, (int) id->driver_data); + +	regmap_config = &aic31xx_i2c_regmap; + +	aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL); +	if (aic31xx == NULL) +		return -ENOMEM; + +	aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config); +	if (IS_ERR(aic31xx->regmap)) { +		ret = PTR_ERR(aic31xx->regmap); +		dev_err(&i2c->dev, "Failed to allocate register map: %d\n", +			ret); +		return ret; +	} +	aic31xx->dev = &i2c->dev; + +	aic31xx->pdata.codec_type = id->driver_data; + +	aic31xx_device_init(aic31xx); + +	return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, +				     aic31xx_dai_driver, +				     ARRAY_SIZE(aic31xx_dai_driver)); +} + +static int aic31xx_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); +	return 0; +} + +static const struct i2c_device_id aic31xx_i2c_id[] = { +	{ "tlv320aic310x", AIC3100 }, +	{ "tlv320aic311x", AIC3110 }, +	{ "tlv320aic3100", AIC3100 }, +	{ "tlv320aic3110", AIC3110 }, +	{ "tlv320aic3120", AIC3120 }, +	{ "tlv320aic3111", AIC3111 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); + +static struct i2c_driver aic31xx_i2c_driver = { +	.driver = { +		.name	= "tlv320aic31xx-codec", +		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(tlv320aic31xx_of_match), +	}, +	.probe		= aic31xx_i2c_probe, +	.remove		= aic31xx_i2c_remove, +	.id_table	= aic31xx_i2c_id, +}; + +module_i2c_driver(aic31xx_i2c_driver); + +MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver"); +MODULE_AUTHOR("Jyri Sarha"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h new file mode 100644 index 00000000000..52ed57c69df --- /dev/null +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -0,0 +1,258 @@ +/* + * ALSA SoC TLV320AIC31XX codec driver + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ +#ifndef _TLV320AIC31XX_H +#define _TLV320AIC31XX_H + +#define AIC31XX_RATES	SNDRV_PCM_RATE_8000_192000 + +#define AIC31XX_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ +			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + + +#define AIC31XX_STEREO_CLASS_D_BIT	0x1 +#define AIC31XX_MINIDSP_BIT		0x2 + +enum aic31xx_type { +	AIC3100	= 0, +	AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, +	AIC3120 = AIC31XX_MINIDSP_BIT, +	AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), +}; + +struct aic31xx_pdata { +	enum aic31xx_type codec_type; +	unsigned int gpio_reset; +	int micbias_vg; +}; + +/* Page Control Register */ +#define AIC31XX_PAGECTL				0x00 + +/* Page 0 Registers */ +/* Software reset register */ +#define AIC31XX_RESET				0x01 +/* OT FLAG register */ +#define AIC31XX_OT_FLAG				0x03 +/* Clock clock Gen muxing, Multiplexers*/ +#define AIC31XX_CLKMUX				0x04 +/* PLL P and R-VAL register */ +#define AIC31XX_PLLPR				0x05 +/* PLL J-VAL register */ +#define AIC31XX_PLLJ				0x06 +/* PLL D-VAL MSB register */ +#define AIC31XX_PLLDMSB				0x07 +/* PLL D-VAL LSB register */ +#define AIC31XX_PLLDLSB				0x08 +/* DAC NDAC_VAL register*/ +#define AIC31XX_NDAC				0x0B +/* DAC MDAC_VAL register */ +#define AIC31XX_MDAC				0x0C +/* DAC OSR setting register 1, MSB value */ +#define AIC31XX_DOSRMSB				0x0D +/* DAC OSR setting register 2, LSB value */ +#define AIC31XX_DOSRLSB				0x0E +#define AIC31XX_MINI_DSP_INPOL			0x10 +/* Clock setting register 8, PLL */ +#define AIC31XX_NADC				0x12 +/* Clock setting register 9, PLL */ +#define AIC31XX_MADC				0x13 +/* ADC Oversampling (AOSR) Register */ +#define AIC31XX_AOSR				0x14 +/* Clock setting register 9, Multiplexers */ +#define AIC31XX_CLKOUTMUX			0x19 +/* Clock setting register 10, CLOCKOUT M divider value */ +#define AIC31XX_CLKOUTMVAL			0x1A +/* Audio Interface Setting Register 1 */ +#define AIC31XX_IFACE1				0x1B +/* Audio Data Slot Offset Programming */ +#define AIC31XX_DATA_OFFSET			0x1C +/* Audio Interface Setting Register 2 */ +#define AIC31XX_IFACE2				0x1D +/* Clock setting register 11, BCLK N Divider */ +#define AIC31XX_BCLKN				0x1E +/* Audio Interface Setting Register 3, Secondary Audio Interface */ +#define AIC31XX_IFACESEC1			0x1F +/* Audio Interface Setting Register 4 */ +#define AIC31XX_IFACESEC2			0x20 +/* Audio Interface Setting Register 5 */ +#define AIC31XX_IFACESEC3			0x21 +/* I2C Bus Condition */ +#define AIC31XX_I2C				0x22 +/* ADC FLAG */ +#define AIC31XX_ADCFLAG				0x24 +/* DAC Flag Registers */ +#define AIC31XX_DACFLAG1			0x25 +#define AIC31XX_DACFLAG2			0x26 +/* Sticky Interrupt flag (overflow) */ +#define AIC31XX_OFFLAG				0x27 +/* Sticy DAC Interrupt flags */ +#define AIC31XX_INTRDACFLAG			0x2C +/* Sticy ADC Interrupt flags */ +#define AIC31XX_INTRADCFLAG			0x2D +/* DAC Interrupt flags 2 */ +#define AIC31XX_INTRDACFLAG2			0x2E +/* ADC Interrupt flags 2 */ +#define AIC31XX_INTRADCFLAG2			0x2F +/* INT1 interrupt control */ +#define AIC31XX_INT1CTRL			0x30 +/* INT2 interrupt control */ +#define AIC31XX_INT2CTRL			0x31 +/* GPIO1 control */ +#define AIC31XX_GPIO1				0x33 + +#define AIC31XX_DACPRB				0x3C +/* ADC Instruction Set Register */ +#define AIC31XX_ADCPRB				0x3D +/* DAC channel setup register */ +#define AIC31XX_DACSETUP			0x3F +/* DAC Mute and volume control register */ +#define AIC31XX_DACMUTE				0x40 +/* Left DAC channel digital volume control */ +#define AIC31XX_LDACVOL				0x41 +/* Right DAC channel digital volume control */ +#define AIC31XX_RDACVOL				0x42 +/* Headset detection */ +#define AIC31XX_HSDETECT			0x43 +/* ADC Digital Mic */ +#define AIC31XX_ADCSETUP			0x51 +/* ADC Digital Volume Control Fine Adjust */ +#define AIC31XX_ADCFGA				0x52 +/* ADC Digital Volume Control Coarse Adjust */ +#define AIC31XX_ADCVOL				0x53 + + +/* Page 1 Registers */ +/* Headphone drivers */ +#define AIC31XX_HPDRIVER			0x9F +/* Class-D Speakear Amplifier */ +#define AIC31XX_SPKAMP				0xA0 +/* HP Output Drivers POP Removal Settings */ +#define AIC31XX_HPPOP				0xA1 +/* Output Driver PGA Ramp-Down Period Control */ +#define AIC31XX_SPPGARAMP			0xA2 +/* DAC_L and DAC_R Output Mixer Routing */ +#define AIC31XX_DACMIXERROUTE			0xA3 +/* Left Analog Vol to HPL */ +#define AIC31XX_LANALOGHPL			0xA4 +/* Right Analog Vol to HPR */ +#define AIC31XX_RANALOGHPR			0xA5 +/* Left Analog Vol to SPL */ +#define AIC31XX_LANALOGSPL			0xA6 +/* Right Analog Vol to SPR */ +#define AIC31XX_RANALOGSPR			0xA7 +/* HPL Driver */ +#define AIC31XX_HPLGAIN				0xA8 +/* HPR Driver */ +#define AIC31XX_HPRGAIN				0xA9 +/* SPL Driver */ +#define AIC31XX_SPLGAIN				0xAA +/* SPR Driver */ +#define AIC31XX_SPRGAIN				0xAB +/* HP Driver Control */ +#define AIC31XX_HPCONTROL			0xAC +/* MIC Bias Control */ +#define AIC31XX_MICBIAS				0xAE +/* MIC PGA*/ +#define AIC31XX_MICPGA				0xAF +/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */ +#define AIC31XX_MICPGAPI			0xB0 +/* ADC Input Selection for M-Terminal */ +#define AIC31XX_MICPGAMI			0xB1 +/* Input CM Settings */ +#define AIC31XX_MICPGACM			0xB2 + +/* Bits, masks and shifts */ + +/* AIC31XX_CLKMUX */ +#define AIC31XX_PLL_CLKIN_MASK			0x0c +#define AIC31XX_PLL_CLKIN_SHIFT			2 +#define AIC31XX_PLL_CLKIN_MCLK			0 +#define AIC31XX_CODEC_CLKIN_MASK		0x03 +#define AIC31XX_CODEC_CLKIN_SHIFT		0 +#define AIC31XX_CODEC_CLKIN_PLL			3 +#define AIC31XX_CODEC_CLKIN_BCLK		1 + +/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC, +   AIC31XX_BCLKN */ +#define AIC31XX_PLL_MASK		0x7f +#define AIC31XX_PM_MASK			0x80 + +/* AIC31XX_IFACE1 */ +#define AIC31XX_WORD_LEN_16BITS		0x00 +#define AIC31XX_WORD_LEN_20BITS		0x01 +#define AIC31XX_WORD_LEN_24BITS		0x02 +#define AIC31XX_WORD_LEN_32BITS		0x03 +#define AIC31XX_IFACE1_DATALEN_MASK	0x30 +#define AIC31XX_IFACE1_DATALEN_SHIFT	(4) +#define AIC31XX_IFACE1_DATATYPE_MASK	0xC0 +#define AIC31XX_IFACE1_DATATYPE_SHIFT	(6) +#define AIC31XX_I2S_MODE		0x00 +#define AIC31XX_DSP_MODE		0x01 +#define AIC31XX_RIGHT_JUSTIFIED_MODE	0x02 +#define AIC31XX_LEFT_JUSTIFIED_MODE	0x03 +#define AIC31XX_IFACE1_MASTER_MASK	0x0C +#define AIC31XX_BCLK_MASTER		0x08 +#define AIC31XX_WCLK_MASTER		0x04 + +/* AIC31XX_DATA_OFFSET */ +#define AIC31XX_DATA_OFFSET_MASK	0xFF + +/* AIC31XX_IFACE2 */ +#define AIC31XX_BCLKINV_MASK		0x08 +#define AIC31XX_BDIVCLK_MASK		0x03 +#define AIC31XX_DAC2BCLK		0x00 +#define AIC31XX_DACMOD2BCLK		0x01 +#define AIC31XX_ADC2BCLK		0x02 +#define AIC31XX_ADCMOD2BCLK		0x03 + +/* AIC31XX_ADCFLAG */ +#define AIC31XX_ADCPWRSTATUS_MASK		0x40 + +/* AIC31XX_DACFLAG1 */ +#define AIC31XX_LDACPWRSTATUS_MASK		0x80 +#define AIC31XX_RDACPWRSTATUS_MASK		0x08 +#define AIC31XX_HPLDRVPWRSTATUS_MASK		0x20 +#define AIC31XX_HPRDRVPWRSTATUS_MASK		0x02 +#define AIC31XX_SPLDRVPWRSTATUS_MASK		0x10 +#define AIC31XX_SPRDRVPWRSTATUS_MASK		0x01 + +/* AIC31XX_INTRDACFLAG */ +#define AIC31XX_HPSCDETECT_MASK			0x80 +#define AIC31XX_BUTTONPRESS_MASK		0x20 +#define AIC31XX_HSPLUG_MASK			0x10 +#define AIC31XX_LDRCTHRES_MASK			0x08 +#define AIC31XX_RDRCTHRES_MASK			0x04 +#define AIC31XX_DACSINT_MASK			0x02 +#define AIC31XX_DACAINT_MASK			0x01 + +/* AIC31XX_INT1CTRL */ +#define AIC31XX_HSPLUGDET_MASK			0x80 +#define AIC31XX_BUTTONPRESSDET_MASK		0x40 +#define AIC31XX_DRCTHRES_MASK			0x20 +#define AIC31XX_AGCNOISE_MASK			0x10 +#define AIC31XX_OC_MASK				0x08 +#define AIC31XX_ENGINE_MASK			0x04 + +/* AIC31XX_DACSETUP */ +#define AIC31XX_SOFTSTEP_MASK			0x03 + +/* AIC31XX_DACMUTE */ +#define AIC31XX_DACMUTE_MASK			0x0C + +/* AIC31XX_MICBIAS */ +#define AIC31XX_MICBIAS_MASK			0x03 +#define AIC31XX_MICBIAS_SHIFT			0 + +#endif	/* _TLV320AIC31XX_H */ diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 2ed57d4aa44..1d9b117345a 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -29,9 +29,12 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/gpio.h> +#include <linux/of_gpio.h>  #include <linux/i2c.h>  #include <linux/cdev.h>  #include <linux/slab.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h>  #include <sound/tlv320aic32x4.h>  #include <sound/core.h> @@ -60,27 +63,38 @@ struct aic32x4_rate_divs {  };  struct aic32x4_priv { +	struct regmap *regmap;  	u32 sysclk; -	u8 page_no; -	void *control_data;  	u32 power_cfg;  	u32 micpga_routing;  	bool swapdacs;  	int rstn_gpio; +	struct clk *mclk; + +	struct regulator *supply_ldo; +	struct regulator *supply_iov; +	struct regulator *supply_dv; +	struct regulator *supply_av;  }; -/* 0dB min, 1dB steps */ -static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);  /* 0dB min, 0.5dB steps */  static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0); +/* -63.5dB min, 0.5dB steps */ +static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0); +/* -6dB min, 1dB steps */ +static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0); +/* -12dB min, 0.5dB steps */ +static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);  static const struct snd_kcontrol_new aic32x4_snd_controls[] = { -	SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL, -			AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5), -	SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, -			AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1), -	SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, -			AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1), +	SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, +			AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), +	SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, +			AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, +			tlv_driver_gain), +	SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, +			AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, +			tlv_driver_gain),  	SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,  			AIC32X4_HPRGAIN, 6, 0x01, 1),  	SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, @@ -91,8 +105,8 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {  	SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),  	SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0), -	SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL, -			AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5), +	SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL, +			AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),  	SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,  			AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), @@ -262,67 +276,25 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {  	{"Right ADC", NULL, "Right Input Mixer"},  }; -static inline int aic32x4_change_page(struct snd_soc_codec *codec, -					unsigned int new_page) -{ -	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); -	u8 data[2]; -	int ret; - -	data[0] = 0x00; -	data[1] = new_page & 0xff; - -	ret = codec->hw_write(codec->control_data, data, 2); -	if (ret == 2) { -		aic32x4->page_no = new_page; -		return 0; -	} else { -		return ret; -	} -} - -static int aic32x4_write(struct snd_soc_codec *codec, unsigned int reg, -				unsigned int val) -{ -	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); -	unsigned int page = reg / 128; -	unsigned int fixed_reg = reg % 128; -	u8 data[2]; -	int ret; - -	/* A write to AIC32X4_PSEL is really a non-explicit page change */ -	if (reg == AIC32X4_PSEL) -		return aic32x4_change_page(codec, val); - -	if (aic32x4->page_no != page) { -		ret = aic32x4_change_page(codec, page); -		if (ret != 0) -			return ret; -	} - -	data[0] = fixed_reg & 0xff; -	data[1] = val & 0xff; - -	if (codec->hw_write(codec->control_data, data, 2) == 2) -		return 0; -	else -		return -EIO; -} +static const struct regmap_range_cfg aic32x4_regmap_pages[] = { +	{ +		.selector_reg = 0, +		.selector_mask  = 0xff, +		.window_start = 0, +		.window_len = 128, +		.range_min = 0, +		.range_max = AIC32X4_RMICPGAVOL, +	}, +}; -static unsigned int aic32x4_read(struct snd_soc_codec *codec, unsigned int reg) -{ -	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); -	unsigned int page = reg / 128; -	unsigned int fixed_reg = reg % 128; -	int ret; +static const struct regmap_config aic32x4_regmap = { +	.reg_bits = 8, +	.val_bits = 8, -	if (aic32x4->page_no != page) { -		ret = aic32x4_change_page(codec, page); -		if (ret != 0) -			return ret; -	} -	return i2c_smbus_read_byte_data(codec->control_data, fixed_reg & 0xff); -} +	.max_register = AIC32X4_RMICPGAVOL, +	.ranges = aic32x4_regmap_pages, +	.num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), +};  static inline int aic32x4_get_divs(int mclk, int rate)  { @@ -493,6 +465,17 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,  	}  	snd_soc_write(codec, AIC32X4_IFACE1, data); +	if (params_channels(params) == 1) { +		data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; +	} else { +		if (aic32x4->swapdacs) +			data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN; +		else +			data = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; +	} +	snd_soc_update_bits(codec, AIC32X4_DACSETUP, AIC32X4_DAC_CHAN_MASK, +			data); +  	return 0;  } @@ -512,8 +495,18 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)  static int aic32x4_set_bias_level(struct snd_soc_codec *codec,  				  enum snd_soc_bias_level level)  { +	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); +	int ret; +  	switch (level) {  	case SND_SOC_BIAS_ON: +		/* Switch on master clock */ +		ret = clk_prepare_enable(aic32x4->mclk); +		if (ret) { +			dev_err(codec->dev, "Failed to enable master clock\n"); +			return ret; +		} +  		/* Switch on PLL */  		snd_soc_update_bits(codec, AIC32X4_PLLPR,  				    AIC32X4_PLLEN, AIC32X4_PLLEN); @@ -541,29 +534,32 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_PREPARE:  		break;  	case SND_SOC_BIAS_STANDBY: -		/* Switch off PLL */ -		snd_soc_update_bits(codec, AIC32X4_PLLPR, -				    AIC32X4_PLLEN, 0); +		/* Switch off BCLK_N Divider */ +		snd_soc_update_bits(codec, AIC32X4_BCLKN, +				    AIC32X4_BCLKEN, 0); -		/* Switch off NDAC Divider */ -		snd_soc_update_bits(codec, AIC32X4_NDAC, -				    AIC32X4_NDACEN, 0); +		/* Switch off MADC Divider */ +		snd_soc_update_bits(codec, AIC32X4_MADC, +				    AIC32X4_MADCEN, 0); + +		/* Switch off NADC Divider */ +		snd_soc_update_bits(codec, AIC32X4_NADC, +				    AIC32X4_NADCEN, 0);  		/* Switch off MDAC Divider */  		snd_soc_update_bits(codec, AIC32X4_MDAC,  				    AIC32X4_MDACEN, 0); -		/* Switch off NADC Divider */ -		snd_soc_update_bits(codec, AIC32X4_NADC, -				    AIC32X4_NADCEN, 0); +		/* Switch off NDAC Divider */ +		snd_soc_update_bits(codec, AIC32X4_NDAC, +				    AIC32X4_NDACEN, 0); -		/* Switch off MADC Divider */ -		snd_soc_update_bits(codec, AIC32X4_MADC, -				    AIC32X4_MADCEN, 0); +		/* Switch off PLL */ +		snd_soc_update_bits(codec, AIC32X4_PLLPR, +				    AIC32X4_PLLEN, 0); -		/* Switch off BCLK_N Divider */ -		snd_soc_update_bits(codec, AIC32X4_BCLKN, -				    AIC32X4_BCLKEN, 0); +		/* Switch off master clock */ +		clk_disable_unprepare(aic32x4->mclk);  		break;  	case SND_SOC_BIAS_OFF:  		break; @@ -617,16 +613,8 @@ static int aic32x4_probe(struct snd_soc_codec *codec)  {  	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);  	u32 tmp_reg; -	int ret; - -	codec->hw_write = (hw_write_t) i2c_master_send; -	codec->control_data = aic32x4->control_data; -	if (aic32x4->rstn_gpio >= 0) { -		ret = devm_gpio_request_one(codec->dev, aic32x4->rstn_gpio, -				GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); -		if (ret != 0) -			return ret; +	if (gpio_is_valid(aic32x4->rstn_gpio)) {  		ndelay(10);  		gpio_set_value(aic32x4->rstn_gpio, 1);  	} @@ -655,20 +643,15 @@ static int aic32x4_probe(struct snd_soc_codec *codec)  	}  	snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg); -	/* Do DACs need to be swapped? */ -	if (aic32x4->swapdacs) { -		snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2RCHN | AIC32X4_RDAC2LCHN); -	} else { -		snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN); -	} -  	/* Mic PGA routing */ -	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) { +	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)  		snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K); -	} -	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) { +	else +		snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_CM1L_10K); +	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)  		snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K); -	} +	else +		snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_CM1R_10K);  	aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -692,8 +675,6 @@ static int aic32x4_remove(struct snd_soc_codec *codec)  }  static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { -	.read = aic32x4_read, -	.write = aic32x4_write,  	.probe = aic32x4_probe,  	.remove = aic32x4_remove,  	.suspend = aic32x4_suspend, @@ -708,11 +689,122 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {  	.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),  }; +static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, +		struct device_node *np) +{ +	aic32x4->swapdacs = false; +	aic32x4->micpga_routing = 0; +	aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0); + +	return 0; +} + +static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4) +{ +	regulator_disable(aic32x4->supply_iov); + +	if (!IS_ERR(aic32x4->supply_ldo)) +		regulator_disable(aic32x4->supply_ldo); + +	if (!IS_ERR(aic32x4->supply_dv)) +		regulator_disable(aic32x4->supply_dv); + +	if (!IS_ERR(aic32x4->supply_av)) +		regulator_disable(aic32x4->supply_av); +} + +static int aic32x4_setup_regulators(struct device *dev, +		struct aic32x4_priv *aic32x4) +{ +	int ret = 0; + +	aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin"); +	aic32x4->supply_iov = devm_regulator_get(dev, "iov"); +	aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv"); +	aic32x4->supply_av = devm_regulator_get_optional(dev, "av"); + +	/* Check if the regulator requirements are fulfilled */ + +	if (IS_ERR(aic32x4->supply_iov)) { +		dev_err(dev, "Missing supply 'iov'\n"); +		return PTR_ERR(aic32x4->supply_iov); +	} + +	if (IS_ERR(aic32x4->supply_ldo)) { +		if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER) +			return -EPROBE_DEFER; + +		if (IS_ERR(aic32x4->supply_dv)) { +			dev_err(dev, "Missing supply 'dv' or 'ldoin'\n"); +			return PTR_ERR(aic32x4->supply_dv); +		} +		if (IS_ERR(aic32x4->supply_av)) { +			dev_err(dev, "Missing supply 'av' or 'ldoin'\n"); +			return PTR_ERR(aic32x4->supply_av); +		} +	} else { +		if (IS_ERR(aic32x4->supply_dv) && +				PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER) +			return -EPROBE_DEFER; +		if (IS_ERR(aic32x4->supply_av) && +				PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER) +			return -EPROBE_DEFER; +	} + +	ret = regulator_enable(aic32x4->supply_iov); +	if (ret) { +		dev_err(dev, "Failed to enable regulator iov\n"); +		return ret; +	} + +	if (!IS_ERR(aic32x4->supply_ldo)) { +		ret = regulator_enable(aic32x4->supply_ldo); +		if (ret) { +			dev_err(dev, "Failed to enable regulator ldo\n"); +			goto error_ldo; +		} +	} + +	if (!IS_ERR(aic32x4->supply_dv)) { +		ret = regulator_enable(aic32x4->supply_dv); +		if (ret) { +			dev_err(dev, "Failed to enable regulator dv\n"); +			goto error_dv; +		} +	} + +	if (!IS_ERR(aic32x4->supply_av)) { +		ret = regulator_enable(aic32x4->supply_av); +		if (ret) { +			dev_err(dev, "Failed to enable regulator av\n"); +			goto error_av; +		} +	} + +	if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av)) +		aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE; + +	return 0; + +error_av: +	if (!IS_ERR(aic32x4->supply_dv)) +		regulator_disable(aic32x4->supply_dv); + +error_dv: +	if (!IS_ERR(aic32x4->supply_ldo)) +		regulator_disable(aic32x4->supply_ldo); + +error_ldo: +	regulator_disable(aic32x4->supply_iov); +	return ret; +} +  static int aic32x4_i2c_probe(struct i2c_client *i2c,  			     const struct i2c_device_id *id)  {  	struct aic32x4_pdata *pdata = i2c->dev.platform_data;  	struct aic32x4_priv *aic32x4; +	struct device_node *np = i2c->dev.of_node;  	int ret;  	aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv), @@ -720,7 +812,10 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,  	if (aic32x4 == NULL)  		return -ENOMEM; -	aic32x4->control_data = i2c; +	aic32x4->regmap = devm_regmap_init_i2c(i2c, &aic32x4_regmap); +	if (IS_ERR(aic32x4->regmap)) +		return PTR_ERR(aic32x4->regmap); +  	i2c_set_clientdata(i2c, aic32x4);  	if (pdata) { @@ -728,6 +823,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,  		aic32x4->swapdacs = pdata->swapdacs;  		aic32x4->micpga_routing = pdata->micpga_routing;  		aic32x4->rstn_gpio = pdata->rstn_gpio; +	} else if (np) { +		ret = aic32x4_parse_dt(aic32x4, np); +		if (ret) { +			dev_err(&i2c->dev, "Failed to parse DT node\n"); +			return ret; +		}  	} else {  		aic32x4->power_cfg = 0;  		aic32x4->swapdacs = false; @@ -735,13 +836,44 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,  		aic32x4->rstn_gpio = -1;  	} +	aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); +	if (IS_ERR(aic32x4->mclk)) { +		dev_err(&i2c->dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n"); +		return PTR_ERR(aic32x4->mclk); +	} + +	if (gpio_is_valid(aic32x4->rstn_gpio)) { +		ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, +				GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); +		if (ret != 0) +			return ret; +	} + +	ret = aic32x4_setup_regulators(&i2c->dev, aic32x4); +	if (ret) { +		dev_err(&i2c->dev, "Failed to setup regulators\n"); +		return ret; +	} +  	ret = snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_aic32x4, &aic32x4_dai, 1); -	return ret; +	if (ret) { +		dev_err(&i2c->dev, "Failed to register codec\n"); +		aic32x4_disable_regulators(aic32x4); +		return ret; +	} + +	i2c_set_clientdata(i2c, aic32x4); + +	return 0;  }  static int aic32x4_i2c_remove(struct i2c_client *client)  { +	struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client); + +	aic32x4_disable_regulators(aic32x4); +  	snd_soc_unregister_codec(&client->dev);  	return 0;  } @@ -752,10 +884,17 @@ static const struct i2c_device_id aic32x4_i2c_id[] = {  };  MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); +static const struct of_device_id aic32x4_of_id[] = { +	{ .compatible = "ti,tlv320aic32x4", }, +	{ /* senitel */ } +}; +MODULE_DEVICE_TABLE(of, aic32x4_of_id); +  static struct i2c_driver aic32x4_i2c_driver = {  	.driver = {  		.name = "tlv320aic32x4",  		.owner = THIS_MODULE, +		.of_match_table = aic32x4_of_id,  	},  	.probe =    aic32x4_i2c_probe,  	.remove =   aic32x4_i2c_remove, diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 35774223fd9..995f033a855 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -120,7 +120,9 @@  #define AIC32X4_MICBIAS_2075V		0x60  #define AIC32X4_LMICPGANIN_IN2R_10K	0x10 +#define AIC32X4_LMICPGANIN_CM1L_10K	0x40  #define AIC32X4_RMICPGANIN_IN1L_10K	0x10 +#define AIC32X4_RMICPGANIN_CM1R_10K	0x40  #define AIC32X4_LMICPGAVOL_NOGAIN	0x80  #define AIC32X4_RMICPGAVOL_NOGAIN	0x80 @@ -138,6 +140,7 @@  #define AIC32X4_LDAC2RCHN		(0x02 << 4)  #define AIC32X4_LDAC2LCHN		(0x01 << 4)  #define AIC32X4_RDAC2RCHN		(0x01 << 2) +#define AIC32X4_DAC_CHAN_MASK		0x3c  #define AIC32X4_SSTEP2WCLK		0x01  #define AIC32X4_MUTEON			0x0C diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6e3f269243e..e12fafbb1e0 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -40,6 +40,7 @@  #include <linux/i2c.h>  #include <linux/gpio.h>  #include <linux/regulator/consumer.h> +#include <linux/of.h>  #include <linux/of_gpio.h>  #include <linux/slab.h>  #include <sound/core.h> @@ -72,9 +73,9 @@ struct aic3x_disable_nb {  /* codec private data */  struct aic3x_priv {  	struct snd_soc_codec *codec; +	struct regmap *regmap;  	struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];  	struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; -	enum snd_soc_control_type control_type;  	struct aic3x_setup_data *setup;  	unsigned int sysclk;  	struct list_head list; @@ -90,41 +91,45 @@ struct aic3x_priv {  	enum aic3x_micbias_voltage micbias_vg;  }; -/* - * AIC3X register cache - * We can't read the AIC3X register space when we are - * using 2 wire for device control, so we cache them instead. - * There is no point in caching the reset register - */ -static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { -	0x00, 0x00, 0x00, 0x10,	/* 0 */ -	0x04, 0x00, 0x00, 0x00,	/* 4 */ -	0x00, 0x00, 0x00, 0x01,	/* 8 */ -	0x00, 0x00, 0x00, 0x80,	/* 12 */ -	0x80, 0xff, 0xff, 0x78,	/* 16 */ -	0x78, 0x78, 0x78, 0x78,	/* 20 */ -	0x78, 0x00, 0x00, 0xfe,	/* 24 */ -	0x00, 0x00, 0xfe, 0x00,	/* 28 */ -	0x18, 0x18, 0x00, 0x00,	/* 32 */ -	0x00, 0x00, 0x00, 0x00,	/* 36 */ -	0x00, 0x00, 0x00, 0x80,	/* 40 */ -	0x80, 0x00, 0x00, 0x00,	/* 44 */ -	0x00, 0x00, 0x00, 0x04,	/* 48 */ -	0x00, 0x00, 0x00, 0x00,	/* 52 */ -	0x00, 0x00, 0x04, 0x00,	/* 56 */ -	0x00, 0x00, 0x00, 0x00,	/* 60 */ -	0x00, 0x04, 0x00, 0x00,	/* 64 */ -	0x00, 0x00, 0x00, 0x00,	/* 68 */ -	0x04, 0x00, 0x00, 0x00,	/* 72 */ -	0x00, 0x00, 0x00, 0x00,	/* 76 */ -	0x00, 0x00, 0x00, 0x00,	/* 80 */ -	0x00, 0x00, 0x00, 0x00,	/* 84 */ -	0x00, 0x00, 0x00, 0x00,	/* 88 */ -	0x00, 0x00, 0x00, 0x00,	/* 92 */ -	0x00, 0x00, 0x00, 0x00,	/* 96 */ -	0x00, 0x00, 0x02, 0x00,	/* 100 */ -	0x00, 0x00, 0x00, 0x00,	/* 104 */ -	0x00, 0x00,            	/* 108 */ +static const struct reg_default aic3x_reg[] = { +	{   0, 0x00 }, {   1, 0x00 }, {   2, 0x00 }, {   3, 0x10 }, +	{   4, 0x04 }, {   5, 0x00 }, {   6, 0x00 }, {   7, 0x00 }, +	{   8, 0x00 }, {   9, 0x00 }, {  10, 0x00 }, {  11, 0x01 }, +	{  12, 0x00 }, {  13, 0x00 }, {  14, 0x00 }, {  15, 0x80 }, +	{  16, 0x80 }, {  17, 0xff }, {  18, 0xff }, {  19, 0x78 }, +	{  20, 0x78 }, {  21, 0x78 }, {  22, 0x78 }, {  23, 0x78 }, +	{  24, 0x78 }, {  25, 0x00 }, {  26, 0x00 }, {  27, 0xfe }, +	{  28, 0x00 }, {  29, 0x00 }, {  30, 0xfe }, {  31, 0x00 }, +	{  32, 0x18 }, {  33, 0x18 }, {  34, 0x00 }, {  35, 0x00 }, +	{  36, 0x00 }, {  37, 0x00 }, {  38, 0x00 }, {  39, 0x00 }, +	{  40, 0x00 }, {  41, 0x00 }, {  42, 0x00 }, {  43, 0x80 }, +	{  44, 0x80 }, {  45, 0x00 }, {  46, 0x00 }, {  47, 0x00 }, +	{  48, 0x00 }, {  49, 0x00 }, {  50, 0x00 }, {  51, 0x04 }, +	{  52, 0x00 }, {  53, 0x00 }, {  54, 0x00 }, {  55, 0x00 }, +	{  56, 0x00 }, {  57, 0x00 }, {  58, 0x04 }, {  59, 0x00 }, +	{  60, 0x00 }, {  61, 0x00 }, {  62, 0x00 }, {  63, 0x00 }, +	{  64, 0x00 }, {  65, 0x04 }, {  66, 0x00 }, {  67, 0x00 }, +	{  68, 0x00 }, {  69, 0x00 }, {  70, 0x00 }, {  71, 0x00 }, +	{  72, 0x04 }, {  73, 0x00 }, {  74, 0x00 }, {  75, 0x00 }, +	{  76, 0x00 }, {  77, 0x00 }, {  78, 0x00 }, {  79, 0x00 }, +	{  80, 0x00 }, {  81, 0x00 }, {  82, 0x00 }, {  83, 0x00 }, +	{  84, 0x00 }, {  85, 0x00 }, {  86, 0x00 }, {  87, 0x00 }, +	{  88, 0x00 }, {  89, 0x00 }, {  90, 0x00 }, {  91, 0x00 }, +	{  92, 0x00 }, {  93, 0x00 }, {  94, 0x00 }, {  95, 0x00 }, +	{  96, 0x00 }, {  97, 0x00 }, {  98, 0x00 }, {  99, 0x00 }, +	{ 100, 0x00 }, { 101, 0x00 }, { 102, 0x02 }, { 103, 0x00 }, +	{ 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 }, +	{ 108, 0x00 }, { 109, 0x00 }, +}; + +static const struct regmap_config aic3x_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = DAC_ICC_ADJ, +	.reg_defaults = aic3x_reg, +	.num_reg_defaults = ARRAY_SIZE(aic3x_reg), +	.cache_type = REGCACHE_RBTREE,  };  #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ @@ -164,7 +169,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,  	mask <<= shift;  	val <<= shift; -	change = snd_soc_test_bits(codec, val, mask, reg); +	change = snd_soc_test_bits(codec, reg, mask, val);  	if (change) {  		update.kcontrol = kcontrol;  		update.reg = reg; @@ -345,16 +350,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {  			 DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,  			 0, 118, 1, output_stage_tlv), -	SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume", -			 LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, -			 0, 118, 1, output_stage_tlv), -	SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume", -			 PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL, -			 0, 118, 1, output_stage_tlv), -	SOC_DOUBLE_R_TLV("Mono DAC Playback Volume", -			 DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL, -			 0, 118, 1, output_stage_tlv), -  	SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",  			 LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,  			 0, 118, 1, output_stage_tlv), @@ -378,7 +373,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {  	/* Output pin mute controls */  	SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,  		     0x01, 0), -	SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),  	SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,  		     0x01, 0),  	SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, @@ -407,6 +401,20 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {  	SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),  }; +static const struct snd_kcontrol_new aic3x_mono_controls[] = { +	SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume", +			 LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, +			 0, 118, 1, output_stage_tlv), +	SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume", +			 PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL, +			 0, 118, 1, output_stage_tlv), +	SOC_DOUBLE_R_TLV("Mono DAC Playback Volume", +			 DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL, +			 0, 118, 1, output_stage_tlv), + +	SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), +}; +  /*   * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps   */ @@ -560,9 +568,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {  	SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),  	SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0), -	/* Mono Output */ -	SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), -  	/* Inputs to Left ADC */  	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),  	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, @@ -621,9 +626,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {  	SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,  			   &aic3x_right_line_mixer_controls[0],  			   ARRAY_SIZE(aic3x_right_line_mixer_controls)), -	SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, -			   &aic3x_mono_mixer_controls[0], -			   ARRAY_SIZE(aic3x_mono_mixer_controls)),  	SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,  			   &aic3x_left_hp_mixer_controls[0],  			   ARRAY_SIZE(aic3x_left_hp_mixer_controls)), @@ -639,7 +641,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("LLOUT"),  	SND_SOC_DAPM_OUTPUT("RLOUT"), -	SND_SOC_DAPM_OUTPUT("MONO_LOUT"),  	SND_SOC_DAPM_OUTPUT("HPLOUT"),  	SND_SOC_DAPM_OUTPUT("HPROUT"),  	SND_SOC_DAPM_OUTPUT("HPLCOM"), @@ -661,6 +662,17 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("Detection"),  }; +static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = { +	/* Mono Output */ +	SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), + +	SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, +			   &aic3x_mono_mixer_controls[0], +			   ARRAY_SIZE(aic3x_mono_mixer_controls)), + +	SND_SOC_DAPM_OUTPUT("MONO_LOUT"), +}; +  static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {  	/* Class-D outputs */  	SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0), @@ -674,6 +686,8 @@ static const struct snd_soc_dapm_route intercon[] = {  	/* Left Input */  	{"Left Line1L Mux", "single-ended", "LINE1L"},  	{"Left Line1L Mux", "differential", "LINE1L"}, +	{"Left Line1R Mux", "single-ended", "LINE1R"}, +	{"Left Line1R Mux", "differential", "LINE1R"},  	{"Left Line2L Mux", "single-ended", "LINE2L"},  	{"Left Line2L Mux", "differential", "LINE2L"}, @@ -690,6 +704,8 @@ static const struct snd_soc_dapm_route intercon[] = {  	/* Right Input */  	{"Right Line1R Mux", "single-ended", "LINE1R"},  	{"Right Line1R Mux", "differential", "LINE1R"}, +	{"Right Line1L Mux", "single-ended", "LINE1L"}, +	{"Right Line1L Mux", "differential", "LINE1L"},  	{"Right Line2R Mux", "single-ended", "LINE2R"},  	{"Right Line2R Mux", "differential", "LINE2R"}, @@ -745,17 +761,6 @@ static const struct snd_soc_dapm_route intercon[] = {  	{"Right Line Out", NULL, "Right DAC Mux"},  	{"RLOUT", NULL, "Right Line Out"}, -	/* Mono Output */ -	{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, -	{"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, -	{"Mono Mixer", "DACL1 Switch", "Left DAC Mux"}, -	{"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, -	{"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, -	{"Mono Mixer", "DACR1 Switch", "Right DAC Mux"}, - -	{"Mono Out", NULL, "Mono Mixer"}, -	{"MONO_LOUT", NULL, "Mono Out"}, -  	/* Left HP Output */  	{"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},  	{"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, @@ -811,6 +816,18 @@ static const struct snd_soc_dapm_route intercon[] = {  	{"HPRCOM", NULL, "Right HP Com"},  }; +static const struct snd_soc_dapm_route intercon_mono[] = { +	/* Mono Output */ +	{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, +	{"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, +	{"Mono Mixer", "DACL1 Switch", "Left DAC Mux"}, +	{"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, +	{"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, +	{"Mono Mixer", "DACR1 Switch", "Right DAC Mux"}, +	{"Mono Out", NULL, "Mono Mixer"}, +	{"MONO_LOUT", NULL, "Mono Out"}, +}; +  static const struct snd_soc_dapm_route intercon_3007[] = {  	/* Class-D outputs */  	{"Left Class-D Out", NULL, "Left Line Out"}, @@ -824,17 +841,20 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)  	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);  	struct snd_soc_dapm_context *dapm = &codec->dapm; -	snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets, -				  ARRAY_SIZE(aic3x_dapm_widgets)); - -	/* set up audio path interconnects */ -	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - -	if (aic3x->model == AIC3X_MODEL_3007) { +	switch (aic3x->model) { +	case AIC3X_MODEL_3X: +	case AIC3X_MODEL_33: +		snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets, +			ARRAY_SIZE(aic3x_dapm_mono_widgets)); +		snd_soc_dapm_add_routes(dapm, intercon_mono, +					ARRAY_SIZE(intercon_mono)); +		break; +	case AIC3X_MODEL_3007:  		snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,  			ARRAY_SIZE(aic3007_dapm_widgets));  		snd_soc_dapm_add_routes(dapm, intercon_3007,  					ARRAY_SIZE(intercon_3007)); +		break;  	}  	return 0; @@ -1078,29 +1098,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,  	return 0;  } -static int aic3x_init_3007(struct snd_soc_codec *codec) -{ -	u8 tmp1, tmp2, *cache = codec->reg_cache; - -	/* -	 * There is no need to cache writes to undocumented page 0xD but -	 * respective page 0 register cache entries must be preserved -	 */ -	tmp1 = cache[0xD]; -	tmp2 = cache[0x8]; -	/* Class-D speaker driver init; datasheet p. 46 */ -	snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); -	snd_soc_write(codec, 0xD, 0x0D); -	snd_soc_write(codec, 0x8, 0x5C); -	snd_soc_write(codec, 0x8, 0x5D); -	snd_soc_write(codec, 0x8, 0x5C); -	snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); -	cache[0xD] = tmp1; -	cache[0x8] = tmp2; - -	return 0; -} -  static int aic3x_regulator_event(struct notifier_block *nb,  				 unsigned long event, void *data)  { @@ -1115,7 +1112,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,  		 */  		if (gpio_is_valid(aic3x->gpio_reset))  			gpio_set_value(aic3x->gpio_reset, 0); -		aic3x->codec->cache_sync = 1; +		regcache_mark_dirty(aic3x->regmap);  	}  	return 0; @@ -1124,8 +1121,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,  static int aic3x_set_power(struct snd_soc_codec *codec, int power)  {  	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); -	int i, ret; -	u8 *cache = codec->reg_cache; +	int ret;  	if (power) {  		ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), @@ -1133,12 +1129,6 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)  		if (ret)  			goto out;  		aic3x->power = 1; -		/* -		 * Reset release and cache sync is necessary only if some -		 * supply was off or if there were cached writes -		 */ -		if (!codec->cache_sync) -			goto out;  		if (gpio_is_valid(aic3x->gpio_reset)) {  			udelay(1); @@ -1146,12 +1136,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)  		}  		/* Sync reg_cache with the hardware */ -		codec->cache_only = 0; -		for (i = AIC3X_SAMPLE_RATE_SEL_REG; i < ARRAY_SIZE(aic3x_reg); i++) -			snd_soc_write(codec, i, cache[i]); -		if (aic3x->model == AIC3X_MODEL_3007) -			aic3x_init_3007(codec); -		codec->cache_sync = 0; +		regcache_cache_only(aic3x->regmap, false); +		regcache_sync(aic3x->regmap);  	} else {  		/*  		 * Do soft reset to this codec instance in order to clear @@ -1159,10 +1145,10 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)  		 * remain on  		 */  		snd_soc_write(codec, AIC3X_RESET, SOFT_RESET); -		codec->cache_sync = 1; +		regcache_mark_dirty(aic3x->regmap);  		aic3x->power = 0;  		/* HW writes are needless when bias is off */ -		codec->cache_only = 1; +		regcache_cache_only(aic3x->regmap, true);  		ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),  					     aic3x->supplies);  	} @@ -1249,6 +1235,24 @@ static int aic3x_resume(struct snd_soc_codec *codec)  	return 0;  } +static void aic3x_mono_init(struct snd_soc_codec *codec) +{ +	/* DAC to Mono Line Out default volume and route to Output mixer */ +	snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); +	snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); + +	/* unmute all outputs */ +	snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE); + +	/* PGA to Mono Line Out default volume, disconnect from Output Mixer */ +	snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); +	snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); + +	/* Line2 to Mono Out default volume, disconnect from Output Mixer */ +	snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); +	snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); +} +  /*   * initialise the AIC3X driver   * register the mixer and dsp interfaces with the kernel @@ -1272,14 +1276,10 @@ static int aic3x_init(struct snd_soc_codec *codec)  	/* DAC to Line Out default volume and route to Output mixer */  	snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);  	snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); -	/* DAC to Mono Line Out default volume and route to Output mixer */ -	snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); -	snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);  	/* unmute all outputs */  	snd_soc_update_bits(codec, LLOPM_CTRL, UNMUTE, UNMUTE);  	snd_soc_update_bits(codec, RLOPM_CTRL, UNMUTE, UNMUTE); -	snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);  	snd_soc_update_bits(codec, HPLOUT_CTRL, UNMUTE, UNMUTE);  	snd_soc_update_bits(codec, HPROUT_CTRL, UNMUTE, UNMUTE);  	snd_soc_update_bits(codec, HPLCOM_CTRL, UNMUTE, UNMUTE); @@ -1300,9 +1300,6 @@ static int aic3x_init(struct snd_soc_codec *codec)  	/* PGA to Line Out default volume, disconnect from Output Mixer */  	snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);  	snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); -	/* PGA to Mono Line Out default volume, disconnect from Output Mixer */ -	snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); -	snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);  	/* Line2 to HP Bypass default volume, disconnect from Output Mixer */  	snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); @@ -1312,13 +1309,15 @@ static int aic3x_init(struct snd_soc_codec *codec)  	/* Line2 Line Out default volume, disconnect from Output Mixer */  	snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);  	snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); -	/* Line2 to Mono Out default volume, disconnect from Output Mixer */ -	snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); -	snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); -	if (aic3x->model == AIC3X_MODEL_3007) { -		aic3x_init_3007(codec); +	switch (aic3x->model) { +	case AIC3X_MODEL_3X: +	case AIC3X_MODEL_33: +		aic3x_mono_init(codec); +		break; +	case AIC3X_MODEL_3007:  		snd_soc_write(codec, CLASSD_CTRL, 0); +		break;  	}  	return 0; @@ -1345,29 +1344,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)  	INIT_LIST_HEAD(&aic3x->list);  	aic3x->codec = codec; -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	if (gpio_is_valid(aic3x->gpio_reset) && -	    !aic3x_is_shared_reset(aic3x)) { -		ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); -		if (ret != 0) -			goto err_gpio; -		gpio_direction_output(aic3x->gpio_reset, 0); -	} - -	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) -		aic3x->supplies[i].supply = aic3x_supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), -				 aic3x->supplies); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); -		goto err_get; -	}  	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {  		aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;  		aic3x->disable_nb[i].aic3x = aic3x; @@ -1381,7 +1357,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)  		}  	} -	codec->cache_only = 1; +	regcache_mark_dirty(aic3x->regmap);  	aic3x_init(codec);  	if (aic3x->setup) { @@ -1392,10 +1368,17 @@ static int aic3x_probe(struct snd_soc_codec *codec)  			      (aic3x->setup->gpio_func[1] & 0xf) << 4);  	} -	snd_soc_add_codec_controls(codec, aic3x_snd_controls, -			     ARRAY_SIZE(aic3x_snd_controls)); -	if (aic3x->model == AIC3X_MODEL_3007) -		snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); +	switch (aic3x->model) { +	case AIC3X_MODEL_3X: +	case AIC3X_MODEL_33: +		snd_soc_add_codec_controls(codec, aic3x_mono_controls, +				ARRAY_SIZE(aic3x_mono_controls)); +		break; +	case AIC3X_MODEL_3007: +		snd_soc_add_codec_controls(codec, +				&aic3x_classd_amp_gain_ctrl, 1); +		break; +	}  	/* set mic bias voltage */  	switch (aic3x->micbias_vg) { @@ -1416,7 +1399,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)  	}  	aic3x_add_widgets(codec); -	list_add(&aic3x->list, &reset_list);  	return 0; @@ -1424,12 +1406,6 @@ err_notif:  	while (i--)  		regulator_unregister_notifier(aic3x->supplies[i].consumer,  					      &aic3x->disable_nb[i].nb); -	regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); -err_get: -	if (gpio_is_valid(aic3x->gpio_reset) && -	    !aic3x_is_shared_reset(aic3x)) -		gpio_free(aic3x->gpio_reset); -err_gpio:  	return ret;  } @@ -1440,15 +1416,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)  	aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);  	list_del(&aic3x->list); -	if (gpio_is_valid(aic3x->gpio_reset) && -	    !aic3x_is_shared_reset(aic3x)) { -		gpio_set_value(aic3x->gpio_reset, 0); -		gpio_free(aic3x->gpio_reset); -	}  	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)  		regulator_unregister_notifier(aic3x->supplies[i].consumer,  					      &aic3x->disable_nb[i].nb); -	regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);  	return 0;  } @@ -1456,13 +1426,16 @@ static int aic3x_remove(struct snd_soc_codec *codec)  static struct snd_soc_codec_driver soc_codec_dev_aic3x = {  	.set_bias_level = aic3x_set_bias_level,  	.idle_bias_off = true, -	.reg_cache_size = ARRAY_SIZE(aic3x_reg), -	.reg_word_size = sizeof(u8), -	.reg_cache_default = aic3x_reg,  	.probe = aic3x_probe,  	.remove = aic3x_remove,  	.suspend = aic3x_suspend,  	.resume = aic3x_resume, +	.controls = aic3x_snd_controls, +	.num_controls = ARRAY_SIZE(aic3x_snd_controls), +	.dapm_widgets = aic3x_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets), +	.dapm_routes = intercon, +	.num_dapm_routes = ARRAY_SIZE(intercon),  };  /* @@ -1479,6 +1452,16 @@ static const struct i2c_device_id aic3x_i2c_id[] = {  };  MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); +static const struct reg_default aic3007_class_d[] = { +	/* Class-D speaker driver init; datasheet p. 46 */ +	{ AIC3X_PAGE_SELECT, 0x0D }, +	{ 0xD, 0x0D }, +	{ 0x8, 0x5C }, +	{ 0x8, 0x5D }, +	{ 0x8, 0x5C }, +	{ AIC3X_PAGE_SELECT, 0x00 }, +}; +  /*   * If the i2c layer weren't so broken, we could pass this kind of data   * around @@ -1490,7 +1473,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,  	struct aic3x_priv *aic3x;  	struct aic3x_setup_data *ai3x_setup;  	struct device_node *np = i2c->dev.of_node; -	int ret; +	int ret, i;  	u32 value;  	aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); @@ -1499,7 +1482,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,  		return -ENOMEM;  	} -	aic3x->control_type = SND_SOC_I2C; +	aic3x->regmap = devm_regmap_init_i2c(i2c, &aic3x_regmap); +	if (IS_ERR(aic3x->regmap)) { +		ret = PTR_ERR(aic3x->regmap); +		return ret; +	} + +	regcache_cache_only(aic3x->regmap, true);  	i2c_set_clientdata(i2c, aic3x);  	if (pdata) { @@ -1551,14 +1540,60 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,  	aic3x->model = id->driver_data; +	if (gpio_is_valid(aic3x->gpio_reset) && +	    !aic3x_is_shared_reset(aic3x)) { +		ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); +		if (ret != 0) +			goto err; +		gpio_direction_output(aic3x->gpio_reset, 0); +	} + +	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) +		aic3x->supplies[i].supply = aic3x_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies), +				      aic3x->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); +		goto err_gpio; +	} + +	if (aic3x->model == AIC3X_MODEL_3007) { +		ret = regmap_register_patch(aic3x->regmap, aic3007_class_d, +					    ARRAY_SIZE(aic3007_class_d)); +		if (ret != 0) +			dev_err(&i2c->dev, "Failed to init class D: %d\n", +				ret); +	} +  	ret = snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_aic3x, &aic3x_dai, 1); + +	if (ret != 0) +		goto err_gpio; + +	list_add(&aic3x->list, &reset_list); + +	return 0; + +err_gpio: +	if (gpio_is_valid(aic3x->gpio_reset) && +	    !aic3x_is_shared_reset(aic3x)) +		gpio_free(aic3x->gpio_reset); +err:  	return ret;  }  static int aic3x_i2c_remove(struct i2c_client *client)  { +	struct aic3x_priv *aic3x = i2c_get_clientdata(client); +  	snd_soc_unregister_codec(&client->dev); +	if (gpio_is_valid(aic3x->gpio_reset) && +	    !aic3x_is_shared_reset(aic3x)) { +		gpio_set_value(aic3x->gpio_reset, 0); +		gpio_free(aic3x->gpio_reset); +	}  	return 0;  } diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 4f358393d6d..df3a7506c02 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -122,7 +122,6 @@ struct tlv320dac33_priv {  	unsigned int uthr;  	enum dac33_state state; -	enum snd_soc_control_type control_type;  	void *control_data;  }; @@ -443,7 +442,7 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w,  static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,  			 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = dac33->fifo_mode; @@ -454,14 +453,14 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,  static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,  			 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);  	int ret = 0;  	if (dac33->fifo_mode == ucontrol->value.integer.value[0])  		return 0;  	/* Do not allow changes while stream is running*/ -	if (codec->active) +	if (snd_soc_codec_is_active(codec))  		return -EPERM;  	if (ucontrol->value.integer.value[0] < 0 || @@ -478,9 +477,7 @@ static const char *dac33_fifo_mode_texts[] = {  	"Bypass", "Mode 1", "Mode 7"  }; -static const struct soc_enum dac33_fifo_mode_enum = -	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts), -			    dac33_fifo_mode_texts); +static SOC_ENUM_SINGLE_EXT_DECL(dac33_fifo_mode_enum, dac33_fifo_mode_texts);  /* L/R Line Output Gain */  static const char *lr_lineout_gain_texts[] = { @@ -488,15 +485,13 @@ static const char *lr_lineout_gain_texts[] = {  	"Line 0dB DAC 12dB", "Line 6dB DAC 18dB",  }; -static const struct soc_enum l_lineout_gain_enum = -	SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0, -			ARRAY_SIZE(lr_lineout_gain_texts), -			lr_lineout_gain_texts); +static SOC_ENUM_SINGLE_DECL(l_lineout_gain_enum, +			    DAC33_LDAC_PWR_CTRL, 0, +			    lr_lineout_gain_texts); -static const struct soc_enum r_lineout_gain_enum = -	SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0, -			ARRAY_SIZE(lr_lineout_gain_texts), -			lr_lineout_gain_texts); +static SOC_ENUM_SINGLE_DECL(r_lineout_gain_enum, +			    DAC33_RDAC_PWR_CTRL, 0, +			    lr_lineout_gain_texts);  /*   * DACL/R digital volume control: @@ -534,18 +529,16 @@ static const struct snd_kcontrol_new dac33_dapm_abypassr_control =  /* LOP L/R invert selection */  static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"}; -static const struct soc_enum dac33_left_lom_enum = -	SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 3, -			ARRAY_SIZE(dac33_lr_lom_texts), -			dac33_lr_lom_texts); +static SOC_ENUM_SINGLE_DECL(dac33_left_lom_enum, +			    DAC33_OUT_AMP_CTRL, 3, +			    dac33_lr_lom_texts);  static const struct snd_kcontrol_new dac33_dapm_left_lom_control =  SOC_DAPM_ENUM("Route", dac33_left_lom_enum); -static const struct soc_enum dac33_right_lom_enum = -	SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 2, -			ARRAY_SIZE(dac33_lr_lom_texts), -			dac33_lr_lom_texts); +static SOC_ENUM_SINGLE_DECL(dac33_right_lom_enum, +			    DAC33_OUT_AMP_CTRL, 2, +			    dac33_lr_lom_texts);  static const struct snd_kcontrol_new dac33_dapm_right_lom_control =  SOC_DAPM_ENUM("Route", dac33_right_lom_enum); @@ -1547,7 +1540,7 @@ static int dac33_i2c_probe(struct i2c_client *client,  	for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)  		dac33->supplies[i].supply = dac33_supply_names[i]; -	ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies), +	ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),  				 dac33->supplies);  	if (ret != 0) { @@ -1558,11 +1551,9 @@ static int dac33_i2c_probe(struct i2c_client *client,  	ret = snd_soc_register_codec(&client->dev,  			&soc_codec_dev_tlv320dac33, &dac33_dai, 1);  	if (ret < 0) -		goto err_register; +		goto err_get;  	return ret; -err_register: -	regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);  err_get:  	if (dac33->power_gpio >= 0)  		gpio_free(dac33->power_gpio); @@ -1580,8 +1571,6 @@ static int dac33_i2c_remove(struct i2c_client *client)  	if (dac33->power_gpio >= 0)  		gpio_free(dac33->power_gpio); -	regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); -  	snd_soc_unregister_codec(&client->dev);  	return 0;  } diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index c58bee8346c..8fc5a647453 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -30,6 +30,8 @@  #include <sound/tpa6130a2-plat.h>  #include <sound/soc.h>  #include <sound/tlv.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #include "tpa6130a2.h" @@ -55,7 +57,8 @@ static int tpa6130a2_i2c_read(int reg)  	struct tpa6130a2_data *data;  	int val; -	BUG_ON(tpa6130a2_client == NULL); +	if (WARN_ON(!tpa6130a2_client)) +		return -EINVAL;  	data = i2c_get_clientdata(tpa6130a2_client);  	/* If powered off, return the cached value */ @@ -77,7 +80,8 @@ static int tpa6130a2_i2c_write(int reg, u8 value)  	struct tpa6130a2_data *data;  	int val = 0; -	BUG_ON(tpa6130a2_client == NULL); +	if (WARN_ON(!tpa6130a2_client)) +		return -EINVAL;  	data = i2c_get_clientdata(tpa6130a2_client);  	if (data->power_state) { @@ -98,7 +102,8 @@ static u8 tpa6130a2_read(int reg)  {  	struct tpa6130a2_data *data; -	BUG_ON(tpa6130a2_client == NULL); +	if (WARN_ON(!tpa6130a2_client)) +		return 0;  	data = i2c_get_clientdata(tpa6130a2_client);  	return data->regs[reg]; @@ -109,7 +114,8 @@ static int tpa6130a2_initialize(void)  	struct tpa6130a2_data *data;  	int i, ret = 0; -	BUG_ON(tpa6130a2_client == NULL); +	if (WARN_ON(!tpa6130a2_client)) +		return -EINVAL;  	data = i2c_get_clientdata(tpa6130a2_client);  	for (i = 1; i < TPA6130A2_REG_VERSION; i++) { @@ -127,7 +133,8 @@ static int tpa6130a2_power(u8 power)  	u8	val;  	int	ret = 0; -	BUG_ON(tpa6130a2_client == NULL); +	if (WARN_ON(!tpa6130a2_client)) +		return -EINVAL;  	data = i2c_get_clientdata(tpa6130a2_client);  	mutex_lock(&data->mutex); @@ -193,7 +200,8 @@ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,  	unsigned int mask = (1 << fls(max)) - 1;  	unsigned int invert = mc->invert; -	BUG_ON(tpa6130a2_client == NULL); +	if (WARN_ON(!tpa6130a2_client)) +		return -EINVAL;  	data = i2c_get_clientdata(tpa6130a2_client);  	mutex_lock(&data->mutex); @@ -223,7 +231,8 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,  	unsigned int val = (ucontrol->value.integer.value[0] & mask);  	unsigned int val_reg; -	BUG_ON(tpa6130a2_client == NULL); +	if (WARN_ON(!tpa6130a2_client)) +		return -EINVAL;  	data = i2c_get_clientdata(tpa6130a2_client);  	if (invert) @@ -364,30 +373,33 @@ static int tpa6130a2_probe(struct i2c_client *client,  {  	struct device *dev;  	struct tpa6130a2_data *data; -	struct tpa6130a2_platform_data *pdata; +	struct tpa6130a2_platform_data *pdata = client->dev.platform_data; +	struct device_node *np = client->dev.of_node;  	const char *regulator;  	int ret;  	dev = &client->dev; -	if (client->dev.platform_data == NULL) { -		dev_err(dev, "Platform data not set\n"); -		dump_stack(); -		return -ENODEV; -	} -  	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);  	if (data == NULL) {  		dev_err(dev, "Can not allocate memory\n");  		return -ENOMEM;  	} +	if (pdata) { +		data->power_gpio = pdata->power_gpio; +	} else if (np) { +		data->power_gpio = of_get_named_gpio(np, "power-gpio", 0); +	} else { +		dev_err(dev, "Platform data not set\n"); +		dump_stack(); +		return -ENODEV; +	} +  	tpa6130a2_client = client;  	i2c_set_clientdata(tpa6130a2_client, data); -	pdata = client->dev.platform_data; -	data->power_gpio = pdata->power_gpio;  	data->id = id->driver_data;  	mutex_init(&data->mutex); @@ -466,10 +478,20 @@ static const struct i2c_device_id tpa6130a2_id[] = {  };  MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id tpa6130a2_of_match[] = { +	{ .compatible = "ti,tpa6130a2", }, +	{ .compatible = "ti,tpa6140a2" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, tpa6130a2_of_match); +#endif +  static struct i2c_driver tpa6130a2_i2c_driver = {  	.driver = {  		.name = "tpa6130a2",  		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(tpa6130a2_of_match),  	},  	.probe = tpa6130a2_probe,  	.remove = tpa6130a2_remove, diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1e3884d6b3f..69e12a311ba 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -46,94 +46,7 @@  /* TWL4030 PMBR1 Register GPIO6 mux bits */  #define TWL4030_GPIO6_PWM0_MUTE(value)	((value & 0x03) << 2) -/* Shadow register used by the audio driver */ -#define TWL4030_REG_SW_SHADOW		0x4A -#define TWL4030_CACHEREGNUM	(TWL4030_REG_SW_SHADOW + 1) - -/* TWL4030_REG_SW_SHADOW (0x4A) Fields */ -#define TWL4030_HFL_EN			0x01 -#define TWL4030_HFR_EN			0x02 - -/* - * twl4030 register cache & default register settings - */ -static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { -	0x00, /* this register not used		*/ -	0x00, /* REG_CODEC_MODE		(0x1)	*/ -	0x00, /* REG_OPTION		(0x2)	*/ -	0x00, /* REG_UNKNOWN		(0x3)	*/ -	0x00, /* REG_MICBIAS_CTL	(0x4)	*/ -	0x00, /* REG_ANAMICL		(0x5)	*/ -	0x00, /* REG_ANAMICR		(0x6)	*/ -	0x00, /* REG_AVADC_CTL		(0x7)	*/ -	0x00, /* REG_ADCMICSEL		(0x8)	*/ -	0x00, /* REG_DIGMIXING		(0x9)	*/ -	0x0f, /* REG_ATXL1PGA		(0xA)	*/ -	0x0f, /* REG_ATXR1PGA		(0xB)	*/ -	0x0f, /* REG_AVTXL2PGA		(0xC)	*/ -	0x0f, /* REG_AVTXR2PGA		(0xD)	*/ -	0x00, /* REG_AUDIO_IF		(0xE)	*/ -	0x00, /* REG_VOICE_IF		(0xF)	*/ -	0x3f, /* REG_ARXR1PGA		(0x10)	*/ -	0x3f, /* REG_ARXL1PGA		(0x11)	*/ -	0x3f, /* REG_ARXR2PGA		(0x12)	*/ -	0x3f, /* REG_ARXL2PGA		(0x13)	*/ -	0x25, /* REG_VRXPGA		(0x14)	*/ -	0x00, /* REG_VSTPGA		(0x15)	*/ -	0x00, /* REG_VRX2ARXPGA		(0x16)	*/ -	0x00, /* REG_AVDAC_CTL		(0x17)	*/ -	0x00, /* REG_ARX2VTXPGA		(0x18)	*/ -	0x32, /* REG_ARXL1_APGA_CTL	(0x19)	*/ -	0x32, /* REG_ARXR1_APGA_CTL	(0x1A)	*/ -	0x32, /* REG_ARXL2_APGA_CTL	(0x1B)	*/ -	0x32, /* REG_ARXR2_APGA_CTL	(0x1C)	*/ -	0x00, /* REG_ATX2ARXPGA		(0x1D)	*/ -	0x00, /* REG_BT_IF		(0x1E)	*/ -	0x55, /* REG_BTPGA		(0x1F)	*/ -	0x00, /* REG_BTSTPGA		(0x20)	*/ -	0x00, /* REG_EAR_CTL		(0x21)	*/ -	0x00, /* REG_HS_SEL		(0x22)	*/ -	0x00, /* REG_HS_GAIN_SET	(0x23)	*/ -	0x00, /* REG_HS_POPN_SET	(0x24)	*/ -	0x00, /* REG_PREDL_CTL		(0x25)	*/ -	0x00, /* REG_PREDR_CTL		(0x26)	*/ -	0x00, /* REG_PRECKL_CTL		(0x27)	*/ -	0x00, /* REG_PRECKR_CTL		(0x28)	*/ -	0x00, /* REG_HFL_CTL		(0x29)	*/ -	0x00, /* REG_HFR_CTL		(0x2A)	*/ -	0x05, /* REG_ALC_CTL		(0x2B)	*/ -	0x00, /* REG_ALC_SET1		(0x2C)	*/ -	0x00, /* REG_ALC_SET2		(0x2D)	*/ -	0x00, /* REG_BOOST_CTL		(0x2E)	*/ -	0x00, /* REG_SOFTVOL_CTL	(0x2F)	*/ -	0x13, /* REG_DTMF_FREQSEL	(0x30)	*/ -	0x00, /* REG_DTMF_TONEXT1H	(0x31)	*/ -	0x00, /* REG_DTMF_TONEXT1L	(0x32)	*/ -	0x00, /* REG_DTMF_TONEXT2H	(0x33)	*/ -	0x00, /* REG_DTMF_TONEXT2L	(0x34)	*/ -	0x79, /* REG_DTMF_TONOFF	(0x35)	*/ -	0x11, /* REG_DTMF_WANONOFF	(0x36)	*/ -	0x00, /* REG_I2S_RX_SCRAMBLE_H	(0x37)	*/ -	0x00, /* REG_I2S_RX_SCRAMBLE_M	(0x38)	*/ -	0x00, /* REG_I2S_RX_SCRAMBLE_L	(0x39)	*/ -	0x06, /* REG_APLL_CTL		(0x3A)	*/ -	0x00, /* REG_DTMF_CTL		(0x3B)	*/ -	0x44, /* REG_DTMF_PGA_CTL2	(0x3C)	*/ -	0x69, /* REG_DTMF_PGA_CTL1	(0x3D)	*/ -	0x00, /* REG_MISC_SET_1		(0x3E)	*/ -	0x00, /* REG_PCMBTMUX		(0x3F)	*/ -	0x00, /* not used		(0x40)	*/ -	0x00, /* not used		(0x41)	*/ -	0x00, /* not used		(0x42)	*/ -	0x00, /* REG_RX_PATH_SEL	(0x43)	*/ -	0x32, /* REG_VDL_APGA_CTL	(0x44)	*/ -	0x00, /* REG_VIBRA_CTL		(0x45)	*/ -	0x00, /* REG_VIBRA_SET		(0x46)	*/ -	0x00, /* REG_VIBRA_PWM_SET	(0x47)	*/ -	0x00, /* REG_ANAMIC_GAIN	(0x48)	*/ -	0x00, /* REG_MISC_SET_2		(0x49)	*/ -	0x00, /* REG_SW_SHADOW		(0x4A)	- Shadow, non HW register */ -}; +#define TWL4030_CACHEREGNUM	(TWL4030_REG_MISC_SET_2 + 1)  /* codec private data */  struct twl4030_priv { @@ -157,83 +70,109 @@ struct twl4030_priv {  	u8 earpiece_enabled;  	u8 predrivel_enabled, predriver_enabled;  	u8 carkitl_enabled, carkitr_enabled; +	u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1];  	struct twl4030_codec_data *pdata;  }; -/* - * read twl4030 register cache - */ -static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, -	unsigned int reg) +static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) +{ +	int i; +	u8 byte; + +	for (i = TWL4030_REG_EAR_CTL; i <= TWL4030_REG_PRECKR_CTL; i++) { +		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, i); +		twl4030->ctl_cache[i - TWL4030_REG_EAR_CTL] = byte; +	} +} + +static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg)  { -	u8 *cache = codec->reg_cache; +	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); +	u8 value = 0;  	if (reg >= TWL4030_CACHEREGNUM)  		return -EIO; -	return cache[reg]; +	switch (reg) { +	case TWL4030_REG_EAR_CTL: +	case TWL4030_REG_PREDL_CTL: +	case TWL4030_REG_PREDR_CTL: +	case TWL4030_REG_PRECKL_CTL: +	case TWL4030_REG_PRECKR_CTL: +	case TWL4030_REG_HS_GAIN_SET: +		value = twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL]; +		break; +	default: +		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &value, reg); +		break; +	} + +	return value;  } -/* - * write twl4030 register cache - */ -static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec, -						u8 reg, u8 value) +static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030, +				      unsigned int reg)  { -	u8 *cache = codec->reg_cache; +	bool write_to_reg = false; -	if (reg >= TWL4030_CACHEREGNUM) -		return; -	cache[reg] = value; +	/* Decide if the given register can be written */ +	switch (reg) { +	case TWL4030_REG_EAR_CTL: +		if (twl4030->earpiece_enabled) +			write_to_reg = true; +		break; +	case TWL4030_REG_PREDL_CTL: +		if (twl4030->predrivel_enabled) +			write_to_reg = true; +		break; +	case TWL4030_REG_PREDR_CTL: +		if (twl4030->predriver_enabled) +			write_to_reg = true; +		break; +	case TWL4030_REG_PRECKL_CTL: +		if (twl4030->carkitl_enabled) +			write_to_reg = true; +		break; +	case TWL4030_REG_PRECKR_CTL: +		if (twl4030->carkitr_enabled) +			write_to_reg = true; +		break; +	case TWL4030_REG_HS_GAIN_SET: +		if (twl4030->hsl_enabled || twl4030->hsr_enabled) +			write_to_reg = true; +		break; +	default: +		/* All other register can be written */ +		write_to_reg = true; +		break; +	} + +	return write_to_reg;  } -/* - * write to the twl4030 register space - */ -static int twl4030_write(struct snd_soc_codec *codec, -			unsigned int reg, unsigned int value) +static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, +			 unsigned int value)  {  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); -	int write_to_reg = 0; - -	twl4030_write_reg_cache(codec, reg, value); -	if (likely(reg < TWL4030_REG_SW_SHADOW)) { -		/* Decide if the given register can be written */ -		switch (reg) { -		case TWL4030_REG_EAR_CTL: -			if (twl4030->earpiece_enabled) -				write_to_reg = 1; -			break; -		case TWL4030_REG_PREDL_CTL: -			if (twl4030->predrivel_enabled) -				write_to_reg = 1; -			break; -		case TWL4030_REG_PREDR_CTL: -			if (twl4030->predriver_enabled) -				write_to_reg = 1; -			break; -		case TWL4030_REG_PRECKL_CTL: -			if (twl4030->carkitl_enabled) -				write_to_reg = 1; -			break; -		case TWL4030_REG_PRECKR_CTL: -			if (twl4030->carkitr_enabled) -				write_to_reg = 1; -			break; -		case TWL4030_REG_HS_GAIN_SET: -			if (twl4030->hsl_enabled || twl4030->hsr_enabled) -				write_to_reg = 1; -			break; -		default: -			/* All other register can be written */ -			write_to_reg = 1; -			break; -		} -		if (write_to_reg) -			return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, -						    value, reg); + +	/* Update the ctl cache */ +	switch (reg) { +	case TWL4030_REG_EAR_CTL: +	case TWL4030_REG_PREDL_CTL: +	case TWL4030_REG_PREDR_CTL: +	case TWL4030_REG_PRECKL_CTL: +	case TWL4030_REG_PRECKR_CTL: +	case TWL4030_REG_HS_GAIN_SET: +		twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL] = value; +		break; +	default: +		break;  	} + +	if (twl4030_can_write_to_chip(twl4030, reg)) +		return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); +  	return 0;  } @@ -260,46 +199,14 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)  	else  		mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER); -	if (mode >= 0) { -		twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode); +	if (mode >= 0)  		twl4030->codec_powered = enable; -	}  	/* REVISIT: this delay is present in TI sample drivers */  	/* but there seems to be no TRM requirement for it     */  	udelay(10);  } -static inline void twl4030_check_defaults(struct snd_soc_codec *codec) -{ -	int i, difference = 0; -	u8 val; - -	dev_dbg(codec->dev, "Checking TWL audio default configuration\n"); -	for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) { -		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i); -		if (val != twl4030_reg[i]) { -			difference++; -			dev_dbg(codec->dev, -				 "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n", -				 i, val, twl4030_reg[i]); -		} -	} -	dev_dbg(codec->dev, "Found %d non-matching registers. %s\n", -		 difference, difference ? "Not OK" : "OK"); -} - -static inline void twl4030_reset_registers(struct snd_soc_codec *codec) -{ -	int i; - -	/* set all audio section registers to reasonable defaults */ -	for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) -		if (i != TWL4030_REG_APLL_CTL) -			twl4030_write(codec, i, twl4030_reg[i]); - -} -  static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,  				   struct device_node *node)  { @@ -380,27 +287,17 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)  		}  	} -	/* Check defaults, if instructed before anything else */ -	if (pdata && pdata->check_defaults) -		twl4030_check_defaults(codec); - -	/* Reset registers, if no setup data or if instructed to do so */ -	if (!pdata || (pdata && pdata->reset_registers)) -		twl4030_reset_registers(codec); - -	/* Refresh APLL_CTL register from HW */ -	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, -			    TWL4030_REG_APLL_CTL); -	twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte); +	/* Initialize the local ctl register cache */ +	tw4030_init_ctl_cache(twl4030);  	/* anti-pop when changing analog gain */ -	reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); +	reg = twl4030_read(codec, TWL4030_REG_MISC_SET_1);  	twl4030_write(codec, TWL4030_REG_MISC_SET_1, -		reg | TWL4030_SMOOTH_ANAVOL_EN); +		      reg | TWL4030_SMOOTH_ANAVOL_EN);  	twl4030_write(codec, TWL4030_REG_OPTION, -		TWL4030_ATXL1_EN | TWL4030_ATXR1_EN | -		TWL4030_ARXL2_EN | TWL4030_ARXR2_EN); +		      TWL4030_ATXL1_EN | TWL4030_ATXR1_EN | +		      TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);  	/* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */  	twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32); @@ -411,19 +308,19 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)  	twl4030->pdata = pdata; -	reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); +	reg = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);  	reg &= ~TWL4030_RAMP_DELAY;  	reg |= (pdata->ramp_delay_value << 2); -	twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg); +	twl4030_write(codec, TWL4030_REG_HS_POPN_SET, reg);  	/* initiate offset cancellation */  	twl4030_codec_enable(codec, 1); -	reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); +	reg = twl4030_read(codec, TWL4030_REG_ANAMICL);  	reg &= ~TWL4030_OFFSET_CNCL_SEL;  	reg |= pdata->offset_cncl_path;  	twl4030_write(codec, TWL4030_REG_ANAMICL, -		reg | TWL4030_CNCL_OFFSET_START); +		      reg | TWL4030_CNCL_OFFSET_START);  	/*  	 * Wait for offset cancellation to complete. @@ -433,15 +330,14 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)  	msleep(20);  	do {  		usleep_range(1000, 2000); +		twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, true);  		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, -				    TWL4030_REG_ANAMICL); +				TWL4030_REG_ANAMICL); +		twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, false);  	} while ((i++ < 100) &&  		 ((byte & TWL4030_CNCL_OFFSET_START) ==  		  TWL4030_CNCL_OFFSET_START)); -	/* Make sure that the reg_cache has the same value as the HW */ -	twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); -  	twl4030_codec_enable(codec, 0);  } @@ -461,9 +357,6 @@ static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)  			status = twl4030_audio_disable_resource(  							TWL4030_AUDIO_RES_APLL);  	} - -	if (status >= 0) -		twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);  }  /* Earpiece */ @@ -522,43 +415,40 @@ static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = {  static const char *twl4030_handsfreel_texts[] =  		{"Voice", "AudioL1", "AudioL2", "AudioR2"}; -static const struct soc_enum twl4030_handsfreel_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, -			ARRAY_SIZE(twl4030_handsfreel_texts), -			twl4030_handsfreel_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_handsfreel_enum, +			    TWL4030_REG_HFL_CTL, 0, +			    twl4030_handsfreel_texts);  static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control =  SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);  /* Handsfree Left virtual mute */  static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = -	SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0); +	SOC_DAPM_SINGLE_VIRT("Switch", 1);  /* Handsfree Right */  static const char *twl4030_handsfreer_texts[] =  		{"Voice", "AudioR1", "AudioR2", "AudioL2"}; -static const struct soc_enum twl4030_handsfreer_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, -			ARRAY_SIZE(twl4030_handsfreer_texts), -			twl4030_handsfreer_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_handsfreer_enum, +			    TWL4030_REG_HFR_CTL, 0, +			    twl4030_handsfreer_texts);  static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control =  SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);  /* Handsfree Right virtual mute */  static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = -	SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0); +	SOC_DAPM_SINGLE_VIRT("Switch", 1);  /* Vibra */  /* Vibra audio path selection */  static const char *twl4030_vibra_texts[] =  		{"AudioL1", "AudioR1", "AudioL2", "AudioR2"}; -static const struct soc_enum twl4030_vibra_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2, -			ARRAY_SIZE(twl4030_vibra_texts), -			twl4030_vibra_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibra_enum, +			    TWL4030_REG_VIBRA_CTL, 2, +			    twl4030_vibra_texts);  static const struct snd_kcontrol_new twl4030_dapm_vibra_control =  SOC_DAPM_ENUM("Route", twl4030_vibra_enum); @@ -567,10 +457,9 @@ SOC_DAPM_ENUM("Route", twl4030_vibra_enum);  static const char *twl4030_vibrapath_texts[] =  		{"Local vibrator", "Audio"}; -static const struct soc_enum twl4030_vibrapath_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4, -			ARRAY_SIZE(twl4030_vibrapath_texts), -			twl4030_vibrapath_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibrapath_enum, +			    TWL4030_REG_VIBRA_CTL, 4, +			    twl4030_vibrapath_texts);  static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control =  SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); @@ -597,10 +486,9 @@ static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = {  static const char *twl4030_micpathtx1_texts[] =  		{"Analog", "Digimic0"}; -static const struct soc_enum twl4030_micpathtx1_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 0, -			ARRAY_SIZE(twl4030_micpathtx1_texts), -			twl4030_micpathtx1_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx1_enum, +			    TWL4030_REG_ADCMICSEL, 0, +			    twl4030_micpathtx1_texts);  static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control =  SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum); @@ -609,10 +497,9 @@ SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum);  static const char *twl4030_micpathtx2_texts[] =  		{"Analog", "Digimic1"}; -static const struct soc_enum twl4030_micpathtx2_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 2, -			ARRAY_SIZE(twl4030_micpathtx2_texts), -			twl4030_micpathtx2_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx2_enum, +			    TWL4030_REG_ADCMICSEL, 2, +			    twl4030_micpathtx2_texts);  static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =  SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); @@ -679,20 +566,18 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =   */  #define TWL4030_OUTPUT_PGA(pin_name, reg, mask)				\  static int pin_name##pga_event(struct snd_soc_dapm_widget *w,		\ -		struct snd_kcontrol *kcontrol, int event)		\ +			       struct snd_kcontrol *kcontrol, int event) \  {									\  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \  									\  	switch (event) {						\  	case SND_SOC_DAPM_POST_PMU:					\  		twl4030->pin_name##_enabled = 1;			\ -		twl4030_write(w->codec, reg,				\ -			twl4030_read_reg_cache(w->codec, reg));		\ +		twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \  		break;							\  	case SND_SOC_DAPM_POST_PMD:					\  		twl4030->pin_name##_enabled = 0;			\ -		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,		\ -					0, reg);			\ +		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 0, reg);	\  		break;							\  	}								\  	return 0;							\ @@ -708,7 +593,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)  {  	unsigned char hs_ctl; -	hs_ctl = twl4030_read_reg_cache(codec, reg); +	hs_ctl = twl4030_read(codec, reg);  	if (ramp) {  		/* HF ramp-up */ @@ -735,7 +620,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)  }  static int handsfreelpga_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +			       struct snd_kcontrol *kcontrol, int event)  {  	switch (event) {  	case SND_SOC_DAPM_POST_PMU: @@ -749,7 +634,7 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,  }  static int handsfreerpga_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +			       struct snd_kcontrol *kcontrol, int event)  {  	switch (event) {  	case SND_SOC_DAPM_POST_PMU: @@ -763,14 +648,14 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,  }  static int vibramux_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +			  struct snd_kcontrol *kcontrol, int event)  {  	twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);  	return 0;  }  static int apll_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +		      struct snd_kcontrol *kcontrol, int event)  {  	switch (event) {  	case SND_SOC_DAPM_PRE_PMU: @@ -784,11 +669,11 @@ static int apll_event(struct snd_soc_dapm_widget *w,  }  static int aif_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +		     struct snd_kcontrol *kcontrol, int event)  {  	u8 audio_if; -	audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF); +	audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF);  	switch (event) {  	case SND_SOC_DAPM_PRE_PMU:  		/* Enable AIF */ @@ -796,12 +681,12 @@ static int aif_event(struct snd_soc_dapm_widget *w,  		twl4030_apll_enable(w->codec, 1);  		twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, -						audio_if | TWL4030_AIF_EN); +			      audio_if | TWL4030_AIF_EN);  		break;  	case SND_SOC_DAPM_POST_PMD:  		/* disable the DAI before we stop it's source PLL */  		twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, -						audio_if &  ~TWL4030_AIF_EN); +			      audio_if &  ~TWL4030_AIF_EN);  		twl4030_apll_enable(w->codec, 0);  		break;  	} @@ -818,8 +703,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)  				    8388608, 16777216, 33554432, 67108864};  	unsigned int delay; -	hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); -	hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); +	hs_gain = twl4030_read(codec, TWL4030_REG_HS_GAIN_SET); +	hs_pop = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);  	delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /  		twl4030->sysclk) + 1; @@ -839,9 +724,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)  		hs_pop |= TWL4030_VMID_EN;  		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);  		/* Actually write to the register */ -		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, -					hs_gain, -					TWL4030_REG_HS_GAIN_SET); +		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain, +				 TWL4030_REG_HS_GAIN_SET);  		hs_pop |= TWL4030_RAMP_EN;  		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);  		/* Wait ramp delay time + 1, so the VMID can settle */ @@ -854,9 +738,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)  		/* Wait ramp delay time + 1, so the VMID can settle */  		twl4030_wait_ms(delay);  		/* Bypass the reg_cache to mute the headset */ -		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, -					hs_gain & (~0x0f), -					TWL4030_REG_HS_GAIN_SET); +		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f), +				 TWL4030_REG_HS_GAIN_SET);  		hs_pop &= ~TWL4030_VMID_EN;  		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -874,7 +757,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)  }  static int headsetlpga_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +			     struct snd_kcontrol *kcontrol, int event)  {  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); @@ -898,7 +781,7 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,  }  static int headsetrpga_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +			     struct snd_kcontrol *kcontrol, int event)  {  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); @@ -922,7 +805,7 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,  }  static int digimic_event(struct snd_soc_dapm_widget *w, -		struct snd_kcontrol *kcontrol, int event) +			 struct snd_kcontrol *kcontrol, int event)  {  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);  	struct twl4030_codec_data *pdata = twl4030->pdata; @@ -943,11 +826,11 @@ static int digimic_event(struct snd_soc_dapm_widget *w,   * Custom volsw and volsw_2r get/put functions to handle these gain bits.   */  static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, -	struct snd_ctl_elem_value *ucontrol) +				     struct snd_ctl_elem_value *ucontrol)  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int shift = mc->shift;  	unsigned int rshift = mc->rshift; @@ -972,11 +855,11 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,  }  static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, -	struct snd_ctl_elem_value *ucontrol) +				     struct snd_ctl_elem_value *ucontrol)  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int shift = mc->shift;  	unsigned int rshift = mc->rshift; @@ -1001,11 +884,11 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,  }  static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, -	struct snd_ctl_elem_value *ucontrol) +					struct snd_ctl_elem_value *ucontrol)  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	unsigned int shift = mc->shift; @@ -1028,11 +911,11 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,  }  static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, -	struct snd_ctl_elem_value *ucontrol) +					struct snd_ctl_elem_value *ucontrol)  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	unsigned int shift = mc->shift; @@ -1066,19 +949,15 @@ static const char *twl4030_op_modes_texts[] = {  	"Option 2 (voice/audio)", "Option 1 (audio)"  }; -static const struct soc_enum twl4030_op_modes_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0, -			ARRAY_SIZE(twl4030_op_modes_texts), -			twl4030_op_modes_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum, +			    TWL4030_REG_CODEC_MODE, 0, +			    twl4030_op_modes_texts);  static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); -	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -	unsigned short val; -	unsigned short mask;  	if (twl4030->configured) {  		dev_err(codec->dev, @@ -1086,19 +965,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,  		return -EBUSY;  	} -	if (ucontrol->value.enumerated.item[0] > e->max - 1) -		return -EINVAL; - -	val = ucontrol->value.enumerated.item[0] << e->shift_l; -	mask = e->mask << e->shift_l; -	if (e->shift_l != e->shift_r) { -		if (ucontrol->value.enumerated.item[1] > e->max - 1) -			return -EINVAL; -		val |= ucontrol->value.enumerated.item[1] << e->shift_r; -		mask |= e->mask << e->shift_r; -	} - -	return snd_soc_update_bits(codec, e->reg, mask, val); +	return snd_soc_put_enum_double(kcontrol, ucontrol);  }  /* @@ -1155,10 +1022,9 @@ static const char *twl4030_avadc_clk_priority_texts[] = {  	"Voice high priority", "HiFi high priority"  }; -static const struct soc_enum twl4030_avadc_clk_priority_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2, -			ARRAY_SIZE(twl4030_avadc_clk_priority_texts), -			twl4030_avadc_clk_priority_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_avadc_clk_priority_enum, +			    TWL4030_REG_AVADC_CTL, 2, +			    twl4030_avadc_clk_priority_texts);  static const char *twl4030_rampdelay_texts[] = {  	"27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", @@ -1166,40 +1032,36 @@ static const char *twl4030_rampdelay_texts[] = {  	"3495/2581/1748 ms"  }; -static const struct soc_enum twl4030_rampdelay_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2, -			ARRAY_SIZE(twl4030_rampdelay_texts), -			twl4030_rampdelay_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_rampdelay_enum, +			    TWL4030_REG_HS_POPN_SET, 2, +			    twl4030_rampdelay_texts);  /* Vibra H-bridge direction mode */  static const char *twl4030_vibradirmode_texts[] = {  	"Vibra H-bridge direction", "Audio data MSB",  }; -static const struct soc_enum twl4030_vibradirmode_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5, -			ARRAY_SIZE(twl4030_vibradirmode_texts), -			twl4030_vibradirmode_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibradirmode_enum, +			    TWL4030_REG_VIBRA_CTL, 5, +			    twl4030_vibradirmode_texts);  /* Vibra H-bridge direction */  static const char *twl4030_vibradir_texts[] = {  	"Positive polarity", "Negative polarity",  }; -static const struct soc_enum twl4030_vibradir_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1, -			ARRAY_SIZE(twl4030_vibradir_texts), -			twl4030_vibradir_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibradir_enum, +			    TWL4030_REG_VIBRA_CTL, 1, +			    twl4030_vibradir_texts);  /* Digimic Left and right swapping */  static const char *twl4030_digimicswap_texts[] = {  	"Not swapped", "Swapped",  }; -static const struct soc_enum twl4030_digimicswap_enum = -	SOC_ENUM_SINGLE(TWL4030_REG_MISC_SET_1, 0, -			ARRAY_SIZE(twl4030_digimicswap_texts), -			twl4030_digimicswap_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_digimicswap_enum, +			    TWL4030_REG_MISC_SET_1, 0, +			    twl4030_digimicswap_texts);  static const struct snd_kcontrol_new twl4030_snd_controls[] = {  	/* Codec operation mode control */ @@ -1759,11 +1621,11 @@ static void twl4030_constraints(struct twl4030_priv *twl4030,  /* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for   * capture has to be enabled/disabled. */  static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction, -				int enable) +			       int enable)  {  	u8 reg, mask; -	reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); +	reg = twl4030_read(codec, TWL4030_REG_OPTION);  	if (direction == SNDRV_PCM_STREAM_PLAYBACK)  		mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN; @@ -1792,14 +1654,14 @@ static int twl4030_startup(struct snd_pcm_substream *substream,  		if (twl4030->configured)  			twl4030_constraints(twl4030, twl4030->master_substream);  	} else { -		if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & +		if (!(twl4030_read(codec, TWL4030_REG_CODEC_MODE) &  			TWL4030_OPTION_1)) {  			/* In option2 4 channel is not supported, set the  			 * constraint for the first stream for channels, the  			 * second stream will 'inherit' this cosntraint */  			snd_pcm_hw_constraint_minmax(substream->runtime, -						SNDRV_PCM_HW_PARAM_CHANNELS, -						2, 2); +						     SNDRV_PCM_HW_PARAM_CHANNELS, +						     2, 2);  		}  		twl4030->master_substream = substream;  	} @@ -1831,8 +1693,8 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,  }  static int twl4030_hw_params(struct snd_pcm_substream *substream, -			   struct snd_pcm_hw_params *params, -			   struct snd_soc_dai *dai) +			     struct snd_pcm_hw_params *params, +			     struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -1840,8 +1702,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,  	 /* If the substream has 4 channel, do the necessary setup */  	if (params_channels(params) == 4) { -		format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); -		mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); +		format = twl4030_read(codec, TWL4030_REG_AUDIO_IF); +		mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE);  		/* Safety check: are we in the correct operating mode and  		 * the interface is in TDM mode? */ @@ -1857,8 +1719,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,  		return 0;  	/* bit rate */ -	old_mode = twl4030_read_reg_cache(codec, -			TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; +	old_mode = twl4030_read(codec, +				TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;  	mode = old_mode & ~TWL4030_APLL_RATE;  	switch (params_rate(params)) { @@ -1899,7 +1761,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,  	}  	/* sample size */ -	old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); +	old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);  	format = old_format;  	format &= ~TWL4030_DATA_WIDTH;  	switch (params_format(params)) { @@ -1948,8 +1810,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, -		int clk_id, unsigned int freq, int dir) +static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, +				  unsigned int freq, int dir)  {  	struct snd_soc_codec *codec = codec_dai->codec;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -1974,15 +1836,14 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,  	return 0;  } -static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, -			     unsigned int fmt) +static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)  {  	struct snd_soc_codec *codec = codec_dai->codec;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);  	u8 old_format, format;  	/* get format */ -	old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); +	old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);  	format = old_format;  	/* set master/slave audio interface */ @@ -2032,7 +1893,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,  static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)  {  	struct snd_soc_codec *codec = dai->codec; -	u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); +	u8 reg = twl4030_read(codec, TWL4030_REG_AUDIO_IF);  	if (tristate)  		reg |= TWL4030_AIF_TRI_EN; @@ -2045,11 +1906,11 @@ static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)  /* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R   * (VTXL, VTXR) for uplink has to be enabled/disabled. */  static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, -				int enable) +				 int enable)  {  	u8 reg, mask; -	reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); +	reg = twl4030_read(codec, TWL4030_REG_OPTION);  	if (direction == SNDRV_PCM_STREAM_PLAYBACK)  		mask = TWL4030_ARXL1_VRX_EN; @@ -2065,7 +1926,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,  }  static int twl4030_voice_startup(struct snd_pcm_substream *substream, -		struct snd_soc_dai *dai) +				 struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -2084,7 +1945,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,  	/* If the codec mode is not option2, the voice PCM interface is not  	 * available.  	 */ -	mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) +	mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE)  		& TWL4030_OPT_MODE;  	if (mode != TWL4030_OPTION_2) { @@ -2097,7 +1958,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,  }  static void twl4030_voice_shutdown(struct snd_pcm_substream *substream, -				struct snd_soc_dai *dai) +				   struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec; @@ -2106,7 +1967,8 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,  }  static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, -		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +				   struct snd_pcm_hw_params *params, +				   struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -2116,8 +1978,8 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,  	twl4030_voice_enable(codec, substream->stream, 1);  	/* bit rate */ -	old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) -		& ~(TWL4030_CODECPDZ); +	old_mode = twl4030_read(codec, +				TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;  	mode = old_mode;  	switch (params_rate(params)) { @@ -2151,7 +2013,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,  }  static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, -		int clk_id, unsigned int freq, int dir) +					int clk_id, unsigned int freq, int dir)  {  	struct snd_soc_codec *codec = codec_dai->codec;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -2172,14 +2034,14 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,  }  static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, -		unsigned int fmt) +				     unsigned int fmt)  {  	struct snd_soc_codec *codec = codec_dai->codec;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);  	u8 old_format, format;  	/* get format */ -	old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); +	old_format = twl4030_read(codec, TWL4030_REG_VOICE_IF);  	format = old_format;  	/* set master/slave audio interface */ @@ -2226,7 +2088,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,  static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)  {  	struct snd_soc_codec *codec = dai->codec; -	u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); +	u8 reg = twl4030_read(codec, TWL4030_REG_VOICE_IF);  	if (tristate)  		reg |= TWL4030_VIF_TRI_EN; @@ -2318,8 +2180,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);  	struct twl4030_codec_data *pdata = twl4030->pdata; -	/* Reset registers to their chip default before leaving */ -	twl4030_reset_registers(codec);  	twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);  	if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) @@ -2331,13 +2191,10 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)  static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {  	.probe = twl4030_soc_probe,  	.remove = twl4030_soc_remove, -	.read = twl4030_read_reg_cache, +	.read = twl4030_read,  	.write = twl4030_write,  	.set_bias_level = twl4030_set_bias_level,  	.idle_bias_off = true, -	.reg_cache_size = sizeof(twl4030_reg), -	.reg_word_size = sizeof(u8), -	.reg_cache_default = twl4030_reg,  	.controls = twl4030_snd_controls,  	.num_controls = ARRAY_SIZE(twl4030_snd_controls), @@ -2350,7 +2207,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {  static int twl4030_codec_probe(struct platform_device *pdev)  {  	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030, -			twl4030_dai, ARRAY_SIZE(twl4030_dai)); +				      twl4030_dai, ARRAY_SIZE(twl4030_dai));  }  static int twl4030_codec_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 3c79dbb6c32..0f6067f04e2 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -54,12 +54,7 @@ enum twl6040_dai_id {  #define TWL6040_OUTHF_0dB 0x03  #define TWL6040_OUTHF_M52dB 0x1D -/* Shadow register used by the driver */ -#define TWL6040_REG_SW_SHADOW	0x2F -#define TWL6040_CACHEREGNUM	(TWL6040_REG_SW_SHADOW + 1) - -/* TWL6040_REG_SW_SHADOW (0x2F) fields */ -#define TWL6040_EAR_PATH_ENABLE	0x01 +#define TWL6040_CACHEREGNUM	(TWL6040_REG_STATUS + 1)  struct twl6040_jack_data {  	struct snd_soc_jack *jack; @@ -77,6 +72,7 @@ struct twl6040_data {  	int hs_power_mode_locked;  	bool dl1_unmuted;  	bool dl2_unmuted; +	u8 dl12_cache[TWL6040_REG_HFRCTL - TWL6040_REG_HSLCTL + 1];  	unsigned int clk_in;  	unsigned int sysclk;  	struct twl6040_jack_data hs_jack; @@ -84,79 +80,8 @@ struct twl6040_data {  	struct mutex mutex;  }; -/* - * twl6040 register cache & default register settings - */ -static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = { -	0x00, /* not used	0x00	*/ -	0x4B, /* REG_ASICID	0x01 (ro) */ -	0x00, /* REG_ASICREV	0x02 (ro) */ -	0x00, /* REG_INTID	0x03	*/ -	0x00, /* REG_INTMR	0x04	*/ -	0x00, /* REG_NCPCTRL	0x05	*/ -	0x00, /* REG_LDOCTL	0x06	*/ -	0x60, /* REG_HPPLLCTL	0x07	*/ -	0x00, /* REG_LPPLLCTL	0x08	*/ -	0x4A, /* REG_LPPLLDIV	0x09	*/ -	0x00, /* REG_AMICBCTL	0x0A	*/ -	0x00, /* REG_DMICBCTL	0x0B	*/ -	0x00, /* REG_MICLCTL	0x0C	*/ -	0x00, /* REG_MICRCTL	0x0D	*/ -	0x00, /* REG_MICGAIN	0x0E	*/ -	0x1B, /* REG_LINEGAIN	0x0F	*/ -	0x00, /* REG_HSLCTL	0x10	*/ -	0x00, /* REG_HSRCTL	0x11	*/ -	0x00, /* REG_HSGAIN	0x12	*/ -	0x00, /* REG_EARCTL	0x13	*/ -	0x00, /* REG_HFLCTL	0x14	*/ -	0x00, /* REG_HFLGAIN	0x15	*/ -	0x00, /* REG_HFRCTL	0x16	*/ -	0x00, /* REG_HFRGAIN	0x17	*/ -	0x00, /* REG_VIBCTLL	0x18	*/ -	0x00, /* REG_VIBDATL	0x19	*/ -	0x00, /* REG_VIBCTLR	0x1A	*/ -	0x00, /* REG_VIBDATR	0x1B	*/ -	0x00, /* REG_HKCTL1	0x1C	*/ -	0x00, /* REG_HKCTL2	0x1D	*/ -	0x00, /* REG_GPOCTL	0x1E	*/ -	0x00, /* REG_ALB	0x1F	*/ -	0x00, /* REG_DLB	0x20	*/ -	0x00, /* not used	0x21	*/ -	0x00, /* not used	0x22	*/ -	0x00, /* not used	0x23	*/ -	0x00, /* not used	0x24	*/ -	0x00, /* not used	0x25	*/ -	0x00, /* not used	0x26	*/ -	0x00, /* not used	0x27	*/ -	0x00, /* REG_TRIM1	0x28	*/ -	0x00, /* REG_TRIM2	0x29	*/ -	0x00, /* REG_TRIM3	0x2A	*/ -	0x00, /* REG_HSOTRIM	0x2B	*/ -	0x00, /* REG_HFOTRIM	0x2C	*/ -	0x09, /* REG_ACCCTL	0x2D	*/ -	0x00, /* REG_STATUS	0x2E (ro) */ - -	0x00, /* REG_SW_SHADOW	0x2F - Shadow, non HW register */ -}; - -/* List of registers to be restored after power up */ -static const int twl6040_restore_list[] = { -	TWL6040_REG_MICLCTL, -	TWL6040_REG_MICRCTL, -	TWL6040_REG_MICGAIN, -	TWL6040_REG_LINEGAIN, -	TWL6040_REG_HSLCTL, -	TWL6040_REG_HSRCTL, -	TWL6040_REG_HSGAIN, -	TWL6040_REG_EARCTL, -	TWL6040_REG_HFLCTL, -	TWL6040_REG_HFLGAIN, -	TWL6040_REG_HFRCTL, -	TWL6040_REG_HFRGAIN, -}; -  /* set of rates for each pll: low-power and high-performance */ -static unsigned int lp_rates[] = { +static const unsigned int lp_rates[] = {  	8000,  	11250,  	16000, @@ -168,7 +93,7 @@ static unsigned int lp_rates[] = {  	96000,  }; -static unsigned int hp_rates[] = { +static const unsigned int hp_rates[] = {  	8000,  	16000,  	32000, @@ -176,62 +101,38 @@ static unsigned int hp_rates[] = {  	96000,  }; -static struct snd_pcm_hw_constraint_list sysclk_constraints[] = { +static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {  	{ .count = ARRAY_SIZE(lp_rates), .list = lp_rates, },  	{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },  }; -/* - * read twl6040 register cache - */ -static inline unsigned int twl6040_read_reg_cache(struct snd_soc_codec *codec, -						unsigned int reg) -{ -	u8 *cache = codec->reg_cache; - -	if (reg >= TWL6040_CACHEREGNUM) -		return -EIO; - -	return cache[reg]; -} - -/* - * write twl6040 register cache - */ -static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec, -						u8 reg, u8 value) -{ -	u8 *cache = codec->reg_cache; - -	if (reg >= TWL6040_CACHEREGNUM) -		return; -	cache[reg] = value; -} - -/* - * read from twl6040 hardware register - */ -static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, -			unsigned int reg) +static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)  { +	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);  	struct twl6040 *twl6040 = codec->control_data;  	u8 value;  	if (reg >= TWL6040_CACHEREGNUM)  		return -EIO; -	if (likely(reg < TWL6040_REG_SW_SHADOW)) { +	switch (reg) { +	case TWL6040_REG_HSLCTL: +	case TWL6040_REG_HSRCTL: +	case TWL6040_REG_EARCTL: +	case TWL6040_REG_HFLCTL: +	case TWL6040_REG_HFRCTL: +		value = priv->dl12_cache[reg - TWL6040_REG_HSLCTL]; +		break; +	default:  		value = twl6040_reg_read(twl6040, reg); -		twl6040_write_reg_cache(codec, reg, value); -	} else { -		value = twl6040_read_reg_cache(codec, reg); +		break;  	}  	return value;  } -static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec, -				    unsigned int reg) +static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec, +				  unsigned int reg)  {  	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); @@ -246,12 +147,27 @@ static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,  		return priv->dl2_unmuted;  	default:  		return 1; -	}; +	} +} + +static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec, +					     u8 reg, u8 value) +{ +	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + +	switch (reg) { +	case TWL6040_REG_HSLCTL: +	case TWL6040_REG_HSRCTL: +	case TWL6040_REG_EARCTL: +	case TWL6040_REG_HFLCTL: +	case TWL6040_REG_HFRCTL: +		priv->dl12_cache[reg - TWL6040_REG_HSLCTL] = value; +		break; +	default: +		break; +	}  } -/* - * write to the twl6040 register space - */  static int twl6040_write(struct snd_soc_codec *codec,  			unsigned int reg, unsigned int value)  { @@ -260,9 +176,8 @@ static int twl6040_write(struct snd_soc_codec *codec,  	if (reg >= TWL6040_CACHEREGNUM)  		return -EIO; -	twl6040_write_reg_cache(codec, reg, value); -	if (likely(reg < TWL6040_REG_SW_SHADOW) && -	    twl6040_is_path_unmuted(codec, reg)) +	twl6040_update_dl12_cache(codec, reg, value); +	if (twl6040_can_write_to_chip(codec, reg))  		return twl6040_reg_write(twl6040, reg, value);  	else  		return 0; @@ -270,45 +185,27 @@ static int twl6040_write(struct snd_soc_codec *codec,  static void twl6040_init_chip(struct snd_soc_codec *codec)  { -	struct twl6040 *twl6040 = codec->control_data; -	u8 val; - -	/* Update reg_cache: ASICREV, and TRIM values */ -	val = twl6040_get_revid(twl6040); -	twl6040_write_reg_cache(codec, TWL6040_REG_ASICREV, val); - -	twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM1); -	twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM2); -	twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM3); -	twl6040_read_reg_volatile(codec, TWL6040_REG_HSOTRIM); -	twl6040_read_reg_volatile(codec, TWL6040_REG_HFOTRIM); +	twl6040_read(codec, TWL6040_REG_TRIM1); +	twl6040_read(codec, TWL6040_REG_TRIM2); +	twl6040_read(codec, TWL6040_REG_TRIM3); +	twl6040_read(codec, TWL6040_REG_HSOTRIM); +	twl6040_read(codec, TWL6040_REG_HFOTRIM);  	/* Change chip defaults */  	/* No imput selected for microphone amplifiers */ -	twl6040_write_reg_cache(codec, TWL6040_REG_MICLCTL, 0x18); -	twl6040_write_reg_cache(codec, TWL6040_REG_MICRCTL, 0x18); +	twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18); +	twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18);  	/*  	 * We need to lower the default gain values, so the ramp code  	 * can work correctly for the first playback.  	 * This reduces the pop noise heard at the first playback.  	 */ -	twl6040_write_reg_cache(codec, TWL6040_REG_HSGAIN, 0xff); -	twl6040_write_reg_cache(codec, TWL6040_REG_EARCTL, 0x1e); -	twl6040_write_reg_cache(codec, TWL6040_REG_HFLGAIN, 0x1d); -	twl6040_write_reg_cache(codec, TWL6040_REG_HFRGAIN, 0x1d); -	twl6040_write_reg_cache(codec, TWL6040_REG_LINEGAIN, 0); -} - -static void twl6040_restore_regs(struct snd_soc_codec *codec) -{ -	u8 *cache = codec->reg_cache; -	int reg, i; - -	for (i = 0; i < ARRAY_SIZE(twl6040_restore_list); i++) { -		reg = twl6040_restore_list[i]; -		twl6040_write(codec, reg, cache[reg]); -	} +	twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff); +	twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e); +	twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d); +	twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d); +	twl6040_write(codec, TWL6040_REG_LINEGAIN, 0);  }  /* set headset dac and driver power mode */ @@ -317,8 +214,8 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)  	int hslctl, hsrctl;  	int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE; -	hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL); -	hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL); +	hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL); +	hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);  	if (high_perf) {  		hslctl &= ~mask; @@ -345,8 +242,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,  	 * Both HS DAC need to be turned on (before the HS driver) and off at  	 * the same time.  	 */ -	hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL); -	hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL); +	hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL); +	hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);  	if (SND_SOC_DAPM_EVENT_ON(event)) {  		hslctl |= TWL6040_HSDACENA;  		hsrctl |= TWL6040_HSDACENA; @@ -391,7 +288,7 @@ static void twl6040_hs_jack_report(struct snd_soc_codec *codec,  	mutex_lock(&priv->mutex);  	/* Sync status */ -	status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS); +	status = twl6040_read(codec, TWL6040_REG_STATUS);  	if (status & TWL6040_PLUGCOMP)  		snd_soc_jack_report(jack, report, report);  	else @@ -443,7 +340,7 @@ static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,  	unsigned int val;  	/* Do not allow changes while Input/FF efect is running */ -	val = twl6040_read_reg_volatile(codec, e->reg); +	val = twl6040_read(codec, e->reg);  	if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))  		return -EBUSY; @@ -495,8 +392,10 @@ static const char *twl6040_amicr_texts[] =  	{"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"};  static const struct soc_enum twl6040_enum[] = { -	SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, 4, twl6040_amicl_texts), -	SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, 4, twl6040_amicr_texts), +	SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, +			ARRAY_SIZE(twl6040_amicl_texts), twl6040_amicl_texts), +	SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, +			ARRAY_SIZE(twl6040_amicr_texts), twl6040_amicr_texts),  };  static const char *twl6040_hs_texts[] = { @@ -555,7 +454,7 @@ static const struct snd_kcontrol_new hfr_mux_controls =  	SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);  static const struct snd_kcontrol_new ep_path_enable_control = -	SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0); +	SOC_DAPM_SINGLE_VIRT("Switch", 1);  static const struct snd_kcontrol_new auxl_switch_control =  	SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0); @@ -579,14 +478,13 @@ static const char *twl6040_power_mode_texts[] = {  	"Low-Power", "High-Performance",  }; -static const struct soc_enum twl6040_power_mode_enum = -	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_power_mode_texts), -			twl6040_power_mode_texts); +static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum, +				twl6040_power_mode_texts);  static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = priv->hs_power_mode; @@ -597,7 +495,7 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,  static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);  	int high_perf = ucontrol->value.enumerated.item[0];  	int ret = 0; @@ -614,7 +512,7 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,  static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = priv->pll_power_mode; @@ -625,7 +523,7 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,  static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);  	priv->pll_power_mode = ucontrol->value.enumerated.item[0]; @@ -668,7 +566,7 @@ int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)  	if (unlikely(trim >= TWL6040_TRIM_INVAL))  		return -EINVAL; -	return twl6040_read_reg_cache(codec, TWL6040_REG_TRIM1 + trim); +	return twl6040_read(codec, TWL6040_REG_TRIM1 + trim);  }  EXPORT_SYMBOL_GPL(twl6040_get_trim_value); @@ -943,8 +841,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,  		priv->codec_powered = 1; -		twl6040_restore_regs(codec); -  		/* Set external boost GPO */  		twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);  		break; @@ -1065,9 +961,9 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i  	switch (id) {  	case TWL6040_DAI_DL1: -		hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL); -		hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL); -		earctl = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL); +		hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL); +		hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL); +		earctl = twl6040_read(codec, TWL6040_REG_EARCTL);  		if (mute) {  			/* Power down drivers and DACs */ @@ -1083,8 +979,8 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i  		priv->dl1_unmuted = !mute;  		break;  	case TWL6040_DAI_DL2: -		hflctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFLCTL); -		hfrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFRCTL); +		hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL); +		hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL);  		if (mute) {  			/* Power down drivers and DACs */ @@ -1100,7 +996,7 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i  		break;  	default:  		break; -	}; +	}  }  static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute) @@ -1221,6 +1117,7 @@ static int twl6040_resume(struct snd_soc_codec *codec)  static int twl6040_probe(struct snd_soc_codec *codec)  {  	struct twl6040_data *priv; +	struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);  	struct platform_device *pdev = container_of(codec->dev,  						   struct platform_device, dev);  	int ret = 0; @@ -1232,7 +1129,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)  	snd_soc_codec_set_drvdata(codec, priv);  	priv->codec = codec; -	codec->control_data = dev_get_drvdata(codec->dev->parent); +	codec->control_data = twl6040;  	priv->plug_irq = platform_get_irq(pdev, 0);  	if (priv->plug_irq < 0) { @@ -1252,10 +1149,10 @@ static int twl6040_probe(struct snd_soc_codec *codec)  		return ret;  	} +	twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  	twl6040_init_chip(codec); -	/* power on device */ -	return twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +	return 0;  }  static int twl6040_remove(struct snd_soc_codec *codec) @@ -1273,12 +1170,9 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {  	.remove = twl6040_remove,  	.suspend = twl6040_suspend,  	.resume = twl6040_resume, -	.read = twl6040_read_reg_cache, +	.read = twl6040_read,  	.write = twl6040_write,  	.set_bias_level = twl6040_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(twl6040_reg), -	.reg_word_size = sizeof(u8), -	.reg_cache_default = twl6040_reg,  	.ignore_pmdown_time = true,  	.controls = twl6040_snd_controls, diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index c94d4c1e3da..edf27acc1d7 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -203,8 +203,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,  	struct snd_pcm_hw_params *params,  	struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);  	u8 hw_params; diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index fd0a314bc20..e62e70781ec 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,  	/* the interpolator & decimator regs must only be written when the  	 * codec DAI is active.  	 */ -	if (!codec->active && (reg >= UDA1380_MVOL)) +	if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))  		return 0;  	pr_debug("uda1380: hw write %x val %x\n", reg, value);  	if (codec->hw_write(codec->control_data, data, 3) == 3) { @@ -237,25 +237,27 @@ static const char *uda1380_os_setting[] = {  };  static const struct soc_enum uda1380_deemp_enum[] = { -	SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), -	SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), +	SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, ARRAY_SIZE(uda1380_deemp), +			uda1380_deemp), +	SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, ARRAY_SIZE(uda1380_deemp), +			uda1380_deemp),  }; -static const struct soc_enum uda1380_input_sel_enum = -	SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel);		/* SEL_MIC, SEL_LNA */ -static const struct soc_enum uda1380_output_sel_enum = -	SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel);		/* R02_EN_AVC */ -static const struct soc_enum uda1380_spf_enum = -	SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode);		/* M */ -static const struct soc_enum uda1380_capture_sel_enum = -	SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel);	/* SEL_SOURCE */ -static const struct soc_enum uda1380_sel_ns_enum = -	SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns);		/* SEL_NS */ -static const struct soc_enum uda1380_mix_enum = -	SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control);	/* MIX, MIX_POS */ -static const struct soc_enum uda1380_sdet_enum = -	SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting);	/* SD_VALUE */ -static const struct soc_enum uda1380_os_enum = -	SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting);	/* OS */ +static SOC_ENUM_SINGLE_DECL(uda1380_input_sel_enum, +			    UDA1380_ADC, 2, uda1380_input_sel);		/* SEL_MIC, SEL_LNA */ +static SOC_ENUM_SINGLE_DECL(uda1380_output_sel_enum, +			    UDA1380_PM, 7, uda1380_output_sel);		/* R02_EN_AVC */ +static SOC_ENUM_SINGLE_DECL(uda1380_spf_enum, +			    UDA1380_MODE, 14, uda1380_spf_mode);		/* M */ +static SOC_ENUM_SINGLE_DECL(uda1380_capture_sel_enum, +			    UDA1380_IFACE, 6, uda1380_capture_sel);	/* SEL_SOURCE */ +static SOC_ENUM_SINGLE_DECL(uda1380_sel_ns_enum, +			    UDA1380_MIXER, 14, uda1380_sel_ns);		/* SEL_NS */ +static SOC_ENUM_SINGLE_DECL(uda1380_mix_enum, +			    UDA1380_MIXER, 12, uda1380_mix_control);	/* MIX, MIX_POS */ +static SOC_ENUM_SINGLE_DECL(uda1380_sdet_enum, +			    UDA1380_MIXER, 4, uda1380_sdet_setting);	/* SD_VALUE */ +static SOC_ENUM_SINGLE_DECL(uda1380_os_enum, +			    UDA1380_MIXER, 0, uda1380_os_setting);	/* OS */  /*   * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) @@ -564,8 +566,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,  static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,  				 struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);  	/* shut down WSPLL power if running from this clock */ @@ -794,7 +795,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {  	.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int uda1380_i2c_probe(struct i2c_client *i2c,  			     const struct i2c_device_id *id)  { @@ -840,7 +841,7 @@ static struct i2c_driver uda1380_i2c_driver = {  static int __init uda1380_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&uda1380_i2c_driver);  	if (ret != 0)  		pr_err("Failed to register UDA1380 I2C driver: %d\n", ret); @@ -851,7 +852,7 @@ module_init(uda1380_modinit);  static void __exit uda1380_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&uda1380_i2c_driver);  #endif  } diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index b7ab2ef567c..4ead0dc02b8 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -172,7 +172,7 @@ out:  static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,  				      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = wl1273->mode; @@ -190,14 +190,14 @@ static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };  static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,  				      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);  	if (wl1273->mode == ucontrol->value.integer.value[0])  		return 0;  	/* Do not allow changes while stream is running */ -	if (codec->active) +	if (snd_soc_codec_is_active(codec))  		return -EPERM;  	if (ucontrol->value.integer.value[0] < 0 || @@ -209,13 +209,12 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,  	return 1;  } -static const struct soc_enum wl1273_enum = -	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route); +static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);  static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,  				   struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);  	dev_dbg(codec->dev, "%s: enter.\n", __func__); @@ -228,7 +227,7 @@ static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,  static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,  				   struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);  	int val, r = 0; @@ -247,14 +246,12 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,  static const char * const wl1273_audio_strings[] = { "Digital", "Analog" }; -static const struct soc_enum wl1273_audio_enum = -	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings), -			    wl1273_audio_strings); +static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);  static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,  				    struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);  	dev_dbg(codec->dev, "%s: enter.\n", __func__); @@ -267,7 +264,7 @@ static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,  static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,  				    struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);  	int r; diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index d5ebcb00019..71ce3159a62 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -372,7 +372,8 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)  	offset = 0;  	dsp = inforec->dsp_target;  	wm0010->boot_failed = false; -	BUG_ON(!list_empty(&xfer_list)); +	if (WARN_ON(!list_empty(&xfer_list))) +		return -EINVAL;  	init_completion(&done);  	/* First record should be INFO */ @@ -793,11 +794,11 @@ static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source,  		wm0010->max_spi_freq = 0;  	} else {  		for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++) -			if (freq >= pll_clock_map[i].max_sysclk) +			if (freq >= pll_clock_map[i].max_sysclk) { +				wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed; +				wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1;  				break; - -		wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed; -		wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1; +			}  	}  	return 0; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 7fefd766b58..a4c352cc346 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -137,7 +137,8 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)  	unsigned long rate;  	int ret; -	BUG_ON(wm2000->anc_mode != ANC_OFF); +	if (WARN_ON(wm2000->anc_mode != ANC_OFF)) +		return -EINVAL;  	dev_dbg(&i2c->dev, "Beginning power up\n"); @@ -277,7 +278,8 @@ static int wm2000_enter_bypass(struct i2c_client *i2c, int analogue)  {  	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); -	BUG_ON(wm2000->anc_mode != ANC_ACTIVE); +	if (WARN_ON(wm2000->anc_mode != ANC_ACTIVE)) +		return -EINVAL;  	if (analogue) {  		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, @@ -315,7 +317,8 @@ static int wm2000_exit_bypass(struct i2c_client *i2c, int analogue)  {  	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); -	BUG_ON(wm2000->anc_mode != ANC_BYPASS); +	if (WARN_ON(wm2000->anc_mode != ANC_BYPASS)) +		return -EINVAL;  	wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); @@ -349,7 +352,8 @@ static int wm2000_enter_standby(struct i2c_client *i2c, int analogue)  {  	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); -	BUG_ON(wm2000->anc_mode != ANC_ACTIVE); +	if (WARN_ON(wm2000->anc_mode != ANC_ACTIVE)) +		return -EINVAL;  	if (analogue) {  		wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, 248 / 4); @@ -392,7 +396,8 @@ static int wm2000_exit_standby(struct i2c_client *i2c, int analogue)  {  	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); -	BUG_ON(wm2000->anc_mode != ANC_STANDBY); +	if (WARN_ON(wm2000->anc_mode != ANC_STANDBY)) +		return -EINVAL;  	wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); @@ -602,7 +607,7 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)  static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);  	ucontrol->value.enumerated.item[0] = wm2000->anc_active; @@ -613,7 +618,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,  static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);  	int anc_active = ucontrol->value.enumerated.item[0];  	int ret; @@ -635,7 +640,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,  static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);  	ucontrol->value.enumerated.item[0] = wm2000->spk_ena; @@ -646,7 +651,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,  static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);  	int val = ucontrol->value.enumerated.item[0];  	int ret; @@ -781,8 +786,6 @@ static int wm2000_probe(struct snd_soc_codec *codec)  {  	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); -	snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_REGMAP); -  	/* This will trigger a transition to standby mode by default */  	wm2000_anc_set_mode(wm2000); diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 57ba315d0c8..cdea9d9c163 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1083,7 +1083,7 @@ static int wm2200_mixer_values[] = {  #define WM2200_MUX_CTL_DECL(name) \  	const struct snd_kcontrol_new name##_mux =	\ -		SOC_DAPM_VALUE_ENUM("Route", name##_enum) +		SOC_DAPM_ENUM("Route", name##_enum)  #define WM2200_MIXER_ENUMS(name, base_reg) \  	static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg);	     \ @@ -1113,11 +1113,10 @@ static const char *wm2200_rxanc_input_sel_texts[] = {  	"None", "IN1", "IN2", "IN3",  }; -static const struct soc_enum wm2200_rxanc_input_sel = -	SOC_ENUM_SINGLE(WM2200_RXANC_SRC, -			WM2200_IN_RXANC_SEL_SHIFT, -			ARRAY_SIZE(wm2200_rxanc_input_sel_texts), -			wm2200_rxanc_input_sel_texts); +static SOC_ENUM_SINGLE_DECL(wm2200_rxanc_input_sel, +			    WM2200_RXANC_SRC, +			    WM2200_IN_RXANC_SEL_SHIFT, +			    wm2200_rxanc_input_sel_texts);  static const struct snd_kcontrol_new wm2200_snd_controls[] = {  SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL, @@ -1208,7 +1207,7 @@ WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);  WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);  #define WM2200_MUX(name, ctrl) \ -	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) +	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)  #define WM2200_MIXER_WIDGETS(name, name_str)	\  	WM2200_MUX(name_str " Input 1", &name##_in1_mux), \ @@ -1288,11 +1287,10 @@ static const char *wm2200_aec_loopback_texts[] = {  	"OUT1L", "OUT1R", "OUT2L", "OUT2R",  }; -static const struct soc_enum wm2200_aec_loopback = -	SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1, -			WM2200_AEC_LOOPBACK_SRC_SHIFT, -			ARRAY_SIZE(wm2200_aec_loopback_texts), -			wm2200_aec_loopback_texts); +static SOC_ENUM_SINGLE_DECL(wm2200_aec_loopback, +			    WM2200_DAC_AEC_CONTROL_1, +			    WM2200_AEC_LOOPBACK_SRC_SHIFT, +			    wm2200_aec_loopback_texts);  static const struct snd_kcontrol_new wm2200_aec_loopback_mux =  	SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback); @@ -1556,15 +1554,8 @@ static int wm2200_probe(struct snd_soc_codec *codec)  	int ret;  	wm2200->codec = codec; -	codec->control_data = wm2200->regmap;  	codec->dapm.bias_level = SND_SOC_BIAS_OFF; -	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);  	if (ret != 0)  		return ret; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index ac1745d030d..91a9ea2a205 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -14,6 +14,7 @@  #include <linux/moduleparam.h>  #include <linux/init.h>  #include <linux/delay.h> +#include <linux/export.h>  #include <linux/pm.h>  #include <linux/gcd.h>  #include <linux/gpio.h> @@ -389,7 +390,7 @@ static int wm5100_mixer_values[] = {  #define WM5100_MUX_CTL_DECL(name) \  	const struct snd_kcontrol_new name##_mux =	\ -		SOC_DAPM_VALUE_ENUM("Route", name##_enum) +		SOC_DAPM_ENUM("Route", name##_enum)  #define WM5100_MIXER_ENUMS(name, base_reg) \  	static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg);	     \ @@ -447,7 +448,7 @@ WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE);  WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE);  #define WM5100_MUX(name, ctrl) \ -	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) +	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)  #define WM5100_MIXER_WIDGETS(name, name_str)	\  	WM5100_MUX(name_str " Input 1", &name##_in1_mux), \ @@ -505,21 +506,21 @@ static const char *wm5100_lhpf_mode_text[] = {  	"Low-pass", "High-pass"  }; -static const struct soc_enum wm5100_lhpf1_mode = -	SOC_ENUM_SINGLE(WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, 2, -			wm5100_lhpf_mode_text); +static SOC_ENUM_SINGLE_DECL(wm5100_lhpf1_mode, +			    WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, +			    wm5100_lhpf_mode_text); -static const struct soc_enum wm5100_lhpf2_mode = -	SOC_ENUM_SINGLE(WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, 2, -			wm5100_lhpf_mode_text); +static SOC_ENUM_SINGLE_DECL(wm5100_lhpf2_mode, +			    WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, +			    wm5100_lhpf_mode_text); -static const struct soc_enum wm5100_lhpf3_mode = -	SOC_ENUM_SINGLE(WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, 2, -			wm5100_lhpf_mode_text); +static SOC_ENUM_SINGLE_DECL(wm5100_lhpf3_mode, +			    WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, +			    wm5100_lhpf_mode_text); -static const struct soc_enum wm5100_lhpf4_mode = -	SOC_ENUM_SINGLE(WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, 2, -			wm5100_lhpf_mode_text); +static SOC_ENUM_SINGLE_DECL(wm5100_lhpf4_mode, +			    WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, +			    wm5100_lhpf_mode_text);  static const struct snd_kcontrol_new wm5100_snd_controls[] = {  SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL, @@ -1972,7 +1973,8 @@ static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode)  {  	struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode]; -	BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes)); +	if (WARN_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes))) +		return;  	gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);  	regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1, @@ -2098,6 +2100,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100)  int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)  {  	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = &codec->dapm;  	if (jack) {  		wm5100->jack = jack; @@ -2115,9 +2118,14 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)  				    WM5100_ACCDET_RATE_MASK);  		/* We need the charge pump to power MICBIAS */ -		snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2"); -		snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); -		snd_soc_dapm_sync(&codec->dapm); +		snd_soc_dapm_mutex_lock(dapm); + +		snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2"); +		snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); + +		snd_soc_dapm_sync_unlocked(dapm); + +		snd_soc_dapm_mutex_unlock(dapm);  		/* We start off just enabling microphone detection - even a  		 * plain headphone will trigger detection. @@ -2140,6 +2148,7 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)  	return 0;  } +EXPORT_SYMBOL_GPL(wm5100_detect);  static irqreturn_t wm5100_irq(int irq, void *data)  { @@ -2334,13 +2343,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)  	int ret, i;  	wm5100->codec = codec; -	codec->control_data = wm5100->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)  		snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 8bbddc151aa..289b64d89ab 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -582,7 +582,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,  {  	struct snd_soc_codec *codec = w->codec;  	struct arizona *arizona = dev_get_drvdata(codec->dev->parent); -	struct regmap *regmap = codec->control_data; +	struct regmap *regmap = arizona->regmap;  	const struct reg_default *patch = NULL;  	int i, patch_size; @@ -601,8 +601,8 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,  	case SND_SOC_DAPM_POST_PMU:  		if (patch)  			for (i = 0; i < patch_size; i++) -				regmap_write(regmap, patch[i].reg, -					     patch[i].def); +				regmap_write_async(regmap, patch[i].reg, +						   patch[i].def);  		break;  	default: @@ -622,13 +622,16 @@ static const unsigned int wm5102_osr_val[] = {  static const struct soc_enum wm5102_hpout_osr[] = {  	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, -			      ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, +			      ARIZONA_OUT1_OSR_SHIFT, 0x7, +			      ARRAY_SIZE(wm5102_osr_text),  			      wm5102_osr_text, wm5102_osr_val),  	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, -			      ARIZONA_OUT2_OSR_SHIFT, 0x7, 3, +			      ARIZONA_OUT2_OSR_SHIFT, 0x7, +			      ARRAY_SIZE(wm5102_osr_text),  			      wm5102_osr_text, wm5102_osr_val),  	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, -			      ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, +			      ARIZONA_OUT3_OSR_SHIFT, 0x7, +			      ARRAY_SIZE(wm5102_osr_text),  			      wm5102_osr_text, wm5102_osr_val),  }; @@ -685,15 +688,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, -		   ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, -		   ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, -		   ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, -		   ARIZONA_EQ4_ENA_MASK), - +SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), +SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -705,6 +701,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), +SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -716,6 +714,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), +SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -727,6 +727,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), +SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, @@ -762,8 +764,8 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),  SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),  SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),  ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -812,9 +814,9 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,  		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,  		 0xbf, 0, digital_tlv), -SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), -SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), -SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]), +SOC_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), +SOC_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), +SOC_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),  SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,  	   ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0), @@ -968,7 +970,7 @@ static const struct soc_enum wm5102_aec_loopback =  			      wm5102_aec_loopback_values);  static const struct snd_kcontrol_new wm5102_aec_loopback_mux = -	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback); +	SOC_DAPM_ENUM("AEC Loopback", wm5102_aec_loopback);  static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -1202,7 +1204,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,  ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,  		       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,  		       &wm5102_aec_loopback_mux), @@ -1758,12 +1760,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)  	struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);  	int ret; -	codec->control_data = priv->core.arizona->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); -	if (ret != 0) -		return ret; -  	ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);  	if (ret != 0)  		return ret; @@ -1802,9 +1798,17 @@ static unsigned int wm5102_digital_vu[] = {  	ARIZONA_DAC_DIGITAL_VOLUME_5R,  }; +static struct regmap *wm5102_get_regmap(struct device *dev) +{ +	struct wm5102_priv *priv = dev_get_drvdata(dev); + +	return priv->core.arizona->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {  	.probe = wm5102_codec_probe,  	.remove = wm5102_codec_remove, +	.get_regmap = wm5102_get_regmap,  	.idle_bias_off = true, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index bbd64384ca1..2e5fcb559e9 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -30,13 +30,140 @@  #include <linux/mfd/arizona/registers.h>  #include "arizona.h" +#include "wm_adsp.h"  #include "wm5110.h" +#define WM5110_NUM_ADSP 4 +  struct wm5110_priv {  	struct arizona_priv core;  	struct arizona_fll fll[2];  }; +static const struct wm_adsp_region wm5110_dsp1_regions[] = { +	{ .type = WMFW_ADSP2_PM, .base = 0x100000 }, +	{ .type = WMFW_ADSP2_ZM, .base = 0x180000 }, +	{ .type = WMFW_ADSP2_XM, .base = 0x190000 }, +	{ .type = WMFW_ADSP2_YM, .base = 0x1a8000 }, +}; + +static const struct wm_adsp_region wm5110_dsp2_regions[] = { +	{ .type = WMFW_ADSP2_PM, .base = 0x200000 }, +	{ .type = WMFW_ADSP2_ZM, .base = 0x280000 }, +	{ .type = WMFW_ADSP2_XM, .base = 0x290000 }, +	{ .type = WMFW_ADSP2_YM, .base = 0x2a8000 }, +}; + +static const struct wm_adsp_region wm5110_dsp3_regions[] = { +	{ .type = WMFW_ADSP2_PM, .base = 0x300000 }, +	{ .type = WMFW_ADSP2_ZM, .base = 0x380000 }, +	{ .type = WMFW_ADSP2_XM, .base = 0x390000 }, +	{ .type = WMFW_ADSP2_YM, .base = 0x3a8000 }, +}; + +static const struct wm_adsp_region wm5110_dsp4_regions[] = { +	{ .type = WMFW_ADSP2_PM, .base = 0x400000 }, +	{ .type = WMFW_ADSP2_ZM, .base = 0x480000 }, +	{ .type = WMFW_ADSP2_XM, .base = 0x490000 }, +	{ .type = WMFW_ADSP2_YM, .base = 0x4a8000 }, +}; + +static const struct wm_adsp_region *wm5110_dsp_regions[] = { +	wm5110_dsp1_regions, +	wm5110_dsp2_regions, +	wm5110_dsp3_regions, +	wm5110_dsp4_regions, +}; + +static const struct reg_default wm5110_sysclk_revd_patch[] = { +	{ 0x3093, 0x1001 }, +	{ 0x30E3, 0x1301 }, +	{ 0x3133, 0x1201 }, +	{ 0x3183, 0x1501 }, +	{ 0x31D3, 0x1401 }, +	{ 0x0049, 0x01ea }, +	{ 0x004a, 0x01f2 }, +	{ 0x0057, 0x01e7 }, +	{ 0x0058, 0x01fb }, +	{ 0x33ce, 0xc4f5 }, +	{ 0x33cf, 0x1361 }, +	{ 0x33d0, 0x0402 }, +	{ 0x33d1, 0x4700 }, +	{ 0x33d2, 0x026d }, +	{ 0x33d3, 0xff00 }, +	{ 0x33d4, 0x026d }, +	{ 0x33d5, 0x0101 }, +	{ 0x33d6, 0xc4f5 }, +	{ 0x33d7, 0x0361 }, +	{ 0x33d8, 0x0402 }, +	{ 0x33d9, 0x6701 }, +	{ 0x33da, 0xc4f5 }, +	{ 0x33db, 0x136f }, +	{ 0x33dc, 0xc4f5 }, +	{ 0x33dd, 0x134f }, +	{ 0x33de, 0xc4f5 }, +	{ 0x33df, 0x131f }, +	{ 0x33e0, 0x026d }, +	{ 0x33e1, 0x4f01 }, +	{ 0x33e2, 0x026d }, +	{ 0x33e3, 0xf100 }, +	{ 0x33e4, 0x026d }, +	{ 0x33e5, 0x0001 }, +	{ 0x33e6, 0xc4f5 }, +	{ 0x33e7, 0x0361 }, +	{ 0x33e8, 0x0402 }, +	{ 0x33e9, 0x6601 }, +	{ 0x33ea, 0xc4f5 }, +	{ 0x33eb, 0x136f }, +	{ 0x33ec, 0xc4f5 }, +	{ 0x33ed, 0x134f }, +	{ 0x33ee, 0xc4f5 }, +	{ 0x33ef, 0x131f }, +	{ 0x33f0, 0x026d }, +	{ 0x33f1, 0x4e01 }, +	{ 0x33f2, 0x026d }, +	{ 0x33f3, 0xf000 }, +	{ 0x33f6, 0xc4f5 }, +	{ 0x33f7, 0x1361 }, +	{ 0x33f8, 0x0402 }, +	{ 0x33f9, 0x4600 }, +	{ 0x33fa, 0x026d }, +	{ 0x33fb, 0xfe00 }, +}; + +static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, +			    struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct arizona *arizona = dev_get_drvdata(codec->dev->parent); +	struct regmap *regmap = arizona->regmap; +	const struct reg_default *patch = NULL; +	int i, patch_size; + +	switch (arizona->rev) { +	case 3: +		patch = wm5110_sysclk_revd_patch; +		patch_size = ARRAY_SIZE(wm5110_sysclk_revd_patch); +		break; +	default: +		return 0; +	} + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		if (patch) +			for (i = 0; i < patch_size; i++) +				regmap_write_async(regmap, patch[i].reg, +						   patch[i].def); +		break; + +	default: +		break; +	} + +	return 0; +} +  static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);  static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);  static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); @@ -76,6 +203,25 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,  SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,  		     ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), +SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum), + +SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL, +	   ARIZONA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL, +	   ARIZONA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL, +	   ARIZONA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL, +	   ARIZONA_IN2R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3L HPF Switch", ARIZONA_IN3L_CONTROL, +	   ARIZONA_IN3L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3R HPF Switch", ARIZONA_IN3R_CONTROL, +	   ARIZONA_IN3R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4L HPF Switch", ARIZONA_IN4L_CONTROL, +	   ARIZONA_IN4L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4R HPF Switch", ARIZONA_IN4R_CONTROL, +	   ARIZONA_IN4R_HPF_SHIFT, 1, 0), +  SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,  	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),  SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, @@ -101,15 +247,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, -		   ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, -		   ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, -		   ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, -		   ARIZONA_EQ4_ENA_MASK), - +SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), +SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -121,6 +260,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), +SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -132,6 +273,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), +SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -143,6 +286,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), +SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, @@ -179,6 +324,14 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),  SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),  SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), +SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), +SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), +SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), +SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), +  ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE), @@ -207,14 +360,13 @@ ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("SPKDAT2L", ARIZONA_OUT6LMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("SPKDAT2R", ARIZONA_OUT6RMIX_INPUT_1_SOURCE), -SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L, -	   ARIZONA_OUT1_OSR_SHIFT, 1, 0), -SOC_SINGLE("HPOUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L, -	   ARIZONA_OUT2_OSR_SHIFT, 1, 0), -SOC_SINGLE("HPOUT3 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L, -	   ARIZONA_OUT3_OSR_SHIFT, 1, 0), -SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, -	   ARIZONA_OUT4_OSR_SHIFT, 1, 0), +SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL, +	   ARIZONA_HP1_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL, +	   ARIZONA_HP2_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("HPOUT3 SC Protect Switch", ARIZONA_HP3_SHORT_CIRCUIT_CTRL, +	   ARIZONA_HP3_SC_ENA_SHIFT, 1, 0), +  SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,  	   ARIZONA_OUT5_OSR_SHIFT, 1, 0),  SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L, @@ -252,23 +404,18 @@ SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_6L,  		 ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_VOL_SHIFT,  		 0xbf, 0, digital_tlv), -SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L, -		       ARIZONA_OUTPUT_PATH_CONFIG_1R, -		       ARIZONA_OUT1L_PGA_VOL_SHIFT, -		       0x34, 0x40, 0, ana_tlv), -SOC_DOUBLE_R_RANGE_TLV("HPOUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L, -		       ARIZONA_OUTPUT_PATH_CONFIG_2R, -		       ARIZONA_OUT2L_PGA_VOL_SHIFT, -		       0x34, 0x40, 0, ana_tlv), -SOC_DOUBLE_R_RANGE_TLV("HPOUT3 Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L, -		       ARIZONA_OUTPUT_PATH_CONFIG_3R, -		       ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv), -  SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,  	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),  SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,  	   ARIZONA_SPK2R_MUTE_SHIFT, 1, 1), +SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE, +	   ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0), +SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE, +	   ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0), +SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE, +	   ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0), +  SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),  SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), @@ -302,6 +449,10 @@ ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), @@ -331,6 +482,22 @@ ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP4L, ARIZONA_DSP4LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP4R, ARIZONA_DSP4RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP4, ARIZONA_DSP4AUX1MIX_INPUT_1_SOURCE); +  ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE); @@ -361,6 +528,10 @@ ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); @@ -379,6 +550,36 @@ ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);  ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);  ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE); +  static const char *wm5110_aec_loopback_texts[] = {  	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",  	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R", @@ -396,11 +597,11 @@ static const struct soc_enum wm5110_aec_loopback =  			      wm5110_aec_loopback_values);  static const struct snd_kcontrol_new wm5110_aec_loopback_mux = -	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback); +	SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);  static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, -		    0, NULL, 0), +		    0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,  		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, @@ -519,7 +720,66 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,  SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,  		 NULL, 0), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +WM_ADSP2("DSP1", 0), +WM_ADSP2("DSP2", 1), +WM_ADSP2("DSP3", 2), +WM_ADSP2("DSP4", 3), + +SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3, +		 ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3, +		 ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3, +		 ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,  		       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,  		       &wm5110_aec_loopback_mux), @@ -561,11 +821,27 @@ SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,  		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),  SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,  		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, +		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, +		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, +		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, +		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),  SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,  		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),  SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,  		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, +		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, +		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, +		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, +		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),  SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,  		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, @@ -703,6 +979,10 @@ ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),  ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),  ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), +ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"), +ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),  ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),  ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), @@ -721,6 +1001,41 @@ ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),  ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),  ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), +ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), +ARIZONA_DSP_WIDGETS(DSP2, "DSP2"), +ARIZONA_DSP_WIDGETS(DSP3, "DSP3"), +ARIZONA_DSP_WIDGETS(DSP4, "DSP4"), + +ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), +ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), +ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"), +ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), +ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), +ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"), +ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"), + +ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), +ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), +ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"), +ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), +ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), +ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"), +ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"), + +ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"), +ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"), +ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"), +ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"), +ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"), +ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"), +ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"), +  SND_SOC_DAPM_OUTPUT("HPOUT1L"),  SND_SOC_DAPM_OUTPUT("HPOUT1R"),  SND_SOC_DAPM_OUTPUT("HPOUT2L"), @@ -764,6 +1079,10 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),  	{ name, "AIF1RX8", "AIF1RX8" }, \  	{ name, "AIF2RX1", "AIF2RX1" }, \  	{ name, "AIF2RX2", "AIF2RX2" }, \ +	{ name, "AIF2RX3", "AIF2RX3" }, \ +	{ name, "AIF2RX4", "AIF2RX4" }, \ +	{ name, "AIF2RX5", "AIF2RX5" }, \ +	{ name, "AIF2RX6", "AIF2RX6" }, \  	{ name, "AIF3RX1", "AIF3RX1" }, \  	{ name, "AIF3RX2", "AIF3RX2" }, \  	{ name, "SLIMRX1", "SLIMRX1" }, \ @@ -789,7 +1108,55 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),  	{ name, "ASRC1L", "ASRC1L" }, \  	{ name, "ASRC1R", "ASRC1R" }, \  	{ name, "ASRC2L", "ASRC2L" }, \ -	{ name, "ASRC2R", "ASRC2R" } +	{ name, "ASRC2R", "ASRC2R" }, \ +	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \ +	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \ +	{ name, "ISRC1DEC3", "ISRC1DEC3" }, \ +	{ name, "ISRC1DEC4", "ISRC1DEC4" }, \ +	{ name, "ISRC1INT1", "ISRC1INT1" }, \ +	{ name, "ISRC1INT2", "ISRC1INT2" }, \ +	{ name, "ISRC1INT3", "ISRC1INT3" }, \ +	{ name, "ISRC1INT4", "ISRC1INT4" }, \ +	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \ +	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \ +	{ name, "ISRC2DEC3", "ISRC2DEC3" }, \ +	{ name, "ISRC2DEC4", "ISRC2DEC4" }, \ +	{ name, "ISRC2INT1", "ISRC2INT1" }, \ +	{ name, "ISRC2INT2", "ISRC2INT2" }, \ +	{ name, "ISRC2INT3", "ISRC2INT3" }, \ +	{ name, "ISRC2INT4", "ISRC2INT4" }, \ +	{ name, "ISRC3DEC1", "ISRC3DEC1" }, \ +	{ name, "ISRC3DEC2", "ISRC3DEC2" }, \ +	{ name, "ISRC3DEC3", "ISRC3DEC3" }, \ +	{ name, "ISRC3DEC4", "ISRC3DEC4" }, \ +	{ name, "ISRC3INT1", "ISRC3INT1" }, \ +	{ name, "ISRC3INT2", "ISRC3INT2" }, \ +	{ name, "ISRC3INT3", "ISRC3INT3" }, \ +	{ name, "ISRC3INT4", "ISRC3INT4" }, \ +	{ name, "DSP1.1", "DSP1" }, \ +	{ name, "DSP1.2", "DSP1" }, \ +	{ name, "DSP1.3", "DSP1" }, \ +	{ name, "DSP1.4", "DSP1" }, \ +	{ name, "DSP1.5", "DSP1" }, \ +	{ name, "DSP1.6", "DSP1" }, \ +	{ name, "DSP2.1", "DSP2" }, \ +	{ name, "DSP2.2", "DSP2" }, \ +	{ name, "DSP2.3", "DSP2" }, \ +	{ name, "DSP2.4", "DSP2" }, \ +	{ name, "DSP2.5", "DSP2" }, \ +	{ name, "DSP2.6", "DSP2" }, \ +	{ name, "DSP3.1", "DSP3" }, \ +	{ name, "DSP3.2", "DSP3" }, \ +	{ name, "DSP3.3", "DSP3" }, \ +	{ name, "DSP3.4", "DSP3" }, \ +	{ name, "DSP3.5", "DSP3" }, \ +	{ name, "DSP3.6", "DSP3" }, \ +	{ name, "DSP4.1", "DSP4" }, \ +	{ name, "DSP4.2", "DSP4" }, \ +	{ name, "DSP4.3", "DSP4" }, \ +	{ name, "DSP4.4", "DSP4" }, \ +	{ name, "DSP4.5", "DSP4" }, \ +	{ name, "DSP4.6", "DSP4" }  static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {  	{ "AIF2 Capture", NULL, "DBVDD2" }, @@ -861,9 +1228,17 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {  	{ "AIF2 Capture", NULL, "AIF2TX1" },  	{ "AIF2 Capture", NULL, "AIF2TX2" }, +	{ "AIF2 Capture", NULL, "AIF2TX3" }, +	{ "AIF2 Capture", NULL, "AIF2TX4" }, +	{ "AIF2 Capture", NULL, "AIF2TX5" }, +	{ "AIF2 Capture", NULL, "AIF2TX6" },  	{ "AIF2RX1", NULL, "AIF2 Playback" },  	{ "AIF2RX2", NULL, "AIF2 Playback" }, +	{ "AIF2RX3", NULL, "AIF2 Playback" }, +	{ "AIF2RX4", NULL, "AIF2 Playback" }, +	{ "AIF2RX5", NULL, "AIF2 Playback" }, +	{ "AIF2RX6", NULL, "AIF2 Playback" },  	{ "AIF3 Capture", NULL, "AIF3TX1" },  	{ "AIF3 Capture", NULL, "AIF3TX2" }, @@ -947,6 +1322,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {  	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),  	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), +	ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), +	ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), +	ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"), +	ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),  	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),  	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), @@ -983,24 +1362,71 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {  	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),  	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"), +	ARIZONA_DSP_ROUTES("DSP1"), +	ARIZONA_DSP_ROUTES("DSP2"), +	ARIZONA_DSP_ROUTES("DSP3"), +	ARIZONA_DSP_ROUTES("DSP4"), + +	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), +	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), +	ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"), +	ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"), + +	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), +	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), +	ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"), +	ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"), + +	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), +	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), +	ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"), +	ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"), + +	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), +	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), +	ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"), +	ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"), + +	ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"), +	ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"), +	ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"), +	ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"), + +	ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"), +	ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"), +	ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"), +	ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"), + +	{ "AEC Loopback", "HPOUT1L", "OUT1L" }, +	{ "AEC Loopback", "HPOUT1R", "OUT1R" },  	{ "HPOUT1L", NULL, "OUT1L" },  	{ "HPOUT1R", NULL, "OUT1R" }, +	{ "AEC Loopback", "HPOUT2L", "OUT2L" }, +	{ "AEC Loopback", "HPOUT2R", "OUT2R" },  	{ "HPOUT2L", NULL, "OUT2L" },  	{ "HPOUT2R", NULL, "OUT2R" }, +	{ "AEC Loopback", "HPOUT3L", "OUT3L" }, +	{ "AEC Loopback", "HPOUT3R", "OUT3R" },  	{ "HPOUT3L", NULL, "OUT3L" }, -	{ "HPOUT3R", NULL, "OUT3L" }, +	{ "HPOUT3R", NULL, "OUT3R" }, +	{ "AEC Loopback", "SPKOUTL", "OUT4L" },  	{ "SPKOUTLN", NULL, "OUT4L" },  	{ "SPKOUTLP", NULL, "OUT4L" }, +	{ "AEC Loopback", "SPKOUTR", "OUT4R" },  	{ "SPKOUTRN", NULL, "OUT4R" },  	{ "SPKOUTRP", NULL, "OUT4R" }, +	{ "AEC Loopback", "SPKDAT1L", "OUT5L" }, +	{ "AEC Loopback", "SPKDAT1R", "OUT5R" },  	{ "SPKDAT1L", NULL, "OUT5L" },  	{ "SPKDAT1R", NULL, "OUT5R" }, +	{ "AEC Loopback", "SPKDAT2L", "OUT6L" }, +	{ "AEC Loopback", "SPKDAT2R", "OUT6R" },  	{ "SPKDAT2L", NULL, "OUT6L" },  	{ "SPKDAT2R", NULL, "OUT6R" }, @@ -1067,14 +1493,14 @@ static struct snd_soc_dai_driver wm5110_dai[] = {  		.playback = {  			.stream_name = "AIF2 Playback",  			.channels_min = 1, -			.channels_max = 2, +			.channels_max = 6,  			.rates = WM5110_RATES,  			.formats = WM5110_FORMATS,  		},  		.capture = {  			 .stream_name = "AIF2 Capture",  			 .channels_min = 1, -			 .channels_max = 2, +			 .channels_max = 6,  			 .rates = WM5110_RATES,  			 .formats = WM5110_FORMATS,  		 }, @@ -1166,16 +1592,15 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)  	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);  	int ret; -	codec->control_data = priv->core.arizona->regmap;  	priv->core.arizona->dapm = &codec->dapm; -	ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); -	if (ret != 0) -		return ret; -  	arizona_init_spk(codec);  	arizona_init_gpio(codec); +	ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8); +	if (ret != 0) +		return ret; +  	snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");  	priv->core.arizona->dapm = &codec->dapm; @@ -1209,9 +1634,17 @@ static unsigned int wm5110_digital_vu[] = {  	ARIZONA_DAC_DIGITAL_VOLUME_6R,  }; +static struct regmap *wm5110_get_regmap(struct device *dev) +{ +	struct wm5110_priv *priv = dev_get_drvdata(dev); + +	return priv->core.arizona->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {  	.probe = wm5110_codec_probe,  	.remove = wm5110_codec_remove, +	.get_regmap = wm5110_get_regmap,  	.idle_bias_off = true, @@ -1230,7 +1663,7 @@ static int wm5110_probe(struct platform_device *pdev)  {  	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);  	struct wm5110_priv *wm5110; -	int i; +	int i, ret;  	wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv),  			      GFP_KERNEL); @@ -1241,6 +1674,24 @@ static int wm5110_probe(struct platform_device *pdev)  	wm5110->core.arizona = arizona;  	wm5110->core.num_inputs = 8; +	for (i = 0; i < WM5110_NUM_ADSP; i++) { +		wm5110->core.adsp[i].part = "wm5110"; +		wm5110->core.adsp[i].num = i + 1; +		wm5110->core.adsp[i].type = WMFW_ADSP2; +		wm5110->core.adsp[i].dev = arizona->dev; +		wm5110->core.adsp[i].regmap = arizona->regmap; + +		wm5110->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 +			+ (0x100 * i); +		wm5110->core.adsp[i].mem = wm5110_dsp_regions[i]; +		wm5110->core.adsp[i].num_mems +			= ARRAY_SIZE(wm5110_dsp1_regions); + +		ret = wm_adsp2_init(&wm5110->core.adsp[i], false); +		if (ret != 0) +			return ret; +	} +  	for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)  		wm5110->fll[i].vco_mult = 3; @@ -1251,6 +1702,12 @@ static int wm5110_probe(struct platform_device *pdev)  			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,  			 &wm5110->fll[1]); +	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */ +	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2, +			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11); +	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3, +			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12); +  	for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++)  		arizona_init_dai(&wm5110->core, i); diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index af1318ddb06..392285edb59 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -274,7 +274,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,  		break;  	default: -		BUG(); +		WARN(1, "Invalid shift %d\n", w->shift);  		return -1;  	} @@ -302,7 +302,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,  static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,  				  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);  	struct wm8350_output *out = NULL;  	struct soc_mixer_control *mc = @@ -345,7 +345,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,  static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);  	struct wm8350_output *out1 = &wm8350_priv->out1;  	struct wm8350_output *out2 = &wm8350_priv->out2; @@ -1505,10 +1505,6 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)  	if (ret != 0)  		return ret; -	codec->control_data = wm8350->regmap; - -	snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -  	/* Put the codec into reset if it wasn't already */  	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); @@ -1610,11 +1606,19 @@ static int  wm8350_codec_remove(struct snd_soc_codec *codec)  	return 0;  } +static struct regmap *wm8350_get_regmap(struct device *dev) +{ +	struct wm8350 *wm8350 = dev_get_platdata(dev); + +	return wm8350->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {  	.probe =	wm8350_codec_probe,  	.remove =	wm8350_codec_remove,  	.suspend = 	wm8350_suspend,  	.resume =	wm8350_resume, +	.get_regmap =	wm8350_get_regmap,  	.set_bias_level = wm8350_set_bias_level,  	.controls = wm8350_snd_controls, diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index d2a09285028..06e913d3fea 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -32,13 +32,6 @@  #include "wm8400.h" -/* Fake register for internal state */ -#define WM8400_INTDRIVBITS      (WM8400_REGISTER_COUNT + 1) -#define WM8400_INMIXL_PWR			0 -#define WM8400_AINLMUX_PWR			1 -#define WM8400_INMIXR_PWR			2 -#define WM8400_AINRMUX_PWR			3 -  static struct regulator_bulk_data power[] = {  	{  		.supply = "I2S1VDD", @@ -74,32 +67,6 @@ struct wm8400_priv {  	int fll_in, fll_out;  }; -static inline unsigned int wm8400_read(struct snd_soc_codec *codec, -				       unsigned int reg) -{ -	struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); - -	if (reg == WM8400_INTDRIVBITS) -		return wm8400->fake_register; -	else -		return wm8400_reg_read(wm8400->wm8400, reg); -} - -/* - * write to the wm8400 register space - */ -static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg, -	unsigned int value) -{ -	struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); - -	if (reg == WM8400_INTDRIVBITS) { -		wm8400->fake_register = value; -		return 0; -	} else -		return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value); -} -  static void wm8400_codec_reset(struct snd_soc_codec *codec)  {  	struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); @@ -126,7 +93,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);  static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,          struct snd_ctl_elem_value *ucontrol)  { -        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value;  	int reg = mc->reg; @@ -150,19 +117,23 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,  static const char *wm8400_digital_sidetone[] =  	{"None", "Left ADC", "Right ADC", "Reserved"}; -static const struct soc_enum wm8400_left_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, -		WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum, +			    WM8400_DIGITAL_SIDE_TONE, +			    WM8400_ADC_TO_DACL_SHIFT, +			    wm8400_digital_sidetone); -static const struct soc_enum wm8400_right_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, -		WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum, +			    WM8400_DIGITAL_SIDE_TONE, +			    WM8400_ADC_TO_DACR_SHIFT, +			    wm8400_digital_sidetone);  static const char *wm8400_adcmode[] =  	{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; -static const struct soc_enum wm8400_right_adcmode_enum = -SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode); +static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum, +			    WM8400_ADC_CTRL, +			    WM8400_ADC_HPF_CUT_SHIFT, +			    wm8400_adcmode);  static const struct snd_kcontrol_new wm8400_snd_controls[] = {  /* INMIXL */ @@ -352,32 +323,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,   * _DAPM_ Controls   */ -static int inmixer_event (struct snd_soc_dapm_widget *w, -	struct snd_kcontrol *kcontrol, int event) -{ -	u16 reg, fakepower; - -	reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2); -	fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS); - -	if (fakepower & ((1 << WM8400_INMIXL_PWR) | -		(1 << WM8400_AINLMUX_PWR))) { -		reg |= WM8400_AINL_ENA; -	} else { -		reg &= ~WM8400_AINL_ENA; -	} - -	if (fakepower & ((1 << WM8400_INMIXR_PWR) | -		(1 << WM8400_AINRMUX_PWR))) { -		reg |= WM8400_AINR_ENA; -	} else { -		reg &= ~WM8400_AINR_ENA; -	} -	snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg); - -	return 0; -} -  static int outmixer_event (struct snd_soc_dapm_widget *w,  	struct snd_kcontrol * kcontrol, int event)  { @@ -481,9 +426,10 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,  static const char *wm8400_ainlmux[] =  	{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; -static const struct soc_enum wm8400_ainlmux_enum = -SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT, -	ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux); +static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum, +			    WM8400_INPUT_MIXER1, +			    WM8400_AINLMODE_SHIFT, +			    wm8400_ainlmux);  static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =  SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); @@ -494,9 +440,10 @@ SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);  static const char *wm8400_ainrmux[] =  	{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; -static const struct soc_enum wm8400_ainrmux_enum = -SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT, -	ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux); +static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum, +			    WM8400_INPUT_MIXER1, +			    WM8400_AINRMODE_SHIFT, +			    wm8400_ainrmux);  static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =  SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum); @@ -658,27 +605,26 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2,  		   0, &wm8400_dapm_rin34_pga_controls[0],  		   ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)), +SND_SOC_DAPM_SUPPLY("INL", WM8400_POWER_MANAGEMENT_2, WM8400_AINL_ENA_SHIFT, +		    0, NULL, 0), +SND_SOC_DAPM_SUPPLY("INR", WM8400_POWER_MANAGEMENT_2, WM8400_AINR_ENA_SHIFT, +		    0, NULL, 0), +  /* INMIXL */ -SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0, +SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,  	&wm8400_dapm_inmixl_controls[0], -	ARRAY_SIZE(wm8400_dapm_inmixl_controls), -	inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	ARRAY_SIZE(wm8400_dapm_inmixl_controls)),  /* AINLMUX */ -SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0, -	&wm8400_dapm_ainlmux_controls, inmixer_event, -	SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AILNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainlmux_controls),  /* INMIXR */ -SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0, +SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,  	&wm8400_dapm_inmixr_controls[0], -	ARRAY_SIZE(wm8400_dapm_inmixr_controls), -	inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	ARRAY_SIZE(wm8400_dapm_inmixr_controls)),  /* AINRMUX */ -SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0, -	&wm8400_dapm_ainrmux_controls, inmixer_event, -	SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AIRNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainrmux_controls),  /* Output Side */  /* DACs */ @@ -789,11 +735,13 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {  	{"LIN34 PGA", "LIN3 Switch", "LIN3"},  	{"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},  	/* INMIXL */ +	{"INMIXL", NULL, "INL"},  	{"INMIXL", "Record Left Volume", "LOMIX"},  	{"INMIXL", "LIN2 Volume", "LIN2"},  	{"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},  	{"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},  	/* AILNMUX */ +	{"AILNMUX", NULL, "INL"},  	{"AILNMUX", "INMIXL Mix", "INMIXL"},  	{"AILNMUX", "DIFFINL Mix", "LIN12 PGA"},  	{"AILNMUX", "DIFFINL Mix", "LIN34 PGA"}, @@ -808,12 +756,14 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {  	/* RIN34 PGA */  	{"RIN34 PGA", "RIN3 Switch", "RIN3"},  	{"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"}, -	/* INMIXL */ +	/* INMIXR */ +	{"INMIXR", NULL, "INR"},  	{"INMIXR", "Record Right Volume", "ROMIX"},  	{"INMIXR", "RIN2 Volume", "RIN2"},  	{"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},  	{"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},  	/* AIRNMUX */ +	{"AIRNMUX", NULL, "INR"},  	{"AIRNMUX", "INMIXR Mix", "INMIXR"},  	{"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"},  	{"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"}, @@ -1365,7 +1315,7 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)  		return -ENOMEM;  	snd_soc_codec_set_drvdata(codec, priv); -	codec->control_data = priv->wm8400 = wm8400; +	priv->wm8400 = wm8400;  	priv->codec = codec;  	ret = devm_regulator_bulk_get(wm8400->dev, @@ -1409,13 +1359,19 @@ static int  wm8400_codec_remove(struct snd_soc_codec *codec)  	return 0;  } +static struct regmap *wm8400_get_regmap(struct device *dev) +{ +	struct wm8400 *wm8400 = dev_get_platdata(dev); + +	return wm8400->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {  	.probe =	wm8400_codec_probe,  	.remove =	wm8400_codec_remove,  	.suspend =	wm8400_suspend,  	.resume =	wm8400_resume, -	.read = snd_soc_read, -	.write = wm8400_write, +	.get_regmap =	wm8400_get_regmap,  	.set_bias_level = wm8400_set_bias_level,  	.controls = wm8400_snd_controls, diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 6ed5433943e..1c1e328feeb 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -589,20 +589,12 @@ static int wm8510_resume(struct snd_soc_codec *codec)  static int wm8510_probe(struct snd_soc_codec *codec)  { -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	wm8510_reset(codec);  	/* power on device */  	wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	return ret; +	return 0;  }  /* power down chip */ @@ -684,7 +676,7 @@ static struct spi_driver wm8510_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8510_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -735,7 +727,7 @@ static struct i2c_driver wm8510_i2c_driver = {  static int __init wm8510_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8510_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n", @@ -755,7 +747,7 @@ module_init(wm8510_modinit);  static void __exit wm8510_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8510_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 139bf9ac940..601ee8178af 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -75,8 +75,8 @@ static const char *wm8523_zd_count_text[] = {  	"2048",  }; -static const struct soc_enum wm8523_zc_count = -	SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text); +static SOC_ENUM_SINGLE_DECL(wm8523_zc_count, WM8523_ZERO_DETECT, 0, +			    wm8523_zd_count_text);  static const struct snd_kcontrol_new wm8523_controls[] = {  SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR, @@ -392,18 +392,11 @@ static int wm8523_resume(struct snd_soc_codec *codec)  static int wm8523_probe(struct snd_soc_codec *codec)  {  	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); -	int ret;  	wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];  	wm8523->rate_constraint.count =  		ARRAY_SIZE(wm8523->rate_constraint_list); -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Change some default settings - latch VU and enable ZC */  	snd_soc_update_bits(codec, WM8523_DAC_GAINR,  			    WM8523_DACR_VU, WM8523_DACR_VU); @@ -452,7 +445,7 @@ static const struct regmap_config wm8523_regmap = {  	.volatile_reg = wm8523_volatile_register,  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8523_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -555,7 +548,7 @@ static struct i2c_driver wm8523_i2c_driver = {  static int __init wm8523_modinit(void)  {  	int ret; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8523_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n", @@ -568,7 +561,7 @@ module_init(wm8523_modinit);  static void __exit wm8523_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8523_i2c_driver);  #endif  } diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 5e9c40fa7eb..7665ff6aea6 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -252,7 +252,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg; @@ -504,8 +504,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,  				 struct snd_pcm_hw_params *params,  				 struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);  	u16 paifa = 0;  	u16 paifb = 0; @@ -736,7 +735,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,  		break;  	default: -		BUG_ON("Unknown DAI driver ID\n"); +		WARN(1, "Unknown DAI driver ID\n");  		return -EINVAL;  	} @@ -869,12 +868,6 @@ static int wm8580_probe(struct snd_soc_codec *codec)  	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);  	int ret = 0; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),  				    wm8580->supplies);  	if (ret != 0) { @@ -941,7 +934,7 @@ static const struct regmap_config wm8580_regmap = {  	.volatile_reg = wm8580_volatile,  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8580_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -1003,7 +996,7 @@ static int __init wm8580_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8580_i2c_driver);  	if (ret != 0) {  		pr_err("Failed to register WM8580 I2C driver: %d\n", ret); @@ -1016,7 +1009,7 @@ module_init(wm8580_modinit);  static void __exit wm8580_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8580_i2c_driver);  #endif  } diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 5b428b060d4..b0fbcb377ba 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream,  	struct snd_soc_codec *codec = dai->codec;  	/* deactivate */ -	if (!codec->active) { +	if (!snd_soc_codec_is_active(codec)) {  		udelay(50);  		snd_soc_write(codec, WM8711_ACTIVE, 0x0);  	} @@ -367,12 +367,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)  {  	int ret; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8711_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset\n"); @@ -469,7 +463,7 @@ static struct spi_driver wm8711_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8711_i2c_probe(struct i2c_client *client,  			    const struct i2c_device_id *id)  { @@ -520,7 +514,7 @@ static struct i2c_driver wm8711_i2c_driver = {  static int __init wm8711_modinit(void)  {  	int ret; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8711_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n", @@ -540,7 +534,7 @@ module_init(wm8711_modinit);  static void __exit wm8711_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8711_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index c6a292dcded..bac7fc28fe7 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -228,19 +228,10 @@ static int wm8728_resume(struct snd_soc_codec *codec)  static int wm8728_probe(struct snd_soc_codec *codec)  { -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", -		       ret); -		return ret; -	} -  	/* power on device */  	wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	return ret; +	return 0;  }  static int wm8728_remove(struct snd_soc_codec *codec) @@ -320,7 +311,7 @@ static struct spi_driver wm8728_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8728_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -371,7 +362,7 @@ static struct i2c_driver wm8728_i2c_driver = {  static int __init wm8728_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8728_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n", @@ -391,7 +382,7 @@ module_init(wm8728_modinit);  static void __exit wm8728_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8728_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 456bb8c6d75..5ada6161132 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -83,8 +83,8 @@ static bool wm8731_writeable(struct device *dev, unsigned int reg)  static const char *wm8731_input_select[] = {"Line In", "Mic"}; -static const struct soc_enum wm8731_insel_enum = -	SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select); +static SOC_ENUM_SINGLE_DECL(wm8731_insel_enum, +			    WM8731_APANA, 2, wm8731_input_select);  static int wm8731_deemph[] = { 0, 32000, 44100, 48000 }; @@ -119,7 +119,7 @@ static int wm8731_set_deemph(struct snd_soc_codec *codec)  static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8731->deemph; @@ -130,7 +130,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,  static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);  	int deemph = ucontrol->value.enumerated.item[0];  	int ret = 0; @@ -447,10 +447,10 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,  		iface |= 0x0001;  		break;  	case SND_SOC_DAIFMT_DSP_A: -		iface |= 0x0003; +		iface |= 0x0013;  		break;  	case SND_SOC_DAIFMT_DSP_B: -		iface |= 0x0013; +		iface |= 0x0003;  		break;  	default:  		return -EINVAL; @@ -583,17 +583,10 @@ static int wm8731_probe(struct snd_soc_codec *codec)  	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);  	int ret = 0, i; -	codec->control_data = wm8731->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)  		wm8731->supplies[i].supply = wm8731_supply_names[i]; -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), +	ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),  				 wm8731->supplies);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -604,7 +597,7 @@ static int wm8731_probe(struct snd_soc_codec *codec)  				    wm8731->supplies);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); -		goto err_regulator_get; +		return ret;  	}  	ret = wm8731_reset(codec); @@ -631,8 +624,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)  err_regulator_enable:  	regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); -err_regulator_get: -	regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);  	return ret;  } @@ -645,7 +636,6 @@ static int wm8731_remove(struct snd_soc_codec *codec)  	wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);  	regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); -	regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);  	return 0;  } @@ -732,7 +722,7 @@ static struct spi_driver wm8731_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8731_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -791,7 +781,7 @@ static struct i2c_driver wm8731_i2c_driver = {  static int __init wm8731_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8731_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", @@ -811,7 +801,7 @@ module_init(wm8731_modinit);  static void __exit wm8731_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8731_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 2f167a8ca01..b27f26cdc04 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -99,29 +99,29 @@ static const char *micbias_enum_text[] = {  	"100%",  }; -static const struct soc_enum micbias_enum = -	SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text); +static SOC_ENUM_SINGLE_DECL(micbias_enum, +			    WM8737_MIC_PREAMP_CONTROL, 0, micbias_enum_text);  static const char *low_cutoff_text[] = {  	"Low", "High"  }; -static const struct soc_enum low_3d = -	SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text); +static SOC_ENUM_SINGLE_DECL(low_3d, +			    WM8737_3D_ENHANCE, 6, low_cutoff_text);  static const char *high_cutoff_text[] = {  	"High", "Low"  }; -static const struct soc_enum high_3d = -	SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text); +static SOC_ENUM_SINGLE_DECL(high_3d, +			    WM8737_3D_ENHANCE, 5, high_cutoff_text);  static const char *alc_fn_text[] = {  	"Disabled", "Right", "Left", "Stereo"  }; -static const struct soc_enum alc_fn = -	SOC_ENUM_SINGLE(WM8737_ALC1, 7, 4, alc_fn_text); +static SOC_ENUM_SINGLE_DECL(alc_fn, +			    WM8737_ALC1, 7, alc_fn_text);  static const char *alc_hold_text[] = {  	"0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms", @@ -129,24 +129,24 @@ static const char *alc_hold_text[] = {  	"10.916s", "21.832s", "43.691s"  }; -static const struct soc_enum alc_hold = -	SOC_ENUM_SINGLE(WM8737_ALC2, 0, 16, alc_hold_text); +static SOC_ENUM_SINGLE_DECL(alc_hold, +			    WM8737_ALC2, 0, alc_hold_text);  static const char *alc_atk_text[] = {  	"8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms",  	"1.075s", "2.15s", "4.3s", "8.6s"  }; -static const struct soc_enum alc_atk = -	SOC_ENUM_SINGLE(WM8737_ALC3, 0, 11, alc_atk_text); +static SOC_ENUM_SINGLE_DECL(alc_atk, +			    WM8737_ALC3, 0, alc_atk_text);  static const char *alc_dcy_text[] = {  	"33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s",  	"4.3s", "8.6s", "17.2s", "34.41s"  }; -static const struct soc_enum alc_dcy = -	SOC_ENUM_SINGLE(WM8737_ALC3, 4, 11, alc_dcy_text); +static SOC_ENUM_SINGLE_DECL(alc_dcy, +			    WM8737_ALC3, 4, alc_dcy_text);  static const struct snd_kcontrol_new wm8737_snd_controls[] = {  SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R, @@ -191,8 +191,8 @@ static const char *linsel_text[] = {  	"LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC",  }; -static const struct soc_enum linsel_enum = -	SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text); +static SOC_ENUM_SINGLE_DECL(linsel_enum, +			    WM8737_AUDIO_PATH_L, 7, linsel_text);  static const struct snd_kcontrol_new linsel_mux =  	SOC_DAPM_ENUM("LINSEL", linsel_enum); @@ -202,8 +202,8 @@ static const char *rinsel_text[] = {  	"RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC",  }; -static const struct soc_enum rinsel_enum = -	SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text); +static SOC_ENUM_SINGLE_DECL(rinsel_enum, +			    WM8737_AUDIO_PATH_R, 7, rinsel_text);  static const struct snd_kcontrol_new rinsel_mux =  	SOC_DAPM_ENUM("RINSEL", rinsel_enum); @@ -212,15 +212,15 @@ static const char *bypass_text[] = {  	"Direct", "Preamp"  }; -static const struct soc_enum lbypass_enum = -	SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text); +static SOC_ENUM_SINGLE_DECL(lbypass_enum, +			    WM8737_MIC_PREAMP_CONTROL, 2, bypass_text);  static const struct snd_kcontrol_new lbypass_mux =  	SOC_DAPM_ENUM("Left Bypass", lbypass_enum); -static const struct soc_enum rbypass_enum = -	SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text); +static SOC_ENUM_SINGLE_DECL(rbypass_enum, +			    WM8737_MIC_PREAMP_CONTROL, 3, bypass_text);  static const struct snd_kcontrol_new rbypass_mux =  	SOC_DAPM_ENUM("Left Bypass", rbypass_enum); @@ -570,12 +570,6 @@ static int wm8737_probe(struct snd_soc_codec *codec)  	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);  	int ret; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),  				    wm8737->supplies);  	if (ret != 0) { @@ -644,7 +638,7 @@ static const struct regmap_config wm8737_regmap = {  	.volatile_reg = wm8737_volatile,  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8737_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -758,7 +752,7 @@ static struct spi_driver wm8737_spi_driver = {  static int __init wm8737_modinit(void)  {  	int ret; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8737_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n", @@ -781,7 +775,7 @@ static void __exit wm8737_exit(void)  #if defined(CONFIG_SPI_MASTER)  	spi_unregister_driver(&wm8737_spi_driver);  #endif -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8737_i2c_driver);  #endif  } diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index b18813cc7ba..b33542a0460 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -44,7 +44,7 @@ struct wm8741_priv {  	struct regmap *regmap;  	struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];  	unsigned int sysclk; -	struct snd_pcm_hw_constraint_list *sysclk_constraints; +	const struct snd_pcm_hw_constraint_list *sysclk_constraints;  };  static const struct reg_default wm8741_reg_defaults[] = { @@ -122,74 +122,74 @@ static struct {  	{ 6, 768 },  }; -static unsigned int rates_11289[] = { +static const unsigned int rates_11289[] = {  	44100, 88235,  }; -static struct snd_pcm_hw_constraint_list constraints_11289 = { +static const struct snd_pcm_hw_constraint_list constraints_11289 = {  	.count	= ARRAY_SIZE(rates_11289),  	.list	= rates_11289,  }; -static unsigned int rates_12288[] = { +static const unsigned int rates_12288[] = {  	32000, 48000, 96000,  }; -static struct snd_pcm_hw_constraint_list constraints_12288 = { +static const struct snd_pcm_hw_constraint_list constraints_12288 = {  	.count	= ARRAY_SIZE(rates_12288),  	.list	= rates_12288,  }; -static unsigned int rates_16384[] = { +static const unsigned int rates_16384[] = {  	32000,  }; -static struct snd_pcm_hw_constraint_list constraints_16384 = { +static const struct snd_pcm_hw_constraint_list constraints_16384 = {  	.count	= ARRAY_SIZE(rates_16384),  	.list	= rates_16384,  }; -static unsigned int rates_16934[] = { +static const unsigned int rates_16934[] = {  	44100, 88235,  }; -static struct snd_pcm_hw_constraint_list constraints_16934 = { +static const struct snd_pcm_hw_constraint_list constraints_16934 = {  	.count	= ARRAY_SIZE(rates_16934),  	.list	= rates_16934,  }; -static unsigned int rates_18432[] = { +static const unsigned int rates_18432[] = {  	48000, 96000,  }; -static struct snd_pcm_hw_constraint_list constraints_18432 = { +static const struct snd_pcm_hw_constraint_list constraints_18432 = {  	.count	= ARRAY_SIZE(rates_18432),  	.list	= rates_18432,  }; -static unsigned int rates_22579[] = { +static const unsigned int rates_22579[] = {  	44100, 88235, 1764000  }; -static struct snd_pcm_hw_constraint_list constraints_22579 = { +static const struct snd_pcm_hw_constraint_list constraints_22579 = {  	.count	= ARRAY_SIZE(rates_22579),  	.list	= rates_22579,  }; -static unsigned int rates_24576[] = { +static const unsigned int rates_24576[] = {  	32000, 48000, 96000, 192000  }; -static struct snd_pcm_hw_constraint_list constraints_24576 = { +static const struct snd_pcm_hw_constraint_list constraints_24576 = {  	.count	= ARRAY_SIZE(rates_24576),  	.list	= rates_24576,  }; -static unsigned int rates_36864[] = { +static const unsigned int rates_36864[] = {  	48000, 96000, 19200  }; -static struct snd_pcm_hw_constraint_list constraints_36864 = { +static const struct snd_pcm_hw_constraint_list constraints_36864 = {  	.count	= ARRAY_SIZE(rates_36864),  	.list	= rates_36864,  }; @@ -429,12 +429,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)  		goto err_get;  	} -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		goto err_enable; -	} -  	ret = wm8741_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset\n"); @@ -500,7 +494,7 @@ static const struct regmap_config wm8741_regmap = {  	.readable_reg = wm8741_readable,  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8741_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -617,7 +611,7 @@ static int __init wm8741_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8741_i2c_driver);  	if (ret != 0)  		pr_err("Failed to register WM8741 I2C driver: %d\n", ret); @@ -639,7 +633,7 @@ static void __exit wm8741_exit(void)  #if defined(CONFIG_SPI_MASTER)  	spi_unregister_driver(&wm8741_spi_driver);  #endif -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8741_i2c_driver);  #endif  } diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 50d5ff61623..33990b63d21 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -702,12 +702,6 @@ static int wm8750_probe(struct snd_soc_codec *codec)  {  	int ret; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8750_reset(codec);  	if (ret < 0) {  		printk(KERN_ERR "wm8750: failed to reset: %d\n", ret); @@ -816,7 +810,7 @@ static struct spi_driver wm8750_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8750_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -868,7 +862,7 @@ static struct i2c_driver wm8750_i2c_driver = {  static int __init wm8750_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8750_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n", @@ -888,7 +882,7 @@ module_init(wm8750_modinit);  static void __exit wm8750_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8750_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d96ebf52d95..53e57b4049a 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -234,7 +234,7 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),  static int wm8753_get_dai(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = wm8753->dai_func; @@ -244,14 +244,14 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,  static int wm8753_set_dai(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);  	u16 ioctl;  	if (wm8753->dai_func == ucontrol->value.integer.value[0])  		return 0; -	if (codec->active) +	if (snd_soc_codec_is_active(codec))  		return -EBUSY;  	ioctl = snd_soc_read(codec, WM8753_IOCTL); @@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)  	/* the digital mute covers the HiFi and Voice DAC's on the WM8753.  	 * make sure we check if they are not both active when we mute */  	if (mute && wm8753->dai_func == 1) { -		if (!codec->active) +		if (!snd_soc_codec_is_active(codec))  			snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);  	} else {  		if (mute) @@ -1440,7 +1440,6 @@ static void wm8753_work(struct work_struct *work)  static int wm8753_suspend(struct snd_soc_codec *codec)  {  	wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); -	codec->cache_sync = 1;  	return 0;  } @@ -1471,13 +1470,6 @@ static int wm8753_probe(struct snd_soc_codec *codec)  	INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work); -	codec->control_data = wm8753->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8753_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset: %d\n", ret); @@ -1596,7 +1588,7 @@ static struct spi_driver wm8753_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8753_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -1653,7 +1645,7 @@ static struct i2c_driver wm8753_i2c_driver = {  static int __init wm8753_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8753_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n", @@ -1673,7 +1665,7 @@ module_init(wm8753_modinit);  static void __exit wm8753_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8753_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 89a18d82f30..c61aeb38efb 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -196,8 +196,8 @@ static const char *ain_text[] = {  	"AIN5", "AIN6", "AIN7", "AIN8"  }; -static const struct soc_enum ain_enum = -	SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text); +static SOC_ENUM_DOUBLE_DECL(ain_enum, +			    WM8770_ADCMUX, 0, 4, ain_text);  static const struct snd_kcontrol_new ain_mux =  	SOC_DAPM_ENUM("Capture Mux", ain_enum); @@ -580,12 +580,6 @@ static int wm8770_probe(struct snd_soc_codec *codec)  	wm8770 = snd_soc_codec_get_drvdata(codec);  	wm8770->codec = codec; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),  				    wm8770->supplies);  	if (ret) { diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index f31017ed138..70952ceb278 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -325,7 +325,8 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,  	struct snd_soc_codec *codec = dai->codec;  	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec); -	BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk)); +	if (WARN_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk))) +		return -EINVAL;  	wm8776->sysclk[dai->driver->id] = freq; @@ -429,12 +430,6 @@ static int wm8776_probe(struct snd_soc_codec *codec)  {  	int ret = 0; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8776_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset: %d\n", ret); @@ -531,7 +526,7 @@ static struct spi_driver wm8776_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8776_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -583,7 +578,7 @@ static struct i2c_driver wm8776_i2c_driver = {  static int __init wm8776_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8776_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n", @@ -603,7 +598,7 @@ module_init(wm8776_modinit);  static void __exit wm8776_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8776_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 1704b1e119c..d96e5963ee3 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -63,6 +63,7 @@ struct wm8804_priv {  	struct regmap *regmap;  	struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];  	struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; +	int mclk_div;  };  static int txsrc_get(struct snd_kcontrol *kcontrol, @@ -92,7 +93,7 @@ WM8804_REGULATOR_EVENT(0)  WM8804_REGULATOR_EVENT(1)  static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; -static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); +static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);  static const struct snd_kcontrol_new wm8804_snd_controls[] = {  	SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put), @@ -106,7 +107,7 @@ static int txsrc_get(struct snd_kcontrol *kcontrol,  	struct snd_soc_codec *codec;  	unsigned int src; -	codec = snd_kcontrol_chip(kcontrol); +	codec = snd_soc_kcontrol_codec(kcontrol);  	src = snd_soc_read(codec, WM8804_SPDTX4);  	if (src & 0x40)  		ucontrol->value.integer.value[0] = 1; @@ -122,7 +123,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol,  	struct snd_soc_codec *codec;  	unsigned int src, txpwr; -	codec = snd_kcontrol_chip(kcontrol); +	codec = snd_soc_kcontrol_codec(kcontrol);  	if (ucontrol->value.integer.value[0] != 0  			&& ucontrol->value.integer.value[0] != 1) @@ -318,7 +319,7 @@ static struct {  #define FIXED_PLL_SIZE ((1ULL << 22) * 10)  static int pll_factors(struct pll_div *pll_div, unsigned int target, -		       unsigned int source) +		       unsigned int source, unsigned int mclk_div)  {  	u64 Kpart;  	unsigned long int K, Ndiv, Nmod, tmp; @@ -330,7 +331,8 @@ static int pll_factors(struct pll_div *pll_div, unsigned int target,  	 */  	for (i = 0; i < ARRAY_SIZE(post_table); i++) {  		tmp = target * post_table[i].div; -		if (tmp >= 90000000 && tmp <= 100000000) { +		if ((tmp >= 90000000 && tmp <= 100000000) && +		    (mclk_div == post_table[i].mclkdiv)) {  			pll_div->freqmode = post_table[i].freqmode;  			pll_div->mclkdiv = post_table[i].mclkdiv;  			target *= post_table[i].div; @@ -387,8 +389,12 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,  	} else {  		int ret;  		struct pll_div pll_div; +		struct wm8804_priv *wm8804; -		ret = pll_factors(&pll_div, freq_out, freq_in); +		wm8804 = snd_soc_codec_get_drvdata(codec); + +		ret = pll_factors(&pll_div, freq_out, freq_in, +				  wm8804->mclk_div);  		if (ret)  			return ret; @@ -452,6 +458,7 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,  			     int div_id, int div)  {  	struct snd_soc_codec *codec; +	struct wm8804_priv *wm8804;  	codec = dai->codec;  	switch (div_id) { @@ -459,6 +466,10 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,  		snd_soc_update_bits(codec, WM8804_PLL5, 0x30,  				    (div & 0x3) << 4);  		break; +	case WM8804_MCLK_DIV: +		wm8804 = snd_soc_codec_get_drvdata(codec); +		wm8804->mclk_div = div; +		break;  	default:  		dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);  		return -EINVAL; @@ -535,7 +546,6 @@ static int wm8804_remove(struct snd_soc_codec *codec)  	for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)  		regulator_unregister_notifier(wm8804->supplies[i].consumer,  					      &wm8804->disable_nb[i]); -	regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);  	return 0;  } @@ -546,18 +556,10 @@ static int wm8804_probe(struct snd_soc_codec *codec)  	wm8804 = snd_soc_codec_get_drvdata(codec); -	codec->control_data = wm8804->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); -		return ret; -	} -  	for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)  		wm8804->supplies[i].supply = wm8804_supply_names[i]; -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies), +	ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),  				 wm8804->supplies);  	if (ret) {  		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -582,7 +584,7 @@ static int wm8804_probe(struct snd_soc_codec *codec)  				    wm8804->supplies);  	if (ret) {  		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); -		goto err_reg_get; +		return ret;  	}  	id1 = snd_soc_read(codec, WM8804_RST_DEVID1); @@ -627,8 +629,6 @@ static int wm8804_probe(struct snd_soc_codec *codec)  err_reg_enable:  	regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); -err_reg_get: -	regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);  	return ret;  } @@ -739,7 +739,7 @@ static struct spi_driver wm8804_spi_driver = {  };  #endif -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8804_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -791,7 +791,7 @@ static int __init wm8804_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8804_i2c_driver);  	if (ret) {  		printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n", @@ -811,7 +811,7 @@ module_init(wm8804_modinit);  static void __exit wm8804_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8804_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h index 8ec14f5573c..e72d4f4ba6b 100644 --- a/sound/soc/codecs/wm8804.h +++ b/sound/soc/codecs/wm8804.h @@ -57,5 +57,9 @@  #define WM8804_CLKOUT_SRC_OSCCLK		4  #define WM8804_CLKOUT_DIV			1 +#define WM8804_MCLK_DIV				2 + +#define WM8804_MCLKDIV_256FS			0 +#define WM8804_MCLKDIV_128FS			1  #endif  /* _WM8804_H */ diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 7c8257c5a17..d09fdce57f5 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -279,7 +279,8 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w,  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event); +		break;  	}  	return 0; @@ -303,53 +304,53 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);  static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; -static const struct soc_enum mic_bias_level = -SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); +static SOC_ENUM_SINGLE_DECL(mic_bias_level, +			    WM8900_REG_INCTL, 8, mic_bias_level_txt);  static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; -static const struct soc_enum dac_mute_rate = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); +static SOC_ENUM_SINGLE_DECL(dac_mute_rate, +			    WM8900_REG_DACCTRL, 7, dac_mute_rate_txt);  static const char *dac_deemphasis_txt[] = {  	"Disabled", "32kHz", "44.1kHz", "48kHz"  }; -static const struct soc_enum dac_deemphasis = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); +static SOC_ENUM_SINGLE_DECL(dac_deemphasis, +			    WM8900_REG_DACCTRL, 4, dac_deemphasis_txt);  static const char *adc_hpf_cut_txt[] = {  	"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"  }; -static const struct soc_enum adc_hpf_cut = -SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); +static SOC_ENUM_SINGLE_DECL(adc_hpf_cut, +			    WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt);  static const char *lr_txt[] = {  	"Left", "Right"  }; -static const struct soc_enum aifl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(aifl_src, +			    WM8900_REG_AUDIO1, 15, lr_txt); -static const struct soc_enum aifr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(aifr_src, +			    WM8900_REG_AUDIO1, 14, lr_txt); -static const struct soc_enum dacl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(dacl_src, +			    WM8900_REG_AUDIO2, 15, lr_txt); -static const struct soc_enum dacr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(dacr_src, +			    WM8900_REG_AUDIO2, 14, lr_txt);  static const char *sidetone_txt[] = {  	"Disabled", "Left ADC", "Right ADC"  }; -static const struct soc_enum dacl_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); +static SOC_ENUM_SINGLE_DECL(dacl_sidetone, +			    WM8900_REG_SIDETONE, 2, sidetone_txt); -static const struct soc_enum dacr_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); +static SOC_ENUM_SINGLE_DECL(dacr_sidetone, +			    WM8900_REG_SIDETONE, 0, sidetone_txt);  static const struct snd_kcontrol_new wm8900_snd_controls[] = {  SOC_ENUM("Mic Bias Level", mic_bias_level), @@ -495,8 +496,8 @@ SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),  static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" }; -static const struct soc_enum wm8900_lineout2_lp_mux = -SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux); +static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux, +			    WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux);  static const struct snd_kcontrol_new wm8900_lineout2_lp =  SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); @@ -691,7 +692,8 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,  	unsigned int K, Ndiv, Nmod, target;  	unsigned int div; -	BUG_ON(!Fout); +	if (WARN_ON(!Fout)) +		return -EINVAL;  	/* The FLL must run at 90-100MHz which is then scaled down to  	 * the output value by FLLCLK_DIV. */ @@ -742,8 +744,9 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,  	/* Move down to proper range now rounding is done */  	fll_div->k = K / 10; -	BUG_ON(target != Fout * (fll_div->fllclk_div << 2)); -	BUG_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n); +	if (WARN_ON(target != Fout * (fll_div->fllclk_div << 2)) || +	    WARN_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n)) +		return -EINVAL;  	return 0;  } @@ -1175,13 +1178,7 @@ static int wm8900_resume(struct snd_soc_codec *codec)  static int wm8900_probe(struct snd_soc_codec *codec)  { -	int ret = 0, reg; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} +	int reg;  	reg = snd_soc_read(codec, WM8900_REG_ID);  	if (reg != 0x8900) { @@ -1285,7 +1282,7 @@ static struct spi_driver wm8900_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8900_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -1335,7 +1332,7 @@ static struct i2c_driver wm8900_i2c_driver = {  static int __init wm8900_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8900_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n", @@ -1355,7 +1352,7 @@ module_init(wm8900_modinit);  static void __exit wm8900_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8900_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index eebcb1da3b7..b84940c359a 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -439,7 +439,7 @@ static int wm8903_set_deemph(struct snd_soc_codec *codec)  static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8903->deemph; @@ -450,7 +450,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,  static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);  	int deemph = ucontrol->value.enumerated.item[0];  	int ret = 0; @@ -489,28 +489,28 @@ static const char *hpf_mode_text[] = {  	"Hi-fi", "Voice 1", "Voice 2", "Voice 3"  }; -static const struct soc_enum hpf_mode = -	SOC_ENUM_SINGLE(WM8903_ADC_DIGITAL_0, 5, 4, hpf_mode_text); +static SOC_ENUM_SINGLE_DECL(hpf_mode, +			    WM8903_ADC_DIGITAL_0, 5, hpf_mode_text);  static const char *osr_text[] = {  	"Low power", "High performance"  }; -static const struct soc_enum adc_osr = -	SOC_ENUM_SINGLE(WM8903_ANALOGUE_ADC_0, 0, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(adc_osr, +			    WM8903_ANALOGUE_ADC_0, 0, osr_text); -static const struct soc_enum dac_osr = -	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 0, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(dac_osr, +			    WM8903_DAC_DIGITAL_1, 0, osr_text);  static const char *drc_slope_text[] = {  	"1", "1/2", "1/4", "1/8", "1/16", "0"  }; -static const struct soc_enum drc_slope_r0 = -	SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text); +static SOC_ENUM_SINGLE_DECL(drc_slope_r0, +			    WM8903_DRC_2, 3, drc_slope_text); -static const struct soc_enum drc_slope_r1 = -	SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text); +static SOC_ENUM_SINGLE_DECL(drc_slope_r1, +			    WM8903_DRC_2, 0, drc_slope_text);  static const char *drc_attack_text[] = {  	"instantaneous", @@ -518,125 +518,125 @@ static const char *drc_attack_text[] = {  	"46.4ms", "92.8ms", "185.6ms"  }; -static const struct soc_enum drc_attack = -	SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text); +static SOC_ENUM_SINGLE_DECL(drc_attack, +			    WM8903_DRC_1, 12, drc_attack_text);  static const char *drc_decay_text[] = {  	"186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",  	"23.87s", "47.56s"  }; -static const struct soc_enum drc_decay = -	SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text); +static SOC_ENUM_SINGLE_DECL(drc_decay, +			    WM8903_DRC_1, 8, drc_decay_text);  static const char *drc_ff_delay_text[] = {  	"5 samples", "9 samples"  }; -static const struct soc_enum drc_ff_delay = -	SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text); +static SOC_ENUM_SINGLE_DECL(drc_ff_delay, +			    WM8903_DRC_0, 5, drc_ff_delay_text);  static const char *drc_qr_decay_text[] = {  	"0.725ms", "1.45ms", "5.8ms"  }; -static const struct soc_enum drc_qr_decay = -	SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text); +static SOC_ENUM_SINGLE_DECL(drc_qr_decay, +			    WM8903_DRC_1, 4, drc_qr_decay_text);  static const char *drc_smoothing_text[] = {  	"Low", "Medium", "High"  }; -static const struct soc_enum drc_smoothing = -	SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text); +static SOC_ENUM_SINGLE_DECL(drc_smoothing, +			    WM8903_DRC_0, 11, drc_smoothing_text);  static const char *soft_mute_text[] = {  	"Fast (fs/2)", "Slow (fs/32)"  }; -static const struct soc_enum soft_mute = -	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text); +static SOC_ENUM_SINGLE_DECL(soft_mute, +			    WM8903_DAC_DIGITAL_1, 10, soft_mute_text);  static const char *mute_mode_text[] = {  	"Hard", "Soft"  }; -static const struct soc_enum mute_mode = -	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text); +static SOC_ENUM_SINGLE_DECL(mute_mode, +			    WM8903_DAC_DIGITAL_1, 9, mute_mode_text);  static const char *companding_text[] = {  	"ulaw", "alaw"  }; -static const struct soc_enum dac_companding = -	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text); +static SOC_ENUM_SINGLE_DECL(dac_companding, +			    WM8903_AUDIO_INTERFACE_0, 0, companding_text); -static const struct soc_enum adc_companding = -	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text); +static SOC_ENUM_SINGLE_DECL(adc_companding, +			    WM8903_AUDIO_INTERFACE_0, 2, companding_text);  static const char *input_mode_text[] = {  	"Single-Ended", "Differential Line", "Differential Mic"  }; -static const struct soc_enum linput_mode_enum = -	SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); +static SOC_ENUM_SINGLE_DECL(linput_mode_enum, +			    WM8903_ANALOGUE_LEFT_INPUT_1, 0, input_mode_text); -static const struct soc_enum rinput_mode_enum = -	SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); +static SOC_ENUM_SINGLE_DECL(rinput_mode_enum, +			    WM8903_ANALOGUE_RIGHT_INPUT_1, 0, input_mode_text);  static const char *linput_mux_text[] = {  	"IN1L", "IN2L", "IN3L"  }; -static const struct soc_enum linput_enum = -	SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text); +static SOC_ENUM_SINGLE_DECL(linput_enum, +			    WM8903_ANALOGUE_LEFT_INPUT_1, 2, linput_mux_text); -static const struct soc_enum linput_inv_enum = -	SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text); +static SOC_ENUM_SINGLE_DECL(linput_inv_enum, +			    WM8903_ANALOGUE_LEFT_INPUT_1, 4, linput_mux_text);  static const char *rinput_mux_text[] = {  	"IN1R", "IN2R", "IN3R"  }; -static const struct soc_enum rinput_enum = -	SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text); +static SOC_ENUM_SINGLE_DECL(rinput_enum, +			    WM8903_ANALOGUE_RIGHT_INPUT_1, 2, rinput_mux_text); -static const struct soc_enum rinput_inv_enum = -	SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text); +static SOC_ENUM_SINGLE_DECL(rinput_inv_enum, +			    WM8903_ANALOGUE_RIGHT_INPUT_1, 4, rinput_mux_text);  static const char *sidetone_text[] = {  	"None", "Left", "Right"  }; -static const struct soc_enum lsidetone_enum = -	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(lsidetone_enum, +			    WM8903_DAC_DIGITAL_0, 2, sidetone_text); -static const struct soc_enum rsidetone_enum = -	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(rsidetone_enum, +			    WM8903_DAC_DIGITAL_0, 0, sidetone_text);  static const char *adcinput_text[] = {  	"ADC", "DMIC"  }; -static const struct soc_enum adcinput_enum = -	SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text); +static SOC_ENUM_SINGLE_DECL(adcinput_enum, +			    WM8903_CLOCK_RATE_TEST_4, 9, adcinput_text);  static const char *aif_text[] = {  	"Left", "Right"  }; -static const struct soc_enum lcapture_enum = -	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 7, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(lcapture_enum, +			    WM8903_AUDIO_INTERFACE_0, 7, aif_text); -static const struct soc_enum rcapture_enum = -	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 6, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(rcapture_enum, +			    WM8903_AUDIO_INTERFACE_0, 6, aif_text); -static const struct soc_enum lplay_enum = -	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 5, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(lplay_enum, +			    WM8903_AUDIO_INTERFACE_0, 5, aif_text); -static const struct soc_enum rplay_enum = -	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 4, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(rplay_enum, +			    WM8903_AUDIO_INTERFACE_0, 4, aif_text);  static const struct snd_kcontrol_new wm8903_snd_controls[] = { @@ -1897,21 +1897,13 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903)  static int wm8903_probe(struct snd_soc_codec *codec)  {  	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); -	int ret;  	wm8903->codec = codec; -	codec->control_data = wm8903->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	/* power on device */  	wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	return ret; +	return 0;  }  /* power down chip */ diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 4dfa8dceeab..f7c549949c5 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -391,7 +391,7 @@ static void wm8904_set_drc(struct snd_soc_codec *codec)  static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  	struct wm8904_pdata *pdata = wm8904->pdata;  	int value = ucontrol->value.integer.value[0]; @@ -409,7 +409,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,  static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8904->drc_cfg; @@ -462,7 +462,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)  static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,  					 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  	struct wm8904_pdata *pdata = wm8904->pdata;  	int value = ucontrol->value.integer.value[0]; @@ -480,7 +480,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,  static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,  					 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg; @@ -520,7 +520,7 @@ static int wm8904_set_deemph(struct snd_soc_codec *codec)  static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8904->deemph; @@ -530,7 +530,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,  static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  	int deemph = ucontrol->value.enumerated.item[0]; @@ -552,23 +552,25 @@ static const char *input_mode_text[] = {  	"Single-Ended", "Differential Line", "Differential Mic"  }; -static const struct soc_enum lin_mode = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); +static SOC_ENUM_SINGLE_DECL(lin_mode, +			    WM8904_ANALOGUE_LEFT_INPUT_1, 0, +			    input_mode_text); -static const struct soc_enum rin_mode = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); +static SOC_ENUM_SINGLE_DECL(rin_mode, +			    WM8904_ANALOGUE_RIGHT_INPUT_1, 0, +			    input_mode_text);  static const char *hpf_mode_text[] = {  	"Hi-fi", "Voice 1", "Voice 2", "Voice 3"  }; -static const struct soc_enum hpf_mode = -	SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text); +static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5, +			    hpf_mode_text);  static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,  			      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int val;  	int ret; @@ -611,8 +613,7 @@ static const char *drc_path_text[] = {  	"ADC", "DAC"  }; -static const struct soc_enum drc_path = -	SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text); +static SOC_ENUM_SINGLE_DECL(drc_path, WM8904_DRC_0, 14, drc_path_text);  static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = {  SOC_SINGLE_TLV("Digital Playback Boost Volume",  @@ -658,7 +659,8 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv),  static int cp_event(struct snd_soc_dapm_widget *w,  		    struct snd_kcontrol *kcontrol, int event)  { -	BUG_ON(event != SND_SOC_DAPM_POST_PMU); +	if (WARN_ON(event != SND_SOC_DAPM_POST_PMU)) +		return -EINVAL;  	/* Maximum startup time */  	udelay(500); @@ -740,7 +742,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,  		dcs_r = 3;  		break;  	default: -		BUG(); +		WARN(1, "Invalid reg %d\n", reg);  		return -EINVAL;  	} @@ -857,14 +859,14 @@ static const char *lin_text[] = {  	"IN1L", "IN2L", "IN3L"  }; -static const struct soc_enum lin_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text); +static SOC_ENUM_SINGLE_DECL(lin_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 2, +			    lin_text);  static const struct snd_kcontrol_new lin_mux =  	SOC_DAPM_ENUM("Left Capture Mux", lin_enum); -static const struct soc_enum lin_inv_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text); +static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4, +			    lin_text);  static const struct snd_kcontrol_new lin_inv_mux =  	SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum); @@ -873,14 +875,14 @@ static const char *rin_text[] = {  	"IN1R", "IN2R", "IN3R"  }; -static const struct soc_enum rin_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text); +static SOC_ENUM_SINGLE_DECL(rin_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 2, +			    rin_text);  static const struct snd_kcontrol_new rin_mux =  	SOC_DAPM_ENUM("Right Capture Mux", rin_enum); -static const struct soc_enum rin_inv_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text); +static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4, +			    rin_text);  static const struct snd_kcontrol_new rin_inv_mux =  	SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum); @@ -889,26 +891,26 @@ static const char *aif_text[] = {  	"Left", "Right"  }; -static const struct soc_enum aifoutl_enum = -	SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifoutl_enum, WM8904_AUDIO_INTERFACE_0, 7, +			    aif_text);  static const struct snd_kcontrol_new aifoutl_mux =  	SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); -static const struct soc_enum aifoutr_enum = -	SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifoutr_enum, WM8904_AUDIO_INTERFACE_0, 6, +			    aif_text);  static const struct snd_kcontrol_new aifoutr_mux =  	SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); -static const struct soc_enum aifinl_enum = -	SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifinl_enum, WM8904_AUDIO_INTERFACE_0, 5, +			    aif_text);  static const struct snd_kcontrol_new aifinl_mux =  	SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); -static const struct soc_enum aifinr_enum = -	SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifinr_enum, WM8904_AUDIO_INTERFACE_0, 4, +			    aif_text);  static const struct snd_kcontrol_new aifinr_mux =  	SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); @@ -990,26 +992,26 @@ static const char *out_mux_text[] = {  	"DAC", "Bypass"  }; -static const struct soc_enum hpl_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(hpl_enum, WM8904_ANALOGUE_OUT12_ZC, 3, +			    out_mux_text);  static const struct snd_kcontrol_new hpl_mux =  	SOC_DAPM_ENUM("HPL Mux", hpl_enum); -static const struct soc_enum hpr_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(hpr_enum, WM8904_ANALOGUE_OUT12_ZC, 2, +			    out_mux_text);  static const struct snd_kcontrol_new hpr_mux =  	SOC_DAPM_ENUM("HPR Mux", hpr_enum); -static const struct soc_enum linel_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(linel_enum, WM8904_ANALOGUE_OUT12_ZC, 1, +			    out_mux_text);  static const struct snd_kcontrol_new linel_mux =  	SOC_DAPM_ENUM("LINEL Mux", linel_enum); -static const struct soc_enum liner_enum = -	SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(liner_enum, WM8904_ANALOGUE_OUT12_ZC, 0, +			    out_mux_text);  static const struct snd_kcontrol_new liner_mux =  	SOC_DAPM_ENUM("LINER Mux", liner_enum); @@ -1018,14 +1020,14 @@ static const char *sidetone_text[] = {  	"None", "Left", "Right"  }; -static const struct soc_enum dacl_sidetone_enum = -	SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(dacl_sidetone_enum, WM8904_DAC_DIGITAL_0, 2, +			    sidetone_text);  static const struct snd_kcontrol_new dacl_sidetone_mux =  	SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum); -static const struct soc_enum dacr_sidetone_enum = -	SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(dacr_sidetone_enum, WM8904_DAC_DIGITAL_0, 0, +			    sidetone_text);  static const struct snd_kcontrol_new dacr_sidetone_mux =  	SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum); @@ -1443,7 +1445,7 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {  	case SND_SOC_DAIFMT_DSP_B: -		aif1 |= WM8904_AIF_LRCLK_INV; +		aif1 |= 0x3 | WM8904_AIF_LRCLK_INV;  	case SND_SOC_DAIFMT_DSP_A:  		aif1 |= 0x3;  		break; @@ -1980,7 +1982,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)  	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",  		wm8904->num_retune_mobile_texts); -	wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; +	wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts;  	wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;  	ret = snd_soc_add_codec_controls(codec, &control, 1); @@ -2021,7 +2023,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)  		for (i = 0; i < pdata->num_drc_cfgs; i++)  			wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; -		wm8904->drc_enum.max = pdata->num_drc_cfgs; +		wm8904->drc_enum.items = pdata->num_drc_cfgs;  		wm8904->drc_enum.texts = wm8904->drc_texts;  		ret = snd_soc_add_codec_controls(codec, &control, 1); @@ -2046,9 +2048,6 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)  static int wm8904_probe(struct snd_soc_codec *codec)  {  	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = wm8904->regmap;  	switch (wm8904->devtype) {  	case WM8904: @@ -2062,12 +2061,6 @@ static int wm8904_probe(struct snd_soc_codec *codec)  		return -EINVAL;  	} -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	wm8904_handle_pdata(codec);  	wm8904_add_widgets(codec); diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index b1591c61c25..fc6eec9ad66 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -28,7 +28,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> -#include <linux/spi/spi.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -41,97 +41,135 @@  struct wm8940_priv {  	unsigned int sysclk; -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  }; -static int wm8940_volatile_register(struct snd_soc_codec *codec, -				    unsigned int reg) +static bool wm8940_volatile_register(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case WM8940_SOFTRESET: -		return 1; +		return true;  	default: -		return 0; +		return false; +	} +} + +static bool wm8940_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8940_SOFTRESET: +	case WM8940_POWER1: +	case WM8940_POWER2: +	case WM8940_POWER3: +	case WM8940_IFACE: +	case WM8940_COMPANDINGCTL: +	case WM8940_CLOCK: +	case WM8940_ADDCNTRL: +	case WM8940_GPIO: +	case WM8940_CTLINT: +	case WM8940_DAC: +	case WM8940_DACVOL: +	case WM8940_ADC: +	case WM8940_ADCVOL: +	case WM8940_NOTCH1: +	case WM8940_NOTCH2: +	case WM8940_NOTCH3: +	case WM8940_NOTCH4: +	case WM8940_NOTCH5: +	case WM8940_NOTCH6: +	case WM8940_NOTCH7: +	case WM8940_NOTCH8: +	case WM8940_DACLIM1: +	case WM8940_DACLIM2: +	case WM8940_ALC1: +	case WM8940_ALC2: +	case WM8940_ALC3: +	case WM8940_NOISEGATE: +	case WM8940_PLLN: +	case WM8940_PLLK1: +	case WM8940_PLLK2: +	case WM8940_PLLK3: +	case WM8940_ALC4: +	case WM8940_INPUTCTL: +	case WM8940_PGAGAIN: +	case WM8940_ADCBOOST: +	case WM8940_OUTPUTCTL: +	case WM8940_SPKMIX: +	case WM8940_SPKVOL: +	case WM8940_MONOMIX: +		return true; +	default: +		return false;  	}  } -static u16 wm8940_reg_defaults[] = { -	0x8940, /* Soft Reset */ -	0x0000, /* Power 1 */ -	0x0000, /* Power 2 */ -	0x0000, /* Power 3 */ -	0x0010, /* Interface Control */ -	0x0000, /* Companding Control */ -	0x0140, /* Clock Control */ -	0x0000, /* Additional Controls */ -	0x0000, /* GPIO Control */ -	0x0002, /* Auto Increment Control */ -	0x0000, /* DAC Control */ -	0x00FF, /* DAC Volume */ -	0, -	0, -	0x0100, /* ADC Control */ -	0x00FF, /* ADC Volume */ -	0x0000, /* Notch Filter 1 Control 1 */ -	0x0000, /* Notch Filter 1 Control 2 */ -	0x0000, /* Notch Filter 2 Control 1 */ -	0x0000, /* Notch Filter 2 Control 2 */ -	0x0000, /* Notch Filter 3 Control 1 */ -	0x0000, /* Notch Filter 3 Control 2 */ -	0x0000, /* Notch Filter 4 Control 1 */ -	0x0000, /* Notch Filter 4 Control 2 */ -	0x0032, /* DAC Limit Control 1 */ -	0x0000, /* DAC Limit Control 2 */ -	0, -	0, -	0, -	0, -	0, -	0, -	0x0038, /* ALC Control 1 */ -	0x000B, /* ALC Control 2 */ -	0x0032, /* ALC Control 3 */ -	0x0000, /* Noise Gate */ -	0x0041, /* PLLN */ -	0x000C, /* PLLK1 */ -	0x0093, /* PLLK2 */ -	0x00E9, /* PLLK3 */ -	0, -	0, -	0x0030, /* ALC Control 4 */ -	0, -	0x0002, /* Input Control */ -	0x0050, /* PGA Gain */ -	0, -	0x0002, /* ADC Boost Control */ -	0, -	0x0002, /* Output Control */ -	0x0000, /* Speaker Mixer Control */ -	0, -	0, -	0, -	0x0079, /* Speaker Volume */ -	0, -	0x0000, /* Mono Mixer Control */ +static const struct reg_default wm8940_reg_defaults[] = { +	{  0x1, 0x0000 }, /* Power 1 */ +	{  0x2, 0x0000 }, /* Power 2 */ +	{  0x3, 0x0000 }, /* Power 3 */ +	{  0x4, 0x0010 }, /* Interface Control */ +	{  0x5, 0x0000 }, /* Companding Control */ +	{  0x6, 0x0140 }, /* Clock Control */ +	{  0x7, 0x0000 }, /* Additional Controls */ +	{  0x8, 0x0000 }, /* GPIO Control */ +	{  0x9, 0x0002 }, /* Auto Increment Control */ +	{  0xa, 0x0000 }, /* DAC Control */ +	{  0xb, 0x00FF }, /* DAC Volume */ + +	{  0xe, 0x0100 }, /* ADC Control */ +	{  0xf, 0x00FF }, /* ADC Volume */ +	{ 0x10, 0x0000 }, /* Notch Filter 1 Control 1 */ +	{ 0x11, 0x0000 }, /* Notch Filter 1 Control 2 */ +	{ 0x12, 0x0000 }, /* Notch Filter 2 Control 1 */ +	{ 0x13, 0x0000 }, /* Notch Filter 2 Control 2 */ +	{ 0x14, 0x0000 }, /* Notch Filter 3 Control 1 */ +	{ 0x15, 0x0000 }, /* Notch Filter 3 Control 2 */ +	{ 0x16, 0x0000 }, /* Notch Filter 4 Control 1 */ +	{ 0x17, 0x0000 }, /* Notch Filter 4 Control 2 */ +	{ 0x18, 0x0032 }, /* DAC Limit Control 1 */ +	{ 0x19, 0x0000 }, /* DAC Limit Control 2 */ + +	{ 0x20, 0x0038 }, /* ALC Control 1 */ +	{ 0x21, 0x000B }, /* ALC Control 2 */ +	{ 0x22, 0x0032 }, /* ALC Control 3 */ +	{ 0x23, 0x0000 }, /* Noise Gate */ +	{ 0x24, 0x0041 }, /* PLLN */ +	{ 0x25, 0x000C }, /* PLLK1 */ +	{ 0x26, 0x0093 }, /* PLLK2 */ +	{ 0x27, 0x00E9 }, /* PLLK3 */ + +	{ 0x2a, 0x0030 }, /* ALC Control 4 */ + +	{ 0x2c, 0x0002 }, /* Input Control */ +	{ 0x2d, 0x0050 }, /* PGA Gain */ + +	{ 0x2f, 0x0002 }, /* ADC Boost Control */ + +	{ 0x31, 0x0002 }, /* Output Control */ +	{ 0x32, 0x0000 }, /* Speaker Mixer Control */ + +	{ 0x36, 0x0079 }, /* Speaker Volume */ + +	{ 0x38, 0x0000 }, /* Mono Mixer Control */  };  static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; -static const struct soc_enum wm8940_adc_companding_enum -= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); -static const struct soc_enum wm8940_dac_companding_enum -= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding); +static SOC_ENUM_SINGLE_DECL(wm8940_adc_companding_enum, +			    WM8940_COMPANDINGCTL, 1, wm8940_companding); +static SOC_ENUM_SINGLE_DECL(wm8940_dac_companding_enum, +			    WM8940_COMPANDINGCTL, 3, wm8940_companding);  static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"}; -static const struct soc_enum wm8940_alc_mode_enum -= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text); +static SOC_ENUM_SINGLE_DECL(wm8940_alc_mode_enum, +			    WM8940_ALC3, 8, wm8940_alc_mode_text);  static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"}; -static const struct soc_enum wm8940_mic_bias_level_enum -= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text); +static SOC_ENUM_SINGLE_DECL(wm8940_mic_bias_level_enum, +			    WM8940_INPUTCTL, 8, wm8940_mic_bias_level_text);  static const char *wm8940_filter_mode_text[] = {"Audio", "Application"}; -static const struct soc_enum wm8940_filter_mode_enum -= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text); +static SOC_ENUM_SINGLE_DECL(wm8940_filter_mode_enum, +			    WM8940_ADC, 7, wm8940_filter_mode_text);  static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);  static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0); @@ -264,7 +302,7 @@ static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {  	SND_SOC_DAPM_INPUT("AUX"),  }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {  	/* Mono output mixer */  	{"Mono Mixer", "PCM Playback Switch", "DAC"},  	{"Mono Mixer", "Aux Playback Switch", "Aux Input"}, @@ -296,21 +334,6 @@ static const struct snd_soc_dapm_route audio_map[] = {  	{"ADC", NULL, "Boost Mixer"},  }; -static int wm8940_add_widgets(struct snd_soc_codec *codec) -{ -	struct snd_soc_dapm_context *dapm = &codec->dapm; -	int ret; - -	ret = snd_soc_dapm_new_controls(dapm, wm8940_dapm_widgets, -					ARRAY_SIZE(wm8940_dapm_widgets)); -	if (ret) -		goto error_ret; -	ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - -error_ret: -	return ret; -} -  #define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);  static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, @@ -446,6 +469,7 @@ static int wm8940_mute(struct snd_soc_dai *dai, int mute)  static int wm8940_set_bias_level(struct snd_soc_codec *codec,  				 enum snd_soc_bias_level level)  { +	struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);  	u16 val;  	u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;  	int ret = 0; @@ -469,7 +493,7 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			ret = snd_soc_cache_sync(codec); +			ret = regcache_sync(wm8940->regmap);  			if (ret < 0) {  				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);  				return ret; @@ -684,17 +708,10 @@ static int wm8940_resume(struct snd_soc_codec *codec)  static int wm8940_probe(struct snd_soc_codec *codec)  { -	struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);  	struct wm8940_setup_data *pdata = codec->dev->platform_data;  	int ret;  	u16 reg; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8940_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset\n"); @@ -716,11 +733,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)  			return ret;  	} -	ret = snd_soc_add_codec_controls(codec, wm8940_snd_controls, -			     ARRAY_SIZE(wm8940_snd_controls)); -	if (ret) -		return ret; -	ret = wm8940_add_widgets(codec);  	return ret;  } @@ -736,10 +748,24 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {  	.suspend =	wm8940_suspend,  	.resume =	wm8940_resume,  	.set_bias_level = wm8940_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8940_reg_defaults, -	.volatile_register = wm8940_volatile_register, +	.controls =     wm8940_snd_controls, +	.num_controls = ARRAY_SIZE(wm8940_snd_controls), +	.dapm_widgets = wm8940_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets), +	.dapm_routes =  wm8940_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes), +}; + +static const struct regmap_config wm8940_regmap = { +	.reg_bits = 8, +	.val_bits = 16, + +	.max_register = WM8940_MONOMIX, +	.reg_defaults = wm8940_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults), + +	.readable_reg = wm8940_readable_register, +	.volatile_reg = wm8940_volatile_register,  };  static int wm8940_i2c_probe(struct i2c_client *i2c, @@ -753,8 +779,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,  	if (wm8940 == NULL)  		return -ENOMEM; +	wm8940->regmap = devm_regmap_init_i2c(i2c, &wm8940_regmap); +	if (IS_ERR(wm8940->regmap)) +		return PTR_ERR(wm8940->regmap); +  	i2c_set_clientdata(i2c, wm8940); -	wm8940->control_type = SND_SOC_I2C;  	ret = snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8940, &wm8940_dai, 1); diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 82c8ba97572..2a35108f233 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -390,7 +390,7 @@ static int wm8955_set_deemph(struct snd_soc_codec *codec)  static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8955->deemph; @@ -400,7 +400,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,  static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);  	int deemph = ucontrol->value.enumerated.item[0]; @@ -416,22 +416,21 @@ static const char *bass_mode_text[] = {  	"Linear", "Adaptive",  }; -static const struct soc_enum bass_mode = -	SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text); +static SOC_ENUM_SINGLE_DECL(bass_mode, WM8955_BASS_CONTROL, 7, bass_mode_text);  static const char *bass_cutoff_text[] = {  	"Low", "High"  }; -static const struct soc_enum bass_cutoff = -	SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text); +static SOC_ENUM_SINGLE_DECL(bass_cutoff, WM8955_BASS_CONTROL, 6, +			    bass_cutoff_text);  static const char *treble_cutoff_text[] = {  	"High", "Low"  }; -static const struct soc_enum treble_cutoff = -	SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text); +static SOC_ENUM_SINGLE_DECL(treble_cutoff, WM8955_TREBLE_CONTROL, 2, +			    treble_cutoff_text);  static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);  static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0); @@ -896,18 +895,10 @@ static int wm8955_probe(struct snd_soc_codec *codec)  	struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);  	int ret, i; -	codec->control_data = wm8955->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)  		wm8955->supplies[i].supply = wm8955_supply_names[i]; -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies), +	ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),  				 wm8955->supplies);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -918,7 +909,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)  				    wm8955->supplies);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); -		goto err_get; +		return ret;  	}  	ret = wm8955_reset(codec); @@ -970,17 +961,12 @@ static int wm8955_probe(struct snd_soc_codec *codec)  err_enable:  	regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); -err_get: -	regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);  	return ret;  }  static int wm8955_remove(struct snd_soc_codec *codec)  { -	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); -  	wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); -	regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);  	return 0;  } diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index b0710d817a6..b2ebb104d87 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,  			data32 &= 0xffffff; -			wm8994_bulk_write(codec->control_data, +			wm8994_bulk_write(wm8994->wm8994,  					  data32 & 0xffffff,  					  block_len / 2,  					  (void *)(data + 8)); @@ -348,7 +348,7 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)  		aif = 1;  		break;  	default: -		BUG(); +		WARN(1, "Invalid path %d\n", path);  		return;  	} @@ -456,7 +456,7 @@ static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)  static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	struct wm8994 *control = wm8994->wm8994;  	int value = ucontrol->value.integer.value[0]; @@ -478,7 +478,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,  static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg; @@ -500,7 +500,7 @@ static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int mbc = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc]; @@ -512,7 +512,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int mbc = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0]) @@ -546,7 +546,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,  static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	struct wm8994 *control = wm8994->wm8994;  	int value = ucontrol->value.integer.value[0]; @@ -568,7 +568,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,  static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8994->vss_cfg; @@ -579,7 +579,7 @@ static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,  static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,  				   struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	struct wm8994 *control = wm8994->wm8994;  	int value = ucontrol->value.integer.value[0]; @@ -601,7 +601,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,  static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,  				   struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg; @@ -623,7 +623,7 @@ static int wm8958_vss_get(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int vss = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = wm8994->vss_ena[vss]; @@ -635,7 +635,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int vss = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0]) @@ -684,7 +684,7 @@ static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int hpf = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	if (hpf < 3) @@ -699,7 +699,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int hpf = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	if (hpf < 3) { @@ -746,7 +746,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,  static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,  				  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	struct wm8994 *control = wm8994->wm8994;  	int value = ucontrol->value.integer.value[0]; @@ -768,7 +768,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,  static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,  				  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg; @@ -790,7 +790,7 @@ static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int eq = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq]; @@ -802,7 +802,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  {  	int eq = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0]) @@ -944,7 +944,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		for (i = 0; i < pdata->num_mbc_cfgs; i++)  			wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; -		wm8994->mbc_enum.max = pdata->num_mbc_cfgs; +		wm8994->mbc_enum.items = pdata->num_mbc_cfgs;  		wm8994->mbc_enum.texts = wm8994->mbc_texts;  		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, @@ -973,7 +973,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		for (i = 0; i < pdata->num_vss_cfgs; i++)  			wm8994->vss_texts[i] = pdata->vss_cfgs[i].name; -		wm8994->vss_enum.max = pdata->num_vss_cfgs; +		wm8994->vss_enum.items = pdata->num_vss_cfgs;  		wm8994->vss_enum.texts = wm8994->vss_texts;  		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, @@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)  			wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name; -		wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs; +		wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs;  		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;  		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, @@ -1034,7 +1034,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		for (i = 0; i < pdata->num_enh_eq_cfgs; i++)  			wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name; -		wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs; +		wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs;  		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;  		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f156010e52b..a145d0431b6 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -178,7 +178,7 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)  static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.enumerated.item[0] = wm8960->deemph; @@ -188,7 +188,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,  static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,  			     struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);  	int deemph = ucontrol->value.enumerated.item[0]; @@ -976,12 +976,6 @@ static int wm8960_probe(struct snd_soc_codec *codec)  			wm8960->set_bias_level = wm8960_set_bias_level_capless;  	} -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8960_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset\n"); diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 900328e28a1..9c88f04442b 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -317,15 +317,15 @@ static const char *adc_hpf_text[] = {  	"Hi-fi", "Voice 1", "Voice 2", "Voice 3",  }; -static const struct soc_enum adc_hpf = -	SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_2, 7, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(adc_hpf, +			    WM8961_ADC_DAC_CONTROL_2, 7, adc_hpf_text);  static const char *dac_deemph_text[] = {  	"None", "32kHz", "44.1kHz", "48kHz",  }; -static const struct soc_enum dac_deemph = -	SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_1, 1, 4, dac_deemph_text); +static SOC_ENUM_SINGLE_DECL(dac_deemph, +			    WM8961_ADC_DAC_CONTROL_1, 1, dac_deemph_text);  static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);  static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0); @@ -385,11 +385,11 @@ static const char *sidetone_text[] = {  	"None", "Left", "Right"  }; -static const struct soc_enum dacl_sidetone = -	SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_0, 2, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(dacl_sidetone, +			    WM8961_DSP_SIDETONE_0, 2, sidetone_text); -static const struct soc_enum dacr_sidetone = -	SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_1, 2, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(dacr_sidetone, +			    WM8961_DSP_SIDETONE_1, 2, sidetone_text);  static const struct snd_kcontrol_new dacl_mux =  	SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone); @@ -836,15 +836,8 @@ static struct snd_soc_dai_driver wm8961_dai = {  static int wm8961_probe(struct snd_soc_codec *codec)  {  	struct snd_soc_dapm_context *dapm = &codec->dapm; -	int ret = 0;  	u16 reg; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Enable class W */  	reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);  	reg |= WM8961_CP_DYN_PWR_MASK; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 11d80f3b613..ca2fda9d72b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -74,11 +74,9 @@ struct wm8962_priv {  	struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];  	struct notifier_block disable_nb[WM8962_NUM_SUPPLIES]; -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)  	struct input_dev *beep;  	struct work_struct beep_work;  	int beep_rate; -#endif  #ifdef CONFIG_GPIOLIB  	struct gpio_chip gpio_chip; @@ -154,6 +152,7 @@ static struct reg_default wm8962_reg[] = {  	{ 40, 0x0000 },   /* R40    - SPKOUTL volume */  	{ 41, 0x0000 },   /* R41    - SPKOUTR volume */ +	{ 49, 0x0010 },   /* R49    - Class D Control 1 */  	{ 51, 0x0003 },   /* R51    - Class D Control 2 */  	{ 56, 0x0506 },   /* R56    - Clocking 4 */ @@ -795,7 +794,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg)  	case WM8962_ALC2:  	case WM8962_THERMAL_SHUTDOWN_STATUS:  	case WM8962_ADDITIONAL_CONTROL_4: -	case WM8962_CLASS_D_CONTROL_1:  	case WM8962_DC_SERVO_6:  	case WM8962_INTERRUPT_STATUS_1:  	case WM8962_INTERRUPT_STATUS_2: @@ -1479,7 +1477,9 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);  static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)  { -	return regcache_sync_region(codec->control_data, +	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + +	return regcache_sync_region(wm8962->regmap,  				    WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);  } @@ -1550,7 +1550,7 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  {  	int shift = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);  	ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift); @@ -1562,7 +1562,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  {  	int shift = kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);  	int old = wm8962->dsp2_ena;  	int ret = 0; @@ -1600,7 +1600,7 @@ out:  static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,  			    struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	int ret;  	/* Apply the update (if any) */ @@ -1630,7 +1630,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,  static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,  			    struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	int ret;  	/* Apply the update (if any) */ @@ -1658,16 +1658,16 @@ static const char *cap_hpf_mode_text[] = {  	"Hi-fi", "Application"  }; -static const struct soc_enum cap_hpf_mode = -	SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text); +static SOC_ENUM_SINGLE_DECL(cap_hpf_mode, +			    WM8962_ADC_DAC_CONTROL_2, 10, cap_hpf_mode_text);  static const char *cap_lhpf_mode_text[] = {  	"LPF", "HPF"  }; -static const struct soc_enum cap_lhpf_mode = -	SOC_ENUM_SINGLE(WM8962_LHPF1, 1, 2, cap_lhpf_mode_text); +static SOC_ENUM_SINGLE_DECL(cap_lhpf_mode, +			    WM8962_LHPF1, 1, cap_lhpf_mode_text);  static const struct snd_kcontrol_new wm8962_snd_controls[] = {  SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1), @@ -1758,6 +1758,9 @@ SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,  		 WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv),  SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,  		 WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv), +SND_SOC_BYTES("EQL Coefficients", WM8962_EQ4, 18), +SND_SOC_BYTES("EQR Coefficients", WM8962_EQ24, 18), +  SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),  SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA), @@ -1775,6 +1778,11 @@ WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),  SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1),  WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),  SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30), + +SOC_DOUBLE("ALC Switch", WM8962_ALC1, WM8962_ALCL_ENA_SHIFT, +		WM8962_ALCR_ENA_SHIFT, 1, 0), +SND_SOC_BYTES_MASK("ALC Coefficients", WM8962_ALC1, 4, +		WM8962_ALCL_ENA_MASK | WM8962_ALCR_ENA_MASK),  };  static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = { @@ -1845,7 +1853,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		return -EINVAL;  	} @@ -1937,7 +1945,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		return -EINVAL;  	} @@ -1966,7 +1974,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,  		reg = WM8962_SPKOUTL_VOLUME;  		break;  	default: -		BUG(); +		WARN(1, "Invalid shift %d\n", w->shift);  		return -EINVAL;  	} @@ -1974,7 +1982,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,  	case SND_SOC_DAPM_POST_PMU:  		return snd_soc_write(codec, reg, snd_soc_read(codec, reg));  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		return -EINVAL;  	}  } @@ -1997,7 +2005,7 @@ static int dsp2_event(struct snd_soc_dapm_widget *w,  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		return -EINVAL;  	} @@ -2006,40 +2014,40 @@ static int dsp2_event(struct snd_soc_dapm_widget *w,  static const char *st_text[] = { "None", "Left", "Right" }; -static const struct soc_enum str_enum = -	SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text); +static SOC_ENUM_SINGLE_DECL(str_enum, +			    WM8962_DAC_DSP_MIXING_1, 2, st_text);  static const struct snd_kcontrol_new str_mux =  	SOC_DAPM_ENUM("Right Sidetone", str_enum); -static const struct soc_enum stl_enum = -	SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text); +static SOC_ENUM_SINGLE_DECL(stl_enum, +			    WM8962_DAC_DSP_MIXING_2, 2, st_text);  static const struct snd_kcontrol_new stl_mux =  	SOC_DAPM_ENUM("Left Sidetone", stl_enum);  static const char *outmux_text[] = { "DAC", "Mixer" }; -static const struct soc_enum spkoutr_enum = -	SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text); +static SOC_ENUM_SINGLE_DECL(spkoutr_enum, +			    WM8962_SPEAKER_MIXER_2, 7, outmux_text);  static const struct snd_kcontrol_new spkoutr_mux =  	SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum); -static const struct soc_enum spkoutl_enum = -	SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text); +static SOC_ENUM_SINGLE_DECL(spkoutl_enum, +			    WM8962_SPEAKER_MIXER_1, 7, outmux_text);  static const struct snd_kcontrol_new spkoutl_mux =  	SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum); -static const struct soc_enum hpoutr_enum = -	SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text); +static SOC_ENUM_SINGLE_DECL(hpoutr_enum, +			    WM8962_HEADPHONE_MIXER_2, 7, outmux_text);  static const struct snd_kcontrol_new hpoutr_mux =  	SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum); -static const struct soc_enum hpoutl_enum = -	SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text); +static SOC_ENUM_SINGLE_DECL(hpoutl_enum, +			    WM8962_HEADPHONE_MIXER_1, 7, outmux_text);  static const struct snd_kcontrol_new hpoutl_mux =  	SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum); @@ -2431,7 +2439,20 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)  	snd_soc_update_bits(codec, WM8962_CLOCKING_4,  			    WM8962_SYSCLK_RATE_MASK, clocking4); +	/* DSPCLK_DIV can be only generated correctly after enabling SYSCLK. +	 * So we here provisionally enable it and then disable it afterward +	 * if current bias_level hasn't reached SND_SOC_BIAS_ON. +	 */ +	if (codec->dapm.bias_level != SND_SOC_BIAS_ON) +		snd_soc_update_bits(codec, WM8962_CLOCKING2, +				WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA); +  	dspclk = snd_soc_read(codec, WM8962_CLOCKING1); + +	if (codec->dapm.bias_level != SND_SOC_BIAS_ON) +		snd_soc_update_bits(codec, WM8962_CLOCKING2, +				WM8962_SYSCLK_ENA_MASK, 0); +  	if (dspclk < 0) {  		dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);  		return; @@ -2863,9 +2884,13 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,  	snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);  	snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n); -	try_wait_for_completion(&wm8962->fll_lock); +	reinit_completion(&wm8962->fll_lock); -	pm_runtime_get_sync(codec->dev); +	ret = pm_runtime_get_sync(codec->dev); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to resume device: %d\n", ret); +		return ret; +	}  	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,  			    WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK | @@ -2873,8 +2898,6 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,  	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); -	ret = 0; -  	/* This should be a massive overestimate but go even  	 * higher if we'll error out  	 */ @@ -2888,26 +2911,38 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,  	if (timeout == 0 && wm8962->irq) {  		dev_err(codec->dev, "FLL lock timed out"); -		ret = -ETIMEDOUT; +		snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, +				    WM8962_FLL_ENA, 0); +		pm_runtime_put(codec->dev); +		return -ETIMEDOUT;  	}  	wm8962->fll_fref = Fref;  	wm8962->fll_fout = Fout;  	wm8962->fll_src = source; -	return ret; +	return 0;  }  static int wm8962_mute(struct snd_soc_dai *dai, int mute)  {  	struct snd_soc_codec *codec = dai->codec; -	int val; +	int val, ret;  	if (mute) -		val = WM8962_DAC_MUTE; +		val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT;  	else  		val = 0; +	/** +	 * The DAC mute bit is mirrored in two registers, update both to keep +	 * the register cache consistent. +	 */ +	ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1, +				  WM8962_DAC_MUTE_ALT, val); +	if (ret < 0) +		return ret; +  	return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,  				   WM8962_DAC_MUTE, val);  } @@ -2982,9 +3017,16 @@ static irqreturn_t wm8962_irq(int irq, void *data)  	unsigned int active;  	int reg, ret; +	ret = pm_runtime_get_sync(dev); +	if (ret < 0) { +		dev_err(dev, "Failed to resume: %d\n", ret); +		return IRQ_NONE; +	} +  	ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK,  			  &mask);  	if (ret != 0) { +		pm_runtime_put(dev);  		dev_err(dev, "Failed to read interrupt mask: %d\n",  			ret);  		return IRQ_NONE; @@ -2992,14 +3034,17 @@ static irqreturn_t wm8962_irq(int irq, void *data)  	ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active);  	if (ret != 0) { +		pm_runtime_put(dev);  		dev_err(dev, "Failed to read interrupt: %d\n", ret);  		return IRQ_NONE;  	}  	active &= ~mask; -	if (!active) +	if (!active) { +		pm_runtime_put(dev);  		return IRQ_NONE; +	}  	/* Acknowledge the interrupts */  	ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active); @@ -3049,6 +3094,8 @@ static irqreturn_t wm8962_irq(int irq, void *data)  				   msecs_to_jiffies(250));  	} +	pm_runtime_put(dev); +  	return IRQ_HANDLED;  } @@ -3068,6 +3115,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)  int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)  {  	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = &codec->dapm;  	int irq_mask, enable;  	wm8962->jack = jack; @@ -3088,19 +3136,22 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)  	snd_soc_jack_report(wm8962->jack, 0,  			    SND_JACK_MICROPHONE | SND_JACK_BTN_0); +	snd_soc_dapm_mutex_lock(dapm); +  	if (jack) { -		snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); -		snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS"); +		snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); +		snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");  	} else { -		snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK"); -		snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS"); +		snd_soc_dapm_disable_pin_unlocked(dapm, "SYSCLK"); +		snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");  	} +	snd_soc_dapm_mutex_unlock(dapm); +  	return 0;  }  EXPORT_SYMBOL_GPL(wm8962_mic_detect); -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)  static int beep_rates[] = {  	500, 1000, 2000, 4000,  }; @@ -3232,17 +3283,8 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)  	snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);  } -#else -static void wm8962_init_beep(struct snd_soc_codec *codec) -{ -} -static void wm8962_free_beep(struct snd_soc_codec *codec) -{ -} -#endif - -static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio) +static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)  {  	int mask = 0;  	int val = 0; @@ -3263,8 +3305,8 @@ static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)  	}  	if (mask) -		snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1, -				    mask, val); +		regmap_update_bits(wm8962->regmap, WM8962_ANALOGUE_CLOCKING1, +				   mask, val);  }  #ifdef CONFIG_GPIOLIB @@ -3276,7 +3318,6 @@ static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)  static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)  {  	struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); -	struct snd_soc_codec *codec = wm8962->codec;  	/* The WM8962 GPIOs aren't linearly numbered.  For simplicity  	 * we export linear numbers and error out if the unsupported @@ -3292,7 +3333,7 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)  		return -EINVAL;  	} -	wm8962_set_gpio_mode(codec, offset + 1); +	wm8962_set_gpio_mode(wm8962, offset + 1);  	return 0;  } @@ -3376,18 +3417,10 @@ static int wm8962_probe(struct snd_soc_codec *codec)  {  	int ret;  	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); -	struct wm8962_pdata *pdata = &wm8962->pdata; -	int i, trigger, irq_pol; +	int i;  	bool dmicclk, dmicdat;  	wm8962->codec = codec; -	codec->control_data = wm8962->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;  	wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1; @@ -3409,75 +3442,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)  		}  	} -	/* SYSCLK defaults to on; make sure it is off so we can safely -	 * write to registers if the device is declocked. -	 */ -	snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0); - -	/* Ensure we have soft control over all registers */ -	snd_soc_update_bits(codec, WM8962_CLOCKING2, -			    WM8962_CLKREG_OVD, WM8962_CLKREG_OVD); - -	/* Ensure that the oscillator and PLLs are disabled */ -	snd_soc_update_bits(codec, WM8962_PLL2, -			    WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, -			    0); - -	/* Apply static configuration for GPIOs */ -	for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) -		if (pdata->gpio_init[i]) { -			wm8962_set_gpio_mode(codec, i + 1); -			snd_soc_write(codec, 0x200 + i, -					pdata->gpio_init[i] & 0xffff); -		} - - -	/* Put the speakers into mono mode? */ -	if (pdata->spk_mono) -		snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_2, -				WM8962_SPK_MONO_MASK, WM8962_SPK_MONO); - -	/* Micbias setup, detection enable and detection -	 * threasholds. */ -	if (pdata->mic_cfg) -		snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4, -				    WM8962_MICDET_ENA | -				    WM8962_MICDET_THR_MASK | -				    WM8962_MICSHORT_THR_MASK | -				    WM8962_MICBIAS_LVL, -				    pdata->mic_cfg); - -	/* Latch volume update bits */ -	snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME, -			    WM8962_IN_VU, WM8962_IN_VU); -	snd_soc_update_bits(codec, WM8962_RIGHT_INPUT_VOLUME, -			    WM8962_IN_VU, WM8962_IN_VU); -	snd_soc_update_bits(codec, WM8962_LEFT_ADC_VOLUME, -			    WM8962_ADC_VU, WM8962_ADC_VU); -	snd_soc_update_bits(codec, WM8962_RIGHT_ADC_VOLUME, -			    WM8962_ADC_VU, WM8962_ADC_VU); -	snd_soc_update_bits(codec, WM8962_LEFT_DAC_VOLUME, -			    WM8962_DAC_VU, WM8962_DAC_VU); -	snd_soc_update_bits(codec, WM8962_RIGHT_DAC_VOLUME, -			    WM8962_DAC_VU, WM8962_DAC_VU); -	snd_soc_update_bits(codec, WM8962_SPKOUTL_VOLUME, -			    WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); -	snd_soc_update_bits(codec, WM8962_SPKOUTR_VOLUME, -			    WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); -	snd_soc_update_bits(codec, WM8962_HPOUTL_VOLUME, -			    WM8962_HPOUT_VU, WM8962_HPOUT_VU); -	snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME, -			    WM8962_HPOUT_VU, WM8962_HPOUT_VU); - -	/* Stereo control for EQ */ -	snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0); - -	/* Don't debouce interrupts so we don't need SYSCLK */ -	snd_soc_update_bits(codec, WM8962_IRQ_DEBOUNCE, -			    WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB | -			    WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB, -			    0); -  	wm8962_add_widgets(codec);  	/* Save boards having to disable DMIC when not in use */ @@ -3506,36 +3470,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)  	wm8962_init_beep(codec);  	wm8962_init_gpio(codec); -	if (wm8962->irq) { -		if (pdata->irq_active_low) { -			trigger = IRQF_TRIGGER_LOW; -			irq_pol = WM8962_IRQ_POL; -		} else { -			trigger = IRQF_TRIGGER_HIGH; -			irq_pol = 0; -		} - -		snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL, -				    WM8962_IRQ_POL, irq_pol); - -		ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq, -					   trigger | IRQF_ONESHOT, -					   "wm8962", codec->dev); -		if (ret != 0) { -			dev_err(codec->dev, "Failed to request IRQ %d: %d\n", -				wm8962->irq, ret); -			wm8962->irq = 0; -			/* Non-fatal */ -		} else { -			/* Enable some IRQs by default */ -			snd_soc_update_bits(codec, -					    WM8962_INTERRUPT_STATUS_2_MASK, -					    WM8962_FLL_LOCK_EINT | -					    WM8962_TEMP_SHUT_EINT | -					    WM8962_FIFOS_ERR_EINT, 0); -		} -	} -  	return 0;  } @@ -3544,9 +3478,6 @@ static int wm8962_remove(struct snd_soc_codec *codec)  	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);  	int i; -	if (wm8962->irq) -		free_irq(wm8962->irq, codec); -  	cancel_delayed_work_sync(&wm8962->mic_work);  	wm8962_free_gpio(codec); @@ -3619,7 +3550,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,  	struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev);  	struct wm8962_priv *wm8962;  	unsigned int reg; -	int ret, i; +	int ret, i, irq_pol, trigger;  	wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv),  			      GFP_KERNEL); @@ -3704,6 +3635,77 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,  		goto err_enable;  	} +	/* SYSCLK defaults to on; make sure it is off so we can safely +	 * write to registers if the device is declocked. +	 */ +	regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, +			   WM8962_SYSCLK_ENA, 0); + +	/* Ensure we have soft control over all registers */ +	regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, +			   WM8962_CLKREG_OVD, WM8962_CLKREG_OVD); + +	/* Ensure that the oscillator and PLLs are disabled */ +	regmap_update_bits(wm8962->regmap, WM8962_PLL2, +			   WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, +			   0); + +	/* Apply static configuration for GPIOs */ +	for (i = 0; i < ARRAY_SIZE(wm8962->pdata.gpio_init); i++) +		if (wm8962->pdata.gpio_init[i]) { +			wm8962_set_gpio_mode(wm8962, i + 1); +			regmap_write(wm8962->regmap, 0x200 + i, +				     wm8962->pdata.gpio_init[i] & 0xffff); +		} + + +	/* Put the speakers into mono mode? */ +	if (wm8962->pdata.spk_mono) +		regmap_update_bits(wm8962->regmap, WM8962_CLASS_D_CONTROL_2, +				   WM8962_SPK_MONO_MASK, WM8962_SPK_MONO); + +	/* Micbias setup, detection enable and detection +	 * threasholds. */ +	if (wm8962->pdata.mic_cfg) +		regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4, +				   WM8962_MICDET_ENA | +				   WM8962_MICDET_THR_MASK | +				   WM8962_MICSHORT_THR_MASK | +				   WM8962_MICBIAS_LVL, +				   wm8962->pdata.mic_cfg); + +	/* Latch volume update bits */ +	regmap_update_bits(wm8962->regmap, WM8962_LEFT_INPUT_VOLUME, +			   WM8962_IN_VU, WM8962_IN_VU); +	regmap_update_bits(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME, +			   WM8962_IN_VU, WM8962_IN_VU); +	regmap_update_bits(wm8962->regmap, WM8962_LEFT_ADC_VOLUME, +			   WM8962_ADC_VU, WM8962_ADC_VU); +	regmap_update_bits(wm8962->regmap, WM8962_RIGHT_ADC_VOLUME, +			   WM8962_ADC_VU, WM8962_ADC_VU); +	regmap_update_bits(wm8962->regmap, WM8962_LEFT_DAC_VOLUME, +			   WM8962_DAC_VU, WM8962_DAC_VU); +	regmap_update_bits(wm8962->regmap, WM8962_RIGHT_DAC_VOLUME, +			   WM8962_DAC_VU, WM8962_DAC_VU); +	regmap_update_bits(wm8962->regmap, WM8962_SPKOUTL_VOLUME, +			   WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); +	regmap_update_bits(wm8962->regmap, WM8962_SPKOUTR_VOLUME, +			   WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); +	regmap_update_bits(wm8962->regmap, WM8962_HPOUTL_VOLUME, +			   WM8962_HPOUT_VU, WM8962_HPOUT_VU); +	regmap_update_bits(wm8962->regmap, WM8962_HPOUTR_VOLUME, +			   WM8962_HPOUT_VU, WM8962_HPOUT_VU); + +	/* Stereo control for EQ */ +	regmap_update_bits(wm8962->regmap, WM8962_EQ1, +			   WM8962_EQ_SHARED_COEFF, 0); + +	/* Don't debouce interrupts so we don't need SYSCLK */ +	regmap_update_bits(wm8962->regmap, WM8962_IRQ_DEBOUNCE, +			   WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB | +			   WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB, +			   0); +  	if (wm8962->pdata.in4_dc_measure) {  		ret = regmap_register_patch(wm8962->regmap,  					    wm8962_dc_measure, @@ -3714,6 +3716,37 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,  				ret);  	} +	if (wm8962->irq) { +		if (wm8962->pdata.irq_active_low) { +			trigger = IRQF_TRIGGER_LOW; +			irq_pol = WM8962_IRQ_POL; +		} else { +			trigger = IRQF_TRIGGER_HIGH; +			irq_pol = 0; +		} + +		regmap_update_bits(wm8962->regmap, WM8962_INTERRUPT_CONTROL, +				   WM8962_IRQ_POL, irq_pol); + +		ret = devm_request_threaded_irq(&i2c->dev, wm8962->irq, NULL, +						wm8962_irq, +						trigger | IRQF_ONESHOT, +						"wm8962", &i2c->dev); +		if (ret != 0) { +			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", +				wm8962->irq, ret); +			wm8962->irq = 0; +			/* Non-fatal */ +		} else { +			/* Enable some IRQs by default */ +			regmap_update_bits(wm8962->regmap, +					   WM8962_INTERRUPT_STATUS_2_MASK, +					   WM8962_FLL_LOCK_EINT | +					   WM8962_TEMP_SHUT_EINT | +					   WM8962_FIFOS_ERR_EINT, 0); +		} +	} +  	pm_runtime_enable(&i2c->dev);  	pm_request_idle(&i2c->dev); @@ -3722,6 +3755,8 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,  	if (ret < 0)  		goto err_enable; +	regcache_cache_only(wm8962->regmap, true); +  	/* The drivers should power up as needed */  	regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h index a1a5d5294c1..910aafd09d2 100644 --- a/sound/soc/codecs/wm8962.h +++ b/sound/soc/codecs/wm8962.h @@ -1954,6 +1954,10 @@  #define WM8962_SPKOUTL_ENA_MASK                 0x0040  /* SPKOUTL_ENA */  #define WM8962_SPKOUTL_ENA_SHIFT                     6  /* SPKOUTL_ENA */  #define WM8962_SPKOUTL_ENA_WIDTH                     1  /* SPKOUTL_ENA */ +#define WM8962_DAC_MUTE_ALT                     0x0010  /* DAC_MUTE */ +#define WM8962_DAC_MUTE_ALT_MASK                0x0010  /* DAC_MUTE */ +#define WM8962_DAC_MUTE_ALT_SHIFT                    4  /* DAC_MUTE */ +#define WM8962_DAC_MUTE_ALT_WIDTH                    1  /* DAC_MUTE */  #define WM8962_SPKOUTL_PGA_MUTE                 0x0002  /* SPKOUTL_PGA_MUTE */  #define WM8962_SPKOUTL_PGA_MUTE_MASK            0x0002  /* SPKOUTL_PGA_MUTE */  #define WM8962_SPKOUTL_PGA_MUTE_SHIFT                1  /* SPKOUTL_PGA_MUTE */ diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 67aba78a7ca..09b7b420022 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -648,12 +648,6 @@ static int wm8971_probe(struct snd_soc_codec *codec)  	int ret = 0;  	u16 reg; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work);  	wm8971_workq = create_workqueue("wm8971");  	if (wm8971_workq == NULL) diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index a2d01d10a5d..0627c56fa44 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -17,6 +17,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -27,22 +28,22 @@  #include "wm8974.h" -static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { -	0x0000, 0x0000, 0x0000, 0x0000, -	0x0050, 0x0000, 0x0140, 0x0000, -	0x0000, 0x0000, 0x0000, 0x00ff, -	0x0000, 0x0000, 0x0100, 0x00ff, -	0x0000, 0x0000, 0x012c, 0x002c, -	0x002c, 0x002c, 0x002c, 0x0000, -	0x0032, 0x0000, 0x0000, 0x0000, -	0x0000, 0x0000, 0x0000, 0x0000, -	0x0038, 0x000b, 0x0032, 0x0000, -	0x0008, 0x000c, 0x0093, 0x00e9, -	0x0000, 0x0000, 0x0000, 0x0000, -	0x0003, 0x0010, 0x0000, 0x0000, -	0x0000, 0x0002, 0x0000, 0x0000, -	0x0000, 0x0000, 0x0039, 0x0000, -	0x0000, +static const struct reg_default wm8974_reg_defaults[] = { +	{  0, 0x0000 }, {  1, 0x0000 }, {  2, 0x0000 }, {  3, 0x0000 }, +	{  4, 0x0050 }, {  5, 0x0000 }, {  6, 0x0140 }, {  7, 0x0000 }, +	{  8, 0x0000 }, {  9, 0x0000 }, { 10, 0x0000 }, { 11, 0x00ff }, +	{ 12, 0x0000 }, { 13, 0x0000 }, { 14, 0x0100 }, { 15, 0x00ff }, +	{ 16, 0x0000 }, { 17, 0x0000 }, { 18, 0x012c }, { 19, 0x002c }, +	{ 20, 0x002c }, { 21, 0x002c }, { 22, 0x002c }, { 23, 0x0000 }, +	{ 24, 0x0032 }, { 25, 0x0000 }, { 26, 0x0000 }, { 27, 0x0000 }, +	{ 28, 0x0000 }, { 29, 0x0000 }, { 30, 0x0000 }, { 31, 0x0000 }, +	{ 32, 0x0038 }, { 33, 0x000b }, { 34, 0x0032 }, { 35, 0x0000 }, +	{ 36, 0x0008 }, { 37, 0x000c }, { 38, 0x0093 }, { 39, 0x00e9 }, +	{ 40, 0x0000 }, { 41, 0x0000 }, { 42, 0x0000 }, { 43, 0x0000 }, +	{ 44, 0x0003 }, { 45, 0x0010 }, { 46, 0x0000 }, { 47, 0x0000 }, +	{ 48, 0x0000 }, { 49, 0x0002 }, { 50, 0x0000 }, { 51, 0x0000 }, +	{ 52, 0x0000 }, { 53, 0x0000 }, { 54, 0x0039 }, { 55, 0x0000 }, +	{ 56, 0x0000 },  };  #define WM8974_POWER1_BIASEN  0x08 @@ -83,8 +84,8 @@ static const struct soc_enum wm8974_enum[] = {  static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" }; -static const struct soc_enum wm8974_auxmode = -	SOC_ENUM_SINGLE(WM8974_INPUT,  3, 2, wm8974_auxmode_text); +static SOC_ENUM_SINGLE_DECL(wm8974_auxmode, +			    WM8974_INPUT,  3, wm8974_auxmode_text);  static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);  static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); @@ -514,7 +515,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,  		power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			snd_soc_cache_sync(codec); +			regcache_sync(dev_get_regmap(codec->dev, NULL));  			/* Initial cap charge at VMID 5k */  			snd_soc_write(codec, WM8974_POWER1, power1 | 0x3); @@ -579,16 +580,19 @@ static int wm8974_resume(struct snd_soc_codec *codec)  	return 0;  } +static const struct regmap_config wm8974_regmap = { +	.reg_bits = 7, +	.val_bits = 9, + +	.max_register = WM8974_MONOMIX, +	.reg_defaults = wm8974_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults), +}; +  static int wm8974_probe(struct snd_soc_codec *codec)  {  	int ret = 0; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8974_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset\n"); @@ -613,9 +617,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {  	.suspend = 	wm8974_suspend,  	.resume =	wm8974_resume,  	.set_bias_level = wm8974_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8974_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8974_reg,  	.controls = wm8974_snd_controls,  	.num_controls = ARRAY_SIZE(wm8974_snd_controls), @@ -628,8 +629,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {  static int wm8974_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { +	struct regmap *regmap;  	int ret; +	regmap = devm_regmap_init_i2c(i2c, &wm8974_regmap); +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); +  	ret = snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8974, &wm8974_dai, 1); diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index d8fc531c0e5..28ef46c91f6 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -117,21 +117,21 @@ static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"};  static const char *wm8978_alc3[] = {"ALC", "Limiter"};  static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; -static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, -				  wm8978_companding); -static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, -				  wm8978_companding); -static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); -static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); -static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); -static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); -static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); -static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); -static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); -static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); -static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); -static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); -static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); +static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, +			    wm8978_companding); +static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, +			    wm8978_companding); +static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); +static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); +static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); +static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); +static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); +static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); +static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); +static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); +static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); +static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); +static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);  static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);  static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); @@ -975,19 +975,13 @@ static const int update_reg[] = {  static int wm8978_probe(struct snd_soc_codec *codec)  {  	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); -	int ret = 0, i; +	int i;  	/*  	 * Set default system clock to PLL, it is more precise, this is also the  	 * default hardware setting  	 */  	wm8978->sysclk = WM8978_PLL; -	codec->control_data = wm8978->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	/*  	 * Set the update bit in all registers, that have one. This way all diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index aa41ba0dfff..19d5baa38f5 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -205,49 +205,44 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);  static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);  static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; -static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, -				  alc_sel_text); +static SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, alc_sel_text);  static const char *alc_mode_text[] = { "ALC", "Limiter" }; -static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, -				  alc_mode_text); +static SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, alc_mode_text);  static const char *filter_mode_text[] = { "Audio", "Application" }; -static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, -				  filter_mode_text); +static SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, +			    filter_mode_text);  static const char *eq_bw_text[] = { "Narrow", "Wide" };  static const char *eqmode_text[] = { "Capture", "Playback" }; -static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); +static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);  static const char *eq1_cutoff_text[] = {  	"80Hz", "105Hz", "135Hz", "175Hz"  }; -static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, -				  eq1_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, +			    eq1_cutoff_text);  static const char *eq2_cutoff_text[] = {  	"230Hz", "300Hz", "385Hz", "500Hz"  }; -static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, -				  eq2_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, eq2_cutoff_text);  static const char *eq3_cutoff_text[] = {  	"650Hz", "850Hz", "1.1kHz", "1.4kHz"  }; -static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, -				  eq3_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, eq3_cutoff_text);  static const char *eq4_cutoff_text[] = {  	"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"  }; -static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, -				  eq4_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, eq4_cutoff_text);  static const char *eq5_cutoff_text[] = {  	"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"  }; -static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, -				  eq5_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, +			    eq5_cutoff_text);  static const char *depth_3d_text[] = {  	"Off", @@ -267,8 +262,8 @@ static const char *depth_3d_text[] = {  	"93.3%",  	"100%"  }; -static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, -				  depth_3d_text); +static SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, +			    depth_3d_text);  static const struct snd_kcontrol_new wm8983_snd_controls[] = {  	SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, @@ -557,7 +552,7 @@ static const struct snd_soc_dapm_route wm8983_audio_map[] = {  static int eqmode_get(struct snd_kcontrol *kcontrol,  		      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg;  	reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF); @@ -572,7 +567,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,  static int eqmode_put(struct snd_kcontrol *kcontrol,  		      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int regpwr2, regpwr3;  	unsigned int reg_eq; @@ -1000,12 +995,6 @@ static int wm8983_probe(struct snd_soc_codec *codec)  	int ret;  	int i; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); -		return ret; -	} -  	ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset: %d\n", ret); @@ -1129,7 +1118,7 @@ static struct spi_driver wm8983_spi_driver = {  };  #endif -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8983_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -1182,7 +1171,7 @@ static int __init wm8983_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8983_i2c_driver);  	if (ret) {  		printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n", @@ -1202,7 +1191,7 @@ module_init(wm8983_modinit);  static void __exit wm8983_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8983_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 18f2babe109..0f5780c09f3 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -226,52 +226,48 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);  static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);  static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; -static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, -				  alc_sel_text); +static SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, alc_sel_text);  static const char *alc_mode_text[] = { "ALC", "Limiter" }; -static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, -				  alc_mode_text); +static SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, alc_mode_text);  static const char *filter_mode_text[] = { "Audio", "Application" }; -static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, -				  filter_mode_text); +static SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, +			    filter_mode_text);  static const char *eq_bw_text[] = { "Narrow", "Wide" };  static const char *eqmode_text[] = { "Capture", "Playback" }; -static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); +static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);  static const char *eq1_cutoff_text[] = {  	"80Hz", "105Hz", "135Hz", "175Hz"  }; -static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, -				  eq1_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, +			    eq1_cutoff_text);  static const char *eq2_cutoff_text[] = {  	"230Hz", "300Hz", "385Hz", "500Hz"  }; -static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, -				  eq2_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, eq2_cutoff_text);  static const char *eq3_cutoff_text[] = {  	"650Hz", "850Hz", "1.1kHz", "1.4kHz"  }; -static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, -				  eq3_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, +			    eq3_cutoff_text);  static const char *eq4_cutoff_text[] = {  	"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"  }; -static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, -				  eq4_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, eq4_cutoff_text);  static const char *eq5_cutoff_text[] = {  	"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"  }; -static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5, +static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,  				  eq5_cutoff_text);  static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; -static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); +static SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);  static const char *depth_3d_text[] = {  	"Off", @@ -291,8 +287,7 @@ static const char *depth_3d_text[] = {  	"93.3%",  	"100%"  }; -static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, -				  depth_3d_text); +static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text);  static const struct snd_kcontrol_new wm8985_snd_controls[] = {  	SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, @@ -531,7 +526,7 @@ static const struct snd_soc_dapm_route wm8985_dapm_routes[] = {  static int eqmode_get(struct snd_kcontrol *kcontrol,  		      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg;  	reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF); @@ -546,7 +541,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,  static int eqmode_put(struct snd_kcontrol *kcontrol,  		      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int regpwr2, regpwr3;  	unsigned int reg_eq; @@ -989,7 +984,6 @@ static int wm8985_remove(struct snd_soc_codec *codec)  	wm8985 = snd_soc_codec_get_drvdata(codec);  	wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); -	regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);  	return 0;  } @@ -1000,18 +994,11 @@ static int wm8985_probe(struct snd_soc_codec *codec)  	int ret;  	wm8985 = snd_soc_codec_get_drvdata(codec); -	codec->control_data = wm8985->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); -		return ret; -	}  	for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)  		wm8985->supplies[i].supply = wm8985_supply_names[i]; -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies), +	ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),  				 wm8985->supplies);  	if (ret) {  		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -1022,7 +1009,7 @@ static int wm8985_probe(struct snd_soc_codec *codec)  				    wm8985->supplies);  	if (ret) {  		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); -		goto err_reg_get; +		return ret;  	}  	ret = wm8985_reset(codec); @@ -1044,8 +1031,6 @@ static int wm8985_probe(struct snd_soc_codec *codec)  err_reg_enable:  	regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies); -err_reg_get: -	regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);  	return ret;  } @@ -1148,7 +1133,7 @@ static struct spi_driver wm8985_spi_driver = {  };  #endif -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8985_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -1201,7 +1186,7 @@ static int __init wm8985_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8985_i2c_driver);  	if (ret) {  		printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n", @@ -1221,7 +1206,7 @@ module_init(wm8985_modinit);  static void __exit wm8985_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8985_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 39b9acceb59..d3fea46d58e 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -116,7 +116,7 @@ static bool wm8988_writeable(struct device *dev, unsigned int reg)  struct wm8988_priv {  	struct regmap *regmap;  	unsigned int sysclk; -	struct snd_pcm_hw_constraint_list *sysclk_constraints; +	const struct snd_pcm_hw_constraint_list *sysclk_constraints;  };  #define wm8988_reset(c)	snd_soc_write(c, WM8988_RESET, 0) @@ -126,46 +126,46 @@ struct wm8988_priv {   */  static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"}; -static const struct soc_enum bass_boost = -	SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt); +static SOC_ENUM_SINGLE_DECL(bass_boost, +			    WM8988_BASS, 7, bass_boost_txt);  static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; -static const struct soc_enum bass_filter = -	SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt); +static SOC_ENUM_SINGLE_DECL(bass_filter, +			    WM8988_BASS, 6, bass_filter_txt);  static const char *treble_txt[] = {"8kHz", "4kHz"}; -static const struct soc_enum treble = -	SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt); +static SOC_ENUM_SINGLE_DECL(treble, +			    WM8988_TREBLE, 6, treble_txt);  static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"}; -static const struct soc_enum stereo_3d_lc = -	SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt); +static SOC_ENUM_SINGLE_DECL(stereo_3d_lc, +			    WM8988_3D, 5, stereo_3d_lc_txt);  static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"}; -static const struct soc_enum stereo_3d_uc = -	SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt); +static SOC_ENUM_SINGLE_DECL(stereo_3d_uc, +			    WM8988_3D, 6, stereo_3d_uc_txt);  static const char *stereo_3d_func_txt[] = {"Capture", "Playback"}; -static const struct soc_enum stereo_3d_func = -	SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt); +static SOC_ENUM_SINGLE_DECL(stereo_3d_func, +			    WM8988_3D, 7, stereo_3d_func_txt);  static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"}; -static const struct soc_enum alc_func = -	SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt); +static SOC_ENUM_SINGLE_DECL(alc_func, +			    WM8988_ALC1, 7, alc_func_txt);  static const char *ng_type_txt[] = {"Constant PGA Gain",  				    "Mute ADC Output"}; -static const struct soc_enum ng_type = -	SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt); +static SOC_ENUM_SINGLE_DECL(ng_type, +			    WM8988_NGATE, 1, ng_type_txt);  static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const struct soc_enum deemph = -	SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt); +static SOC_ENUM_SINGLE_DECL(deemph, +			    WM8988_ADCDAC, 1, deemph_txt);  static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",  				   "L + R Invert"}; -static const struct soc_enum adcpol = -	SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt); +static SOC_ENUM_SINGLE_DECL(adcpol, +			    WM8988_ADCDAC, 5, adcpol_txt);  static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);  static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); @@ -268,7 +268,7 @@ static const struct soc_enum wm8988_lline_enum =  			      wm8988_line_texts,  			      wm8988_line_values);  static const struct snd_kcontrol_new wm8988_left_line_controls = -	SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); +	SOC_DAPM_ENUM("Route", wm8988_lline_enum);  static const struct soc_enum wm8988_rline_enum =  	SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7, @@ -276,7 +276,7 @@ static const struct soc_enum wm8988_rline_enum =  			      wm8988_line_texts,  			      wm8988_line_values);  static const struct snd_kcontrol_new wm8988_right_line_controls = -	SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); +	SOC_DAPM_ENUM("Route", wm8988_lline_enum);  /* Left Mixer */  static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = { @@ -304,7 +304,7 @@ static const struct soc_enum wm8988_lpga_enum =  			      wm8988_pga_sel,  			      wm8988_pga_val);  static const struct snd_kcontrol_new wm8988_left_pga_controls = -	SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum); +	SOC_DAPM_ENUM("Route", wm8988_lpga_enum);  /* Right PGA Mux */  static const struct soc_enum wm8988_rpga_enum = @@ -313,20 +313,20 @@ static const struct soc_enum wm8988_rpga_enum =  			      wm8988_pga_sel,  			      wm8988_pga_val);  static const struct snd_kcontrol_new wm8988_right_pga_controls = -	SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum); +	SOC_DAPM_ENUM("Route", wm8988_rpga_enum);  /* Differential Mux */  static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"}; -static const struct soc_enum diffmux = -	SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel); +static SOC_ENUM_SINGLE_DECL(diffmux, +			    WM8988_ADCIN, 8, wm8988_diff_sel);  static const struct snd_kcontrol_new wm8988_diffmux_controls =  	SOC_DAPM_ENUM("Route", diffmux);  /* Mono ADC Mux */  static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)",  	"Mono (Right)", "Digital Mono"}; -static const struct soc_enum monomux = -	SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux); +static SOC_ENUM_SINGLE_DECL(monomux, +			    WM8988_ADCIN, 6, wm8988_mono_mux);  static const struct snd_kcontrol_new wm8988_monomux_controls =  	SOC_DAPM_ENUM("Route", monomux); @@ -521,30 +521,30 @@ static inline int get_coeff(int mclk, int rate)  /* The set of rates we can generate from the above for each SYSCLK */ -static unsigned int rates_12288[] = { +static const unsigned int rates_12288[] = {  	8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,  }; -static struct snd_pcm_hw_constraint_list constraints_12288 = { +static const struct snd_pcm_hw_constraint_list constraints_12288 = {  	.count	= ARRAY_SIZE(rates_12288),  	.list	= rates_12288,  }; -static unsigned int rates_112896[] = { +static const unsigned int rates_112896[] = {  	8000, 11025, 22050, 44100,  }; -static struct snd_pcm_hw_constraint_list constraints_112896 = { +static const struct snd_pcm_hw_constraint_list constraints_112896 = {  	.count	= ARRAY_SIZE(rates_112896),  	.list	= rates_112896,  }; -static unsigned int rates_12[] = { +static const unsigned int rates_12[] = {  	8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,  	48000, 88235, 96000,  }; -static struct snd_pcm_hw_constraint_list constraints_12 = { +static const struct snd_pcm_hw_constraint_list constraints_12 = {  	.count	= ARRAY_SIZE(rates_12),  	.list	= rates_12,  }; @@ -810,16 +810,8 @@ static int wm8988_resume(struct snd_soc_codec *codec)  static int wm8988_probe(struct snd_soc_codec *codec)  { -	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);  	int ret = 0; -	codec->control_data = wm8988->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	ret = wm8988_reset(codec);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset\n"); @@ -912,7 +904,7 @@ static struct spi_driver wm8988_spi_driver = {  };  #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8988_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -964,7 +956,7 @@ static struct i2c_driver wm8988_i2c_driver = {  static int __init wm8988_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8988_i2c_driver);  	if (ret != 0) {  		printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n", @@ -984,7 +976,7 @@ module_init(wm8988_modinit);  static void __exit wm8988_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8988_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 253c88bb7a4..b5c1f0f0705 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -17,6 +17,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -30,13 +31,12 @@  /* codec private data */  struct wm8990_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	unsigned int sysclk;  	unsigned int pcmclk;  }; -static int wm8990_volatile_register(struct snd_soc_codec *codec, -				    unsigned int reg) +static bool wm8990_volatile_register(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case WM8990_RESET: @@ -46,71 +46,69 @@ static int wm8990_volatile_register(struct snd_soc_codec *codec,  	}  } -static const u16 wm8990_reg[] = { -	0x8990,     /* R0  - Reset */ -	0x0000,     /* R1  - Power Management (1) */ -	0x6000,     /* R2  - Power Management (2) */ -	0x0000,     /* R3  - Power Management (3) */ -	0x4050,     /* R4  - Audio Interface (1) */ -	0x4000,     /* R5  - Audio Interface (2) */ -	0x01C8,     /* R6  - Clocking (1) */ -	0x0000,     /* R7  - Clocking (2) */ -	0x0040,     /* R8  - Audio Interface (3) */ -	0x0040,     /* R9  - Audio Interface (4) */ -	0x0004,     /* R10 - DAC CTRL */ -	0x00C0,     /* R11 - Left DAC Digital Volume */ -	0x00C0,     /* R12 - Right DAC Digital Volume */ -	0x0000,     /* R13 - Digital Side Tone */ -	0x0100,     /* R14 - ADC CTRL */ -	0x00C0,     /* R15 - Left ADC Digital Volume */ -	0x00C0,     /* R16 - Right ADC Digital Volume */ -	0x0000,     /* R17 */ -	0x0000,     /* R18 - GPIO CTRL 1 */ -	0x1000,     /* R19 - GPIO1 & GPIO2 */ -	0x1010,     /* R20 - GPIO3 & GPIO4 */ -	0x1010,     /* R21 - GPIO5 & GPIO6 */ -	0x8000,     /* R22 - GPIOCTRL 2 */ -	0x0800,     /* R23 - GPIO_POL */ -	0x008B,     /* R24 - Left Line Input 1&2 Volume */ -	0x008B,     /* R25 - Left Line Input 3&4 Volume */ -	0x008B,     /* R26 - Right Line Input 1&2 Volume */ -	0x008B,     /* R27 - Right Line Input 3&4 Volume */ -	0x0000,     /* R28 - Left Output Volume */ -	0x0000,     /* R29 - Right Output Volume */ -	0x0066,     /* R30 - Line Outputs Volume */ -	0x0022,     /* R31 - Out3/4 Volume */ -	0x0079,     /* R32 - Left OPGA Volume */ -	0x0079,     /* R33 - Right OPGA Volume */ -	0x0003,     /* R34 - Speaker Volume */ -	0x0003,     /* R35 - ClassD1 */ -	0x0000,     /* R36 */ -	0x0100,     /* R37 - ClassD3 */ -	0x0079,     /* R38 - ClassD4 */ -	0x0000,     /* R39 - Input Mixer1 */ -	0x0000,     /* R40 - Input Mixer2 */ -	0x0000,     /* R41 - Input Mixer3 */ -	0x0000,     /* R42 - Input Mixer4 */ -	0x0000,     /* R43 - Input Mixer5 */ -	0x0000,     /* R44 - Input Mixer6 */ -	0x0000,     /* R45 - Output Mixer1 */ -	0x0000,     /* R46 - Output Mixer2 */ -	0x0000,     /* R47 - Output Mixer3 */ -	0x0000,     /* R48 - Output Mixer4 */ -	0x0000,     /* R49 - Output Mixer5 */ -	0x0000,     /* R50 - Output Mixer6 */ -	0x0180,     /* R51 - Out3/4 Mixer */ -	0x0000,     /* R52 - Line Mixer1 */ -	0x0000,     /* R53 - Line Mixer2 */ -	0x0000,     /* R54 - Speaker Mixer */ -	0x0000,     /* R55 - Additional Control */ -	0x0000,     /* R56 - AntiPOP1 */ -	0x0000,     /* R57 - AntiPOP2 */ -	0x0000,     /* R58 - MICBIAS */ -	0x0000,     /* R59 */ -	0x0008,     /* R60 - PLL1 */ -	0x0031,     /* R61 - PLL2 */ -	0x0026,     /* R62 - PLL3 */ -	0x0000,	    /* R63 - Driver internal */ +static const struct reg_default wm8990_reg_defaults[] = { +	{  1, 0x0000 },     /* R1  - Power Management (1) */ +	{  2, 0x6000 },     /* R2  - Power Management (2) */ +	{  3, 0x0000 },     /* R3  - Power Management (3) */ +	{  4, 0x4050 },     /* R4  - Audio Interface (1) */ +	{  5, 0x4000 },     /* R5  - Audio Interface (2) */ +	{  6, 0x01C8 },     /* R6  - Clocking (1) */ +	{  7, 0x0000 },     /* R7  - Clocking (2) */ +	{  8, 0x0040 },     /* R8  - Audio Interface (3) */ +	{  9, 0x0040 },     /* R9  - Audio Interface (4) */ +	{ 10, 0x0004 },     /* R10 - DAC CTRL */ +	{ 11, 0x00C0 },     /* R11 - Left DAC Digital Volume */ +	{ 12, 0x00C0 },     /* R12 - Right DAC Digital Volume */ +	{ 13, 0x0000 },     /* R13 - Digital Side Tone */ +	{ 14, 0x0100 },     /* R14 - ADC CTRL */ +	{ 15, 0x00C0 },     /* R15 - Left ADC Digital Volume */ +	{ 16, 0x00C0 },     /* R16 - Right ADC Digital Volume */ + +	{ 18, 0x0000 },     /* R18 - GPIO CTRL 1 */ +	{ 19, 0x1000 },     /* R19 - GPIO1 & GPIO2 */ +	{ 20, 0x1010 },     /* R20 - GPIO3 & GPIO4 */ +	{ 21, 0x1010 },     /* R21 - GPIO5 & GPIO6 */ +	{ 22, 0x8000 },     /* R22 - GPIOCTRL 2 */ +	{ 23, 0x0800 },     /* R23 - GPIO_POL */ +	{ 24, 0x008B },     /* R24 - Left Line Input 1&2 Volume */ +	{ 25, 0x008B },     /* R25 - Left Line Input 3&4 Volume */ +	{ 26, 0x008B },     /* R26 - Right Line Input 1&2 Volume */ +	{ 27, 0x008B },     /* R27 - Right Line Input 3&4 Volume */ +	{ 28, 0x0000 },     /* R28 - Left Output Volume */ +	{ 29, 0x0000 },     /* R29 - Right Output Volume */ +	{ 30, 0x0066 },     /* R30 - Line Outputs Volume */ +	{ 31, 0x0022 },     /* R31 - Out3/4 Volume */ +	{ 32, 0x0079 },     /* R32 - Left OPGA Volume */ +	{ 33, 0x0079 },     /* R33 - Right OPGA Volume */ +	{ 34, 0x0003 },     /* R34 - Speaker Volume */ +	{ 35, 0x0003 },     /* R35 - ClassD1 */ + +	{ 37, 0x0100 },     /* R37 - ClassD3 */ +	{ 38, 0x0079 },     /* R38 - ClassD4 */ +	{ 39, 0x0000 },     /* R39 - Input Mixer1 */ +	{ 40, 0x0000 },     /* R40 - Input Mixer2 */ +	{ 41, 0x0000 },     /* R41 - Input Mixer3 */ +	{ 42, 0x0000 },     /* R42 - Input Mixer4 */ +	{ 43, 0x0000 },     /* R43 - Input Mixer5 */ +	{ 44, 0x0000 },     /* R44 - Input Mixer6 */ +	{ 45, 0x0000 },     /* R45 - Output Mixer1 */ +	{ 46, 0x0000 },     /* R46 - Output Mixer2 */ +	{ 47, 0x0000 },     /* R47 - Output Mixer3 */ +	{ 48, 0x0000 },     /* R48 - Output Mixer4 */ +	{ 49, 0x0000 },     /* R49 - Output Mixer5 */ +	{ 50, 0x0000 },     /* R50 - Output Mixer6 */ +	{ 51, 0x0180 },     /* R51 - Out3/4 Mixer */ +	{ 52, 0x0000 },     /* R52 - Line Mixer1 */ +	{ 53, 0x0000 },     /* R53 - Line Mixer2 */ +	{ 54, 0x0000 },     /* R54 - Speaker Mixer */ +	{ 55, 0x0000 },     /* R55 - Additional Control */ +	{ 56, 0x0000 },     /* R56 - AntiPOP1 */ +	{ 57, 0x0000 },     /* R57 - AntiPOP2 */ +	{ 58, 0x0000 },     /* R58 - MICBIAS */ + +	{ 60, 0x0008 },     /* R60 - PLL1 */ +	{ 61, 0x0031 },     /* R61 - PLL2 */ +	{ 62, 0x0026 },     /* R62 - PLL3 */  };  #define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0) @@ -134,7 +132,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);  static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value;  	int reg = mc->reg; @@ -159,26 +157,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,  static const char *wm8990_digital_sidetone[] =  	{"None", "Left ADC", "Right ADC", "Reserved"}; -static const struct soc_enum wm8990_left_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, -	WM8990_ADC_TO_DACL_SHIFT, -	WM8990_ADC_TO_DACL_MASK, -	wm8990_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8990_left_digital_sidetone_enum, +			    WM8990_DIGITAL_SIDE_TONE, +			    WM8990_ADC_TO_DACL_SHIFT, +			    wm8990_digital_sidetone); -static const struct soc_enum wm8990_right_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, -	WM8990_ADC_TO_DACR_SHIFT, -	WM8990_ADC_TO_DACR_MASK, -	wm8990_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8990_right_digital_sidetone_enum, +			    WM8990_DIGITAL_SIDE_TONE, +			    WM8990_ADC_TO_DACR_SHIFT, +			    wm8990_digital_sidetone);  static const char *wm8990_adcmode[] =  	{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; -static const struct soc_enum wm8990_right_adcmode_enum = -SOC_ENUM_SINGLE(WM8990_ADC_CTRL, -	WM8990_ADC_HPF_CUT_SHIFT, -	WM8990_ADC_HPF_CUT_MASK, -	wm8990_adcmode); +static SOC_ENUM_SINGLE_DECL(wm8990_right_adcmode_enum, +			    WM8990_ADC_CTRL, +			    WM8990_ADC_HPF_CUT_SHIFT, +			    wm8990_adcmode);  static const struct snd_kcontrol_new wm8990_snd_controls[] = {  /* INMIXL */ @@ -376,32 +371,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,   * _DAPM_ Controls   */ -static int inmixer_event(struct snd_soc_dapm_widget *w, -	struct snd_kcontrol *kcontrol, int event) -{ -	u16 reg, fakepower; - -	reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2); -	fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS); - -	if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | -		(1 << WM8990_AINLMUX_PWR_BIT))) { -		reg |= WM8990_AINL_ENA; -	} else { -		reg &= ~WM8990_AINL_ENA; -	} - -	if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | -		(1 << WM8990_AINRMUX_PWR_BIT))) { -		reg |= WM8990_AINR_ENA; -	} else { -		reg &= ~WM8990_AINR_ENA; -	} -	snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); - -	return 0; -} -  static int outmixer_event(struct snd_soc_dapm_widget *w,  	struct snd_kcontrol *kcontrol, int event)  { @@ -503,9 +472,9 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT,  static const char *wm8990_ainlmux[] =  	{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; -static const struct soc_enum wm8990_ainlmux_enum = -SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, -	ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); +static SOC_ENUM_SINGLE_DECL(wm8990_ainlmux_enum, +			    WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, +			    wm8990_ainlmux);  static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls =  SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); @@ -516,9 +485,9 @@ SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum);  static const char *wm8990_ainrmux[] =  	{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; -static const struct soc_enum wm8990_ainrmux_enum = -SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, -	ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); +static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum, +			    WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, +			    wm8990_ainrmux);  static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls =  SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); @@ -656,6 +625,11 @@ SND_SOC_DAPM_INPUT("RIN1"),  SND_SOC_DAPM_INPUT("RIN2"),  SND_SOC_DAPM_INPUT("Internal ADC Source"), +SND_SOC_DAPM_SUPPLY("INL", WM8990_POWER_MANAGEMENT_2, WM8990_AINL_ENA_BIT, 0, +		    NULL, 0), +SND_SOC_DAPM_SUPPLY("INR", WM8990_POWER_MANAGEMENT_2, WM8990_AINR_ENA_BIT, 0, +		    NULL, 0), +  /* DACs */  SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2,  	WM8990_ADCL_ENA_BIT, 0), @@ -677,26 +651,20 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT,  	ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)),  /* INMIXL */ -SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, +SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,  	&wm8990_dapm_inmixl_controls[0], -	ARRAY_SIZE(wm8990_dapm_inmixl_controls), -	inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	ARRAY_SIZE(wm8990_dapm_inmixl_controls)),  /* AINLMUX */ -SND_SOC_DAPM_MUX_E("AINLMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, -	&wm8990_dapm_ainlmux_controls, inmixer_event, -	SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainlmux_controls),  /* INMIXR */ -SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, +SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,  	&wm8990_dapm_inmixr_controls[0], -	ARRAY_SIZE(wm8990_dapm_inmixr_controls), -	inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	ARRAY_SIZE(wm8990_dapm_inmixr_controls)),  /* AINRMUX */ -SND_SOC_DAPM_MUX_E("AINRMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, -	&wm8990_dapm_ainrmux_controls, inmixer_event, -	SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainrmux_controls),  /* Output Side */  /* DACs */ @@ -787,7 +755,7 @@ SND_SOC_DAPM_OUTPUT("RON"),  SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),  }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8990_dapm_routes[] = {  	/* Make DACs turn on when playing even if not mixed into any outputs */  	{"Internal DAC Sink", NULL, "Left DAC"},  	{"Internal DAC Sink", NULL, "Right DAC"}, @@ -796,6 +764,11 @@ static const struct snd_soc_dapm_route audio_map[] = {  	{"Left ADC", NULL, "Internal ADC Source"},  	{"Right ADC", NULL, "Internal ADC Source"}, +	{"AINLMUX", NULL, "INL"}, +	{"INMIXL", NULL, "INL"}, +	{"AINRMUX", NULL, "INR"}, +	{"INMIXR", NULL, "INR"}, +  	/* Input Side */  	/* LIN12 PGA */  	{"LIN12 PGA", "LIN1 Switch", "LIN1"}, @@ -912,18 +885,6 @@ static const struct snd_soc_dapm_route audio_map[] = {  	{"RON", NULL, "RONMIX"},  }; -static int wm8990_add_widgets(struct snd_soc_codec *codec) -{ -	struct snd_soc_dapm_context *dapm = &codec->dapm; - -	snd_soc_dapm_new_controls(dapm, wm8990_dapm_widgets, -				  ARRAY_SIZE(wm8990_dapm_widgets)); -	/* set up the WM8990 audio map */ -	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - -	return 0; -} -  /* PLL divisors */  struct _pll_div {  	u32 div2; @@ -1148,6 +1109,7 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)  static int wm8990_set_bias_level(struct snd_soc_codec *codec,  	enum snd_soc_bias_level level)  { +	struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);  	int ret;  	switch (level) { @@ -1162,7 +1124,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			ret = snd_soc_cache_sync(codec); +			ret = regcache_sync(wm8990->regmap);  			if (ret < 0) {  				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);  				return ret; @@ -1259,6 +1221,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,  		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */  		snd_soc_write(codec, WM8990_ANTIPOP2, 0x0); + +		regcache_mark_dirty(wm8990->regmap);  		break;  	} @@ -1325,14 +1289,6 @@ static int wm8990_resume(struct snd_soc_codec *codec)   */  static int wm8990_probe(struct snd_soc_codec *codec)  { -	int ret; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); -	if (ret < 0) { -		printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	wm8990_reset(codec);  	/* charge output caps */ @@ -1350,10 +1306,6 @@ static int wm8990_probe(struct snd_soc_codec *codec)  	snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));  	snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); -	snd_soc_add_codec_controls(codec, wm8990_snd_controls, -				ARRAY_SIZE(wm8990_snd_controls)); -	wm8990_add_widgets(codec); -  	return 0;  } @@ -1370,13 +1322,25 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {  	.suspend =	wm8990_suspend,  	.resume =	wm8990_resume,  	.set_bias_level = wm8990_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8990_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8990_reg, -	.volatile_register = wm8990_volatile_register, +	.controls =	wm8990_snd_controls, +	.num_controls = ARRAY_SIZE(wm8990_snd_controls), +	.dapm_widgets = wm8990_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets), +	.dapm_routes =	wm8990_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes), +}; + +static const struct regmap_config wm8990_regmap = { +	.reg_bits = 8, +	.val_bits = 16, + +	.max_register = WM8990_PLL3, +	.volatile_reg = wm8990_volatile_register, +	.reg_defaults = wm8990_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8990_reg_defaults), +	.cache_type = REGCACHE_RBTREE,  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)  static int wm8990_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -1418,29 +1382,8 @@ static struct i2c_driver wm8990_i2c_driver = {  	.remove =   wm8990_i2c_remove,  	.id_table = wm8990_i2c_id,  }; -#endif - -static int __init wm8990_modinit(void) -{ -	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	ret = i2c_add_driver(&wm8990_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n", -		       ret); -	} -#endif -	return ret; -} -module_init(wm8990_modinit); -static void __exit wm8990_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -	i2c_del_driver(&wm8990_i2c_driver); -#endif -} -module_exit(wm8990_exit); +module_i2c_driver(wm8990_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8990 driver");  MODULE_AUTHOR("Liam Girdwood"); diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 77c98a4bfe9..0e9c78040c4 100644 --- a/sound/soc/codecs/wm8990.h +++ b/sound/soc/codecs/wm8990.h @@ -78,7 +78,6 @@  #define WM8990_PLL1                             0x3C  #define WM8990_PLL2                             0x3D  #define WM8990_PLL3                             0x3E -#define WM8990_INTDRIVBITS			0x3F  #define WM8990_EXT_ACCESS_ENA			0x75  #define WM8990_EXT_CTL1				0x7a @@ -818,14 +817,6 @@   */  #define WM8990_PLLK2_MASK                       0x00FF  /* PLLK2 - [7:0] */ -/* - * R63 (0x3F) - Internal Driver Bits - */ -#define WM8990_INMIXL_PWR_BIT			0 -#define WM8990_AINLMUX_PWR_BIT			1 -#define WM8990_INMIXR_PWR_BIT			2 -#define WM8990_AINRMUX_PWR_BIT			3 -  #define WM8990_MCLK_DIV 0  #define WM8990_DACCLK_DIV 1  #define WM8990_ADCCLK_DIV 2 diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 3a39df7a382..b8fd284fc0c 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -18,6 +18,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -31,77 +32,84 @@  #include "wm8991.h"  struct wm8991_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	unsigned int pcmclk;  }; -static const u16 wm8991_reg_defs[] = { -	0x8991,     /* R0  - Reset */ -	0x0000,     /* R1  - Power Management (1) */ -	0x6000,     /* R2  - Power Management (2) */ -	0x0000,     /* R3  - Power Management (3) */ -	0x4050,     /* R4  - Audio Interface (1) */ -	0x4000,     /* R5  - Audio Interface (2) */ -	0x01C8,     /* R6  - Clocking (1) */ -	0x0000,     /* R7  - Clocking (2) */ -	0x0040,     /* R8  - Audio Interface (3) */ -	0x0040,     /* R9  - Audio Interface (4) */ -	0x0004,     /* R10 - DAC CTRL */ -	0x00C0,     /* R11 - Left DAC Digital Volume */ -	0x00C0,     /* R12 - Right DAC Digital Volume */ -	0x0000,     /* R13 - Digital Side Tone */ -	0x0100,     /* R14 - ADC CTRL */ -	0x00C0,     /* R15 - Left ADC Digital Volume */ -	0x00C0,     /* R16 - Right ADC Digital Volume */ -	0x0000,     /* R17 */ -	0x0000,     /* R18 - GPIO CTRL 1 */ -	0x1000,     /* R19 - GPIO1 & GPIO2 */ -	0x1010,     /* R20 - GPIO3 & GPIO4 */ -	0x1010,     /* R21 - GPIO5 & GPIO6 */ -	0x8000,     /* R22 - GPIOCTRL 2 */ -	0x0800,     /* R23 - GPIO_POL */ -	0x008B,     /* R24 - Left Line Input 1&2 Volume */ -	0x008B,     /* R25 - Left Line Input 3&4 Volume */ -	0x008B,     /* R26 - Right Line Input 1&2 Volume */ -	0x008B,     /* R27 - Right Line Input 3&4 Volume */ -	0x0000,     /* R28 - Left Output Volume */ -	0x0000,     /* R29 - Right Output Volume */ -	0x0066,     /* R30 - Line Outputs Volume */ -	0x0022,     /* R31 - Out3/4 Volume */ -	0x0079,     /* R32 - Left OPGA Volume */ -	0x0079,     /* R33 - Right OPGA Volume */ -	0x0003,     /* R34 - Speaker Volume */ -	0x0003,     /* R35 - ClassD1 */ -	0x0000,     /* R36 */ -	0x0100,     /* R37 - ClassD3 */ -	0x0000,     /* R38 */ -	0x0000,     /* R39 - Input Mixer1 */ -	0x0000,     /* R40 - Input Mixer2 */ -	0x0000,     /* R41 - Input Mixer3 */ -	0x0000,     /* R42 - Input Mixer4 */ -	0x0000,     /* R43 - Input Mixer5 */ -	0x0000,     /* R44 - Input Mixer6 */ -	0x0000,     /* R45 - Output Mixer1 */ -	0x0000,     /* R46 - Output Mixer2 */ -	0x0000,     /* R47 - Output Mixer3 */ -	0x0000,     /* R48 - Output Mixer4 */ -	0x0000,     /* R49 - Output Mixer5 */ -	0x0000,     /* R50 - Output Mixer6 */ -	0x0180,     /* R51 - Out3/4 Mixer */ -	0x0000,     /* R52 - Line Mixer1 */ -	0x0000,     /* R53 - Line Mixer2 */ -	0x0000,     /* R54 - Speaker Mixer */ -	0x0000,     /* R55 - Additional Control */ -	0x0000,     /* R56 - AntiPOP1 */ -	0x0000,     /* R57 - AntiPOP2 */ -	0x0000,     /* R58 - MICBIAS */ -	0x0000,     /* R59 */ -	0x0008,     /* R60 - PLL1 */ -	0x0031,     /* R61 - PLL2 */ -	0x0026,     /* R62 - PLL3 */ +static const struct reg_default wm8991_reg_defaults[] = { +	{  1, 0x0000 },     /* R1  - Power Management (1) */ +	{  2, 0x6000 },     /* R2  - Power Management (2) */ +	{  3, 0x0000 },     /* R3  - Power Management (3) */ +	{  4, 0x4050 },     /* R4  - Audio Interface (1) */ +	{  5, 0x4000 },     /* R5  - Audio Interface (2) */ +	{  6, 0x01C8 },     /* R6  - Clocking (1) */ +	{  7, 0x0000 },     /* R7  - Clocking (2) */ +	{  8, 0x0040 },     /* R8  - Audio Interface (3) */ +	{  9, 0x0040 },     /* R9  - Audio Interface (4) */ +	{ 10, 0x0004 },     /* R10 - DAC CTRL */ +	{ 11, 0x00C0 },     /* R11 - Left DAC Digital Volume */ +	{ 12, 0x00C0 },     /* R12 - Right DAC Digital Volume */ +	{ 13, 0x0000 },     /* R13 - Digital Side Tone */ +	{ 14, 0x0100 },     /* R14 - ADC CTRL */ +	{ 15, 0x00C0 },     /* R15 - Left ADC Digital Volume */ +	{ 16, 0x00C0 },     /* R16 - Right ADC Digital Volume */ + +	{ 18, 0x0000 },     /* R18 - GPIO CTRL 1 */ +	{ 19, 0x1000 },     /* R19 - GPIO1 & GPIO2 */ +	{ 20, 0x1010 },     /* R20 - GPIO3 & GPIO4 */ +	{ 21, 0x1010 },     /* R21 - GPIO5 & GPIO6 */ +	{ 22, 0x8000 },     /* R22 - GPIOCTRL 2 */ +	{ 23, 0x0800 },     /* R23 - GPIO_POL */ +	{ 24, 0x008B },     /* R24 - Left Line Input 1&2 Volume */ +	{ 25, 0x008B },     /* R25 - Left Line Input 3&4 Volume */ +	{ 26, 0x008B },     /* R26 - Right Line Input 1&2 Volume */ +	{ 27, 0x008B },     /* R27 - Right Line Input 3&4 Volume */ +	{ 28, 0x0000 },     /* R28 - Left Output Volume */ +	{ 29, 0x0000 },     /* R29 - Right Output Volume */ +	{ 30, 0x0066 },     /* R30 - Line Outputs Volume */ +	{ 31, 0x0022 },     /* R31 - Out3/4 Volume */ +	{ 32, 0x0079 },     /* R32 - Left OPGA Volume */ +	{ 33, 0x0079 },     /* R33 - Right OPGA Volume */ +	{ 34, 0x0003 },     /* R34 - Speaker Volume */ +	{ 35, 0x0003 },     /* R35 - ClassD1 */ + +	{ 37, 0x0100 },     /* R37 - ClassD3 */ + +	{ 39, 0x0000 },     /* R39 - Input Mixer1 */ +	{ 40, 0x0000 },     /* R40 - Input Mixer2 */ +	{ 41, 0x0000 },     /* R41 - Input Mixer3 */ +	{ 42, 0x0000 },     /* R42 - Input Mixer4 */ +	{ 43, 0x0000 },     /* R43 - Input Mixer5 */ +	{ 44, 0x0000 },     /* R44 - Input Mixer6 */ +	{ 45, 0x0000 },     /* R45 - Output Mixer1 */ +	{ 46, 0x0000 },     /* R46 - Output Mixer2 */ +	{ 47, 0x0000 },     /* R47 - Output Mixer3 */ +	{ 48, 0x0000 },     /* R48 - Output Mixer4 */ +	{ 49, 0x0000 },     /* R49 - Output Mixer5 */ +	{ 50, 0x0000 },     /* R50 - Output Mixer6 */ +	{ 51, 0x0180 },     /* R51 - Out3/4 Mixer */ +	{ 52, 0x0000 },     /* R52 - Line Mixer1 */ +	{ 53, 0x0000 },     /* R53 - Line Mixer2 */ +	{ 54, 0x0000 },     /* R54 - Speaker Mixer */ +	{ 55, 0x0000 },     /* R55 - Additional Control */ +	{ 56, 0x0000 },     /* R56 - AntiPOP1 */ +	{ 57, 0x0000 },     /* R57 - AntiPOP2 */ +	{ 58, 0x0000 },     /* R58 - MICBIAS */ + +	{ 60, 0x0008 },     /* R60 - PLL1 */ +	{ 61, 0x0031 },     /* R61 - PLL2 */ +	{ 62, 0x0026 },     /* R62 - PLL3 */  }; -#define wm8991_reset(c) snd_soc_write(c, WM8991_RESET, 0) +static bool wm8991_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8991_RESET: +		return true; +	default: +		return false; +	} +}  static const unsigned int rec_mix_tlv[] = {  	TLV_DB_RANGE_HEAD(1), @@ -146,7 +154,7 @@ static const unsigned int out_sidetone_tlv[] = {  static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,  				      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	int reg = kcontrol->private_value & 0xff;  	int ret;  	u16 val; @@ -163,26 +171,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,  static const char *wm8991_digital_sidetone[] =  {"None", "Left ADC", "Right ADC", "Reserved"}; -static const struct soc_enum wm8991_left_digital_sidetone_enum = -	SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE, -			WM8991_ADC_TO_DACL_SHIFT, -			WM8991_ADC_TO_DACL_MASK, -			wm8991_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8991_left_digital_sidetone_enum, +			    WM8991_DIGITAL_SIDE_TONE, +			    WM8991_ADC_TO_DACL_SHIFT, +			    wm8991_digital_sidetone); -static const struct soc_enum wm8991_right_digital_sidetone_enum = -	SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE, -			WM8991_ADC_TO_DACR_SHIFT, -			WM8991_ADC_TO_DACR_MASK, -			wm8991_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8991_right_digital_sidetone_enum, +			    WM8991_DIGITAL_SIDE_TONE, +			    WM8991_ADC_TO_DACR_SHIFT, +			    wm8991_digital_sidetone);  static const char *wm8991_adcmode[] =  {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; -static const struct soc_enum wm8991_right_adcmode_enum = -	SOC_ENUM_SINGLE(WM8991_ADC_CTRL, -			WM8991_ADC_HPF_CUT_SHIFT, -			WM8991_ADC_HPF_CUT_MASK, -			wm8991_adcmode); +static SOC_ENUM_SINGLE_DECL(wm8991_right_adcmode_enum, +			    WM8991_ADC_CTRL, +			    WM8991_ADC_HPF_CUT_SHIFT, +			    wm8991_adcmode);  static const struct snd_kcontrol_new wm8991_snd_controls[] = {  	/* INMIXL */ @@ -374,30 +379,6 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {  /*   * _DAPM_ Controls   */ -static int inmixer_event(struct snd_soc_dapm_widget *w, -			 struct snd_kcontrol *kcontrol, int event) -{ -	u16 reg, fakepower; - -	reg = snd_soc_read(w->codec, WM8991_POWER_MANAGEMENT_2); -	fakepower = snd_soc_read(w->codec, WM8991_INTDRIVBITS); - -	if (fakepower & ((1 << WM8991_INMIXL_PWR_BIT) | -			 (1 << WM8991_AINLMUX_PWR_BIT))) -		reg |= WM8991_AINL_ENA; -	else -		reg &= ~WM8991_AINL_ENA; - -	if (fakepower & ((1 << WM8991_INMIXR_PWR_BIT) | -			 (1 << WM8991_AINRMUX_PWR_BIT))) -		reg |= WM8991_AINR_ENA; -	else -		reg &= ~WM8991_AINR_ENA; - -	snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg); -	return 0; -} -  static int outmixer_event(struct snd_soc_dapm_widget *w,  			  struct snd_kcontrol *kcontrol, int event)  { @@ -502,9 +483,9 @@ static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = {  static const char *wm8991_ainlmux[] =  {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; -static const struct soc_enum wm8991_ainlmux_enum = -	SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT, -			ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux); +static SOC_ENUM_SINGLE_DECL(wm8991_ainlmux_enum, +			    WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT, +			    wm8991_ainlmux);  static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =  	SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum); @@ -515,9 +496,9 @@ static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =  static const char *wm8991_ainrmux[] =  {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; -static const struct soc_enum wm8991_ainrmux_enum = -	SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT, -			ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux); +static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum, +			    WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT, +			    wm8991_ainrmux);  static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =  	SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum); @@ -655,6 +636,11 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {  	SND_SOC_DAPM_INPUT("RIN2"),  	SND_SOC_DAPM_INPUT("Internal ADC Source"), +	SND_SOC_DAPM_SUPPLY("INL", WM8991_POWER_MANAGEMENT_2, +			    WM8991_AINL_ENA_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("INR", WM8991_POWER_MANAGEMENT_2, +			    WM8991_AINR_ENA_BIT, 0, NULL, 0), +  	/* DACs */  	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2,  		WM8991_ADCL_ENA_BIT, 0), @@ -676,26 +662,22 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {  		ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)),  	/* INMIXL */ -	SND_SOC_DAPM_MIXER_E("INMIXL", WM8991_INTDRIVBITS, WM8991_INMIXL_PWR_BIT, 0, +	SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,  		&wm8991_dapm_inmixl_controls[0], -		ARRAY_SIZE(wm8991_dapm_inmixl_controls), -		inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +		ARRAY_SIZE(wm8991_dapm_inmixl_controls)),  	/* AINLMUX */ -	SND_SOC_DAPM_MUX_E("AINLMUX", WM8991_INTDRIVBITS, WM8991_AINLMUX_PWR_BIT, 0, -		&wm8991_dapm_ainlmux_controls, inmixer_event, -		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0, +		&wm8991_dapm_ainlmux_controls),  	/* INMIXR */ -	SND_SOC_DAPM_MIXER_E("INMIXR", WM8991_INTDRIVBITS, WM8991_INMIXR_PWR_BIT, 0, +	SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,  		&wm8991_dapm_inmixr_controls[0], -		ARRAY_SIZE(wm8991_dapm_inmixr_controls), -		inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +		ARRAY_SIZE(wm8991_dapm_inmixr_controls)),  	/* AINRMUX */ -	SND_SOC_DAPM_MUX_E("AINRMUX", WM8991_INTDRIVBITS, WM8991_AINRMUX_PWR_BIT, 0, -		&wm8991_dapm_ainrmux_controls, inmixer_event, -		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0, +		&wm8991_dapm_ainrmux_controls),  	/* Output Side */  	/* DACs */ @@ -787,7 +769,7 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),  }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8991_dapm_routes[] = {  	/* Make DACs turn on when playing even if not mixed into any outputs */  	{"Internal DAC Sink", NULL, "Left DAC"},  	{"Internal DAC Sink", NULL, "Right DAC"}, @@ -797,6 +779,10 @@ static const struct snd_soc_dapm_route audio_map[] = {  	{"Right ADC", NULL, "Internal ADC Source"},  	/* Input Side */ +	{"INMIXL", NULL, "INL"}, +	{"AINLMUX", NULL, "INL"}, +	{"INMIXR", NULL, "INR"}, +	{"AINRMUX", NULL, "INR"},  	/* LIN12 PGA */  	{"LIN12 PGA", "LIN1 Switch", "LIN1"},  	{"LIN12 PGA", "LIN2 Switch", "LIN2"}, @@ -1129,6 +1115,7 @@ static int wm8991_mute(struct snd_soc_dai *dai, int mute)  static int wm8991_set_bias_level(struct snd_soc_codec *codec,  				 enum snd_soc_bias_level level)  { +	struct wm8991_priv *wm8991 = snd_soc_codec_get_drvdata(codec);  	u16 val;  	switch (level) { @@ -1144,7 +1131,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			snd_soc_cache_sync(codec); +			regcache_sync(wm8991->regmap);  			/* Enable all output discharge bits */  			snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |  				      WM8991_DIS_RLINE | WM8991_DIS_OUT3 | @@ -1232,7 +1219,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,  		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */  		snd_soc_write(codec, WM8991_ANTIPOP2, 0x0); -		codec->cache_sync = 1; +		regcache_mark_dirty(wm8991->regmap);  		break;  	} @@ -1261,49 +1248,8 @@ static int wm8991_remove(struct snd_soc_codec *codec)  static int wm8991_probe(struct snd_soc_codec *codec)  { -	struct wm8991_priv *wm8991; -	int ret; - -	wm8991 = snd_soc_codec_get_drvdata(codec); - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8991->control_type); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); -		return ret; -	} - -	ret = wm8991_reset(codec); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to issue reset\n"); -		return ret; -	} -  	wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	snd_soc_update_bits(codec, WM8991_AUDIO_INTERFACE_4, -			    WM8991_ALRCGPIO1, WM8991_ALRCGPIO1); - -	snd_soc_update_bits(codec, WM8991_GPIO1_GPIO2, -			    WM8991_GPIO1_SEL_MASK, 1); - -	snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_1, -			    WM8991_VREF_ENA | WM8991_VMID_MODE_MASK, -			    WM8991_VREF_ENA | WM8991_VMID_MODE_MASK); - -	snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_2, -			    WM8991_OPCLK_ENA, WM8991_OPCLK_ENA); - -	snd_soc_write(codec, WM8991_DAC_CTRL, 0); -	snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); -	snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); - -	snd_soc_add_codec_controls(codec, wm8991_snd_controls, -			     ARRAY_SIZE(wm8991_snd_controls)); - -	snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets, -				  ARRAY_SIZE(wm8991_dapm_widgets)); -	snd_soc_dapm_add_routes(&codec->dapm, audio_map, -				ARRAY_SIZE(audio_map));  	return 0;  } @@ -1352,24 +1298,77 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {  	.suspend = wm8991_suspend,  	.resume = wm8991_resume,  	.set_bias_level = wm8991_set_bias_level, -	.reg_cache_size = WM8991_MAX_REGISTER + 1, -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8991_reg_defs +	.controls = wm8991_snd_controls, +	.num_controls = ARRAY_SIZE(wm8991_snd_controls), +	.dapm_widgets = wm8991_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(wm8991_dapm_widgets), +	.dapm_routes = wm8991_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(wm8991_dapm_routes), +}; + +static const struct regmap_config wm8991_regmap = { +	.reg_bits = 8, +	.val_bits = 16, + +	.max_register = WM8991_PLL3, +	.volatile_reg = wm8991_volatile, +	.reg_defaults = wm8991_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults), +	.cache_type = REGCACHE_RBTREE,  };  static int wm8991_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  {  	struct wm8991_priv *wm8991; +	unsigned int val;  	int ret;  	wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL);  	if (!wm8991)  		return -ENOMEM; -	wm8991->control_type = SND_SOC_I2C; +	wm8991->regmap = devm_regmap_init_i2c(i2c, &wm8991_regmap); +	if (IS_ERR(wm8991->regmap)) +		return PTR_ERR(wm8991->regmap); +  	i2c_set_clientdata(i2c, wm8991); +	ret = regmap_read(wm8991->regmap, WM8991_RESET, &val); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to read device ID: %d\n", ret); +		return ret; +	} +	if (val != 0x8991) { +		dev_err(&i2c->dev, "Device with ID %x is not a WM8991\n", val); +		return -EINVAL; +	} + +	ret = regmap_write(wm8991->regmap, WM8991_RESET, 0); +	if (ret < 0) { +		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); +		return ret; +	} + +	regmap_update_bits(wm8991->regmap, WM8991_AUDIO_INTERFACE_4, +			   WM8991_ALRCGPIO1, WM8991_ALRCGPIO1); + +	regmap_update_bits(wm8991->regmap, WM8991_GPIO1_GPIO2, +			   WM8991_GPIO1_SEL_MASK, 1); + +	regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_1, +			   WM8991_VREF_ENA | WM8991_VMID_MODE_MASK, +			   WM8991_VREF_ENA | WM8991_VMID_MODE_MASK); + +	regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_2, +			   WM8991_OPCLK_ENA, WM8991_OPCLK_ENA); + +	regmap_write(wm8991->regmap, WM8991_DAC_CTRL, 0); +	regmap_write(wm8991->regmap, WM8991_LEFT_OUTPUT_VOLUME, +		     0x50 | (1<<8)); +	regmap_write(wm8991->regmap, WM8991_RIGHT_OUTPUT_VOLUME, +		     0x50 | (1<<8)); +  	ret = snd_soc_register_codec(&i2c->dev,  				     &soc_codec_dev_wm8991, &wm8991_dai, 1); diff --git a/sound/soc/codecs/wm8991.h b/sound/soc/codecs/wm8991.h index 07707d8d7e2..08ed383303c 100644 --- a/sound/soc/codecs/wm8991.h +++ b/sound/soc/codecs/wm8991.h @@ -76,7 +76,6 @@  #define WM8991_PLL1                             0x3C  #define WM8991_PLL2                             0x3D  #define WM8991_PLL3                             0x3E -#define WM8991_INTDRIVBITS			0x3F  #define WM8991_REGISTER_COUNT                   60  #define WM8991_MAX_REGISTER                     0x3F @@ -807,14 +806,6 @@   */  #define WM8991_PLLK2_MASK                       0x00FF  /* PLLK2 - [7:0] */ -/* - * R63 (0x3F) - Internal Driver Bits - */ -#define WM8991_INMIXL_PWR_BIT			0 -#define WM8991_AINLMUX_PWR_BIT			1 -#define WM8991_INMIXR_PWR_BIT			2 -#define WM8991_AINRMUX_PWR_BIT			3 -  #define WM8991_MCLK_DIV 0  #define WM8991_DACCLK_DIV 1  #define WM8991_ADCCLK_DIV 2 diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 433d59a0f3e..f825dc04ebe 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -646,8 +646,8 @@ static const char *dac_deemph_text[] = {  	"48kHz",  }; -static const struct soc_enum dac_deemph = -	SOC_ENUM_SINGLE(WM8993_DAC_CTRL, 4, 4, dac_deemph_text); +static SOC_ENUM_SINGLE_DECL(dac_deemph, +			    WM8993_DAC_CTRL, 4, dac_deemph_text);  static const char *adc_hpf_text[] = {  	"Hi-Fi", @@ -656,16 +656,16 @@ static const char *adc_hpf_text[] = {  	"Voice 3",  }; -static const struct soc_enum adc_hpf = -	SOC_ENUM_SINGLE(WM8993_ADC_CTRL, 5, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(adc_hpf, +			    WM8993_ADC_CTRL, 5, adc_hpf_text);  static const char *drc_path_text[] = {  	"ADC",  	"DAC"  }; -static const struct soc_enum drc_path = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 14, 2, drc_path_text); +static SOC_ENUM_SINGLE_DECL(drc_path, +			    WM8993_DRC_CONTROL_1, 14, drc_path_text);  static const char *drc_r0_text[] = {  	"1", @@ -676,8 +676,8 @@ static const char *drc_r0_text[] = {  	"0",  }; -static const struct soc_enum drc_r0 = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 8, 6, drc_r0_text); +static SOC_ENUM_SINGLE_DECL(drc_r0, +			    WM8993_DRC_CONTROL_3, 8, drc_r0_text);  static const char *drc_r1_text[] = {  	"1", @@ -687,8 +687,8 @@ static const char *drc_r1_text[] = {  	"0",  }; -static const struct soc_enum drc_r1 = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_4, 13, 5, drc_r1_text); +static SOC_ENUM_SINGLE_DECL(drc_r1, +			    WM8993_DRC_CONTROL_4, 13, drc_r1_text);  static const char *drc_attack_text[] = {  	"Reserved", @@ -705,8 +705,8 @@ static const char *drc_attack_text[] = {  	"185.6ms",  }; -static const struct soc_enum drc_attack = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 12, 12, drc_attack_text); +static SOC_ENUM_SINGLE_DECL(drc_attack, +			    WM8993_DRC_CONTROL_2, 12, drc_attack_text);  static const char *drc_decay_text[] = {  	"186ms", @@ -720,16 +720,16 @@ static const char *drc_decay_text[] = {  	"47.56ms",  }; -static const struct soc_enum drc_decay = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 8, 9, drc_decay_text); +static SOC_ENUM_SINGLE_DECL(drc_decay, +			    WM8993_DRC_CONTROL_2, 8, drc_decay_text);  static const char *drc_ff_text[] = {  	"5 samples",  	"9 samples",  }; -static const struct soc_enum drc_ff = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 7, 2, drc_ff_text); +static SOC_ENUM_SINGLE_DECL(drc_ff, +			    WM8993_DRC_CONTROL_3, 7, drc_ff_text);  static const char *drc_qr_rate_text[] = {  	"0.725ms", @@ -737,8 +737,8 @@ static const char *drc_qr_rate_text[] = {  	"5.8ms",  }; -static const struct soc_enum drc_qr_rate = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 0, 3, drc_qr_rate_text); +static SOC_ENUM_SINGLE_DECL(drc_qr_rate, +			    WM8993_DRC_CONTROL_3, 0, drc_qr_rate_text);  static const char *drc_smooth_text[] = {  	"Low", @@ -746,8 +746,8 @@ static const char *drc_smooth_text[] = {  	"High",  }; -static const struct soc_enum drc_smooth = -	SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text); +static SOC_ENUM_SINGLE_DECL(drc_smooth, +			    WM8993_DRC_CONTROL_1, 4, drc_smooth_text);  static const struct snd_kcontrol_new wm8993_snd_controls[] = {  SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE, @@ -841,26 +841,26 @@ static const char *aif_text[] = {  	"Left", "Right"  }; -static const struct soc_enum aifoutl_enum = -	SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 15, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifoutl_enum, +			    WM8993_AUDIO_INTERFACE_1, 15, aif_text);  static const struct snd_kcontrol_new aifoutl_mux =  	SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); -static const struct soc_enum aifoutr_enum = -	SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 14, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifoutr_enum, +			    WM8993_AUDIO_INTERFACE_1, 14, aif_text);  static const struct snd_kcontrol_new aifoutr_mux =  	SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); -static const struct soc_enum aifinl_enum = -	SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 15, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifinl_enum, +			    WM8993_AUDIO_INTERFACE_2, 15, aif_text);  static const struct snd_kcontrol_new aifinl_mux =  	SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); -static const struct soc_enum aifinr_enum = -	SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 14, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifinr_enum, +			    WM8993_AUDIO_INTERFACE_2, 14, aif_text);  static const struct snd_kcontrol_new aifinr_mux =  	SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); @@ -869,14 +869,14 @@ static const char *sidetone_text[] = {  	"None", "Left", "Right"  }; -static const struct soc_enum sidetonel_enum = -	SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 2, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetonel_enum, +			    WM8993_DIGITAL_SIDE_TONE, 2, sidetone_text);  static const struct snd_kcontrol_new sidetonel_mux =  	SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum); -static const struct soc_enum sidetoner_enum = -	SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 0, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetoner_enum, +			    WM8993_DIGITAL_SIDE_TONE, 0, sidetone_text);  static const struct snd_kcontrol_new sidetoner_mux =  	SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum); @@ -1493,13 +1493,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)  	wm8993->hubs_data.dcs_codes_r = -2;  	wm8993->hubs_data.series_startup = 1; -	codec->control_data = wm8993->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Latch volume update bits and default ZC on */  	snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,  			    WM8993_DAC_VU, WM8993_DAC_VU); @@ -1559,10 +1552,7 @@ static int wm8993_probe(struct snd_soc_codec *codec)  static int wm8993_remove(struct snd_soc_codec *codec)  { -	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); -  	wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); -	regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);  	return 0;  } diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 86426a117b0..247b39013fb 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -265,21 +265,21 @@ static const char *sidetone_hpf_text[] = {  	"2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz"  }; -static const struct soc_enum sidetone_hpf = -	SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text); +static SOC_ENUM_SINGLE_DECL(sidetone_hpf, +			    WM8994_SIDETONE, 7, sidetone_hpf_text);  static const char *adc_hpf_text[] = {  	"HiFi", "Voice 1", "Voice 2", "Voice 3"  }; -static const struct soc_enum aif1adc1_hpf = -	SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf, +			    WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text); -static const struct soc_enum aif1adc2_hpf = -	SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf, +			    WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text); -static const struct soc_enum aif2adc_hpf = -	SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif2adc_hpf, +			    WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text);  static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);  static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); @@ -298,7 +298,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	int mask, ret;  	/* Can't enable both ADC and DAC paths simultaneously */ @@ -355,7 +355,7 @@ static int wm8994_get_drc(const char *name)  static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	struct wm8994 *control = wm8994->wm8994;  	struct wm8994_pdata *pdata = &control->pdata; @@ -378,7 +378,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,  static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	int drc = wm8994_get_drc(kcontrol->id.name); @@ -462,7 +462,7 @@ static int wm8994_get_retune_mobile_block(const char *name)  static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,  					 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	struct wm8994 *control = wm8994->wm8994;  	struct wm8994_pdata *pdata = &control->pdata; @@ -485,7 +485,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,  static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,  					 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	int block = wm8994_get_retune_mobile_block(kcontrol->id.name); @@ -501,39 +501,39 @@ static const char *aif_chan_src_text[] = {  	"Left", "Right"  }; -static const struct soc_enum aif1adcl_src = -	SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1adcl_src, +			    WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text); -static const struct soc_enum aif1adcr_src = -	SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1adcr_src, +			    WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text); -static const struct soc_enum aif2adcl_src = -	SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2adcl_src, +			    WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text); -static const struct soc_enum aif2adcr_src = -	SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2adcr_src, +			    WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text); -static const struct soc_enum aif1dacl_src = -	SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1dacl_src, +			    WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text); -static const struct soc_enum aif1dacr_src = -	SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1dacr_src, +			    WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text); -static const struct soc_enum aif2dacl_src = -	SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacl_src, +			    WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text); -static const struct soc_enum aif2dacr_src = -	SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacr_src, +			    WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text);  static const char *osr_text[] = {  	"Low Power", "High Performance",  }; -static const struct soc_enum dac_osr = -	SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(dac_osr, +			    WM8994_OVERSAMPLING, 0, osr_text); -static const struct soc_enum adc_osr = -	SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(adc_osr, +			    WM8994_OVERSAMPLING, 1, osr_text);  static const struct snd_kcontrol_new wm8994_snd_controls[] = {  SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, @@ -690,17 +690,20 @@ static const char *wm8958_ng_text[] = {  	"30ms", "125ms", "250ms", "500ms",  }; -static const struct soc_enum wm8958_aif1dac1_ng_hold = -	SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE, -			WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold, +			    WM8958_AIF1_DAC1_NOISE_GATE, +			    WM8958_AIF1DAC1_NG_THR_SHIFT, +			    wm8958_ng_text); -static const struct soc_enum wm8958_aif1dac2_ng_hold = -	SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE, -			WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold, +			    WM8958_AIF1_DAC2_NOISE_GATE, +			    WM8958_AIF1DAC2_NG_THR_SHIFT, +			    wm8958_ng_text); -static const struct soc_enum wm8958_aif2dac_ng_hold = -	SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE, -			WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold, +			    WM8958_AIF2_DAC_NOISE_GATE, +			    WM8958_AIF2DAC_NG_THR_SHIFT, +			    wm8958_ng_text);  static const struct snd_kcontrol_new wm8958_snd_controls[] = {  SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), @@ -1341,14 +1344,13 @@ static const char *adc_mux_text[] = {  	"DMIC",  }; -static const struct soc_enum adc_enum = -	SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);  static const struct snd_kcontrol_new adcl_mux = -	SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); +	SOC_DAPM_ENUM("ADCL Mux", adc_enum);  static const struct snd_kcontrol_new adcr_mux = -	SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); +	SOC_DAPM_ENUM("ADCR Mux", adc_enum);  static const struct snd_kcontrol_new left_speaker_mixer[] = {  SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0), @@ -1478,14 +1480,14 @@ static const char *sidetone_text[] = {  	"ADC/DMIC1", "DMIC2",  }; -static const struct soc_enum sidetone1_enum = -	SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone1_enum, +			    WM8994_SIDETONE, 0, sidetone_text);  static const struct snd_kcontrol_new sidetone1_mux =  	SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); -static const struct soc_enum sidetone2_enum = -	SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone2_enum, +			    WM8994_SIDETONE, 1, sidetone_text);  static const struct snd_kcontrol_new sidetone2_mux =  	SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); @@ -1498,22 +1500,24 @@ static const char *loopback_text[] = {  	"None", "ADCDAT",  }; -static const struct soc_enum aif1_loopback_enum = -	SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2, -			loopback_text); +static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum, +			    WM8994_AIF1_CONTROL_2, +			    WM8994_AIF1_LOOPBACK_SHIFT, +			    loopback_text);  static const struct snd_kcontrol_new aif1_loopback =  	SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum); -static const struct soc_enum aif2_loopback_enum = -	SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2, -			loopback_text); +static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum, +			    WM8994_AIF2_CONTROL_2, +			    WM8994_AIF2_LOOPBACK_SHIFT, +			    loopback_text);  static const struct snd_kcontrol_new aif2_loopback =  	SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum); -static const struct soc_enum aif1dac_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); +static SOC_ENUM_SINGLE_DECL(aif1dac_enum, +			    WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text);  static const struct snd_kcontrol_new aif1dac_mux =  	SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum); @@ -1522,8 +1526,8 @@ static const char *aif2dac_text[] = {  	"AIF2DACDAT", "AIF3DACDAT",  }; -static const struct soc_enum aif2dac_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text); +static SOC_ENUM_SINGLE_DECL(aif2dac_enum, +			    WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text);  static const struct snd_kcontrol_new aif2dac_mux =  	SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum); @@ -1532,8 +1536,8 @@ static const char *aif2adc_text[] = {  	"AIF2ADCDAT", "AIF3DACDAT",  }; -static const struct soc_enum aif2adc_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text); +static SOC_ENUM_SINGLE_DECL(aif2adc_enum, +			    WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text);  static const struct snd_kcontrol_new aif2adc_mux =  	SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum); @@ -1542,14 +1546,14 @@ static const char *aif3adc_text[] = {  	"AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM",  }; -static const struct soc_enum wm8994_aif3adc_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text); +static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum, +			    WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);  static const struct snd_kcontrol_new wm8994_aif3adc_mux =  	SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum); -static const struct soc_enum wm8958_aif3adc_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum, +			    WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);  static const struct snd_kcontrol_new wm8958_aif3adc_mux =  	SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum); @@ -1558,8 +1562,8 @@ static const char *mono_pcm_out_text[] = {  	"None", "AIF2ADCL", "AIF2ADCR",  }; -static const struct soc_enum mono_pcm_out_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text); +static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum, +			    WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text);  static const struct snd_kcontrol_new mono_pcm_out_mux =  	SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum); @@ -1569,14 +1573,14 @@ static const char *aif2dac_src_text[] = {  };  /* Note that these two control shouldn't be simultaneously switched to AIF3 */ -static const struct soc_enum aif2dacl_src_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum, +			    WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text);  static const struct snd_kcontrol_new aif2dacl_src_mux =  	SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum); -static const struct soc_enum aif2dacr_src_enum = -	SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum, +			    WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text);  static const struct snd_kcontrol_new aif2dacr_src_mux =  	SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum); @@ -1647,15 +1651,15 @@ SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),  };  static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = { -SND_SOC_DAPM_VIRT_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux, +SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,  			adc_mux_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_VIRT_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux, +SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,  			adc_mux_ev, SND_SOC_DAPM_PRE_PMU),  };  static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = { -SND_SOC_DAPM_VIRT_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), -SND_SOC_DAPM_VIRT_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), +SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), +SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),  };  static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { @@ -2549,43 +2553,52 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,  int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)  {  	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = &codec->dapm;  	switch (mode) {  	case WM8994_VMID_NORMAL: +		snd_soc_dapm_mutex_lock(dapm); +  		if (wm8994->hubs.lineout1_se) { -			snd_soc_dapm_disable_pin(&codec->dapm, -						 "LINEOUT1N Driver"); -			snd_soc_dapm_disable_pin(&codec->dapm, -						 "LINEOUT1P Driver"); +			snd_soc_dapm_disable_pin_unlocked(dapm, +							  "LINEOUT1N Driver"); +			snd_soc_dapm_disable_pin_unlocked(dapm, +							  "LINEOUT1P Driver");  		}  		if (wm8994->hubs.lineout2_se) { -			snd_soc_dapm_disable_pin(&codec->dapm, -						 "LINEOUT2N Driver"); -			snd_soc_dapm_disable_pin(&codec->dapm, -						 "LINEOUT2P Driver"); +			snd_soc_dapm_disable_pin_unlocked(dapm, +							  "LINEOUT2N Driver"); +			snd_soc_dapm_disable_pin_unlocked(dapm, +							  "LINEOUT2P Driver");  		}  		/* Do the sync with the old mode to allow it to clean up */ -		snd_soc_dapm_sync(&codec->dapm); +		snd_soc_dapm_sync_unlocked(dapm);  		wm8994->vmid_mode = mode; + +		snd_soc_dapm_mutex_unlock(dapm);  		break;  	case WM8994_VMID_FORCE: +		snd_soc_dapm_mutex_lock(dapm); +  		if (wm8994->hubs.lineout1_se) { -			snd_soc_dapm_force_enable_pin(&codec->dapm, -						      "LINEOUT1N Driver"); -			snd_soc_dapm_force_enable_pin(&codec->dapm, -						      "LINEOUT1P Driver"); +			snd_soc_dapm_force_enable_pin_unlocked(dapm, +							       "LINEOUT1N Driver"); +			snd_soc_dapm_force_enable_pin_unlocked(dapm, +							       "LINEOUT1P Driver");  		}  		if (wm8994->hubs.lineout2_se) { -			snd_soc_dapm_force_enable_pin(&codec->dapm, -						      "LINEOUT2N Driver"); -			snd_soc_dapm_force_enable_pin(&codec->dapm, -						      "LINEOUT2P Driver"); +			snd_soc_dapm_force_enable_pin_unlocked(dapm, +							       "LINEOUT2N Driver"); +			snd_soc_dapm_force_enable_pin_unlocked(dapm, +							       "LINEOUT2P Driver");  		}  		wm8994->vmid_mode = mode; -		snd_soc_dapm_sync(&codec->dapm); +		snd_soc_dapm_sync_unlocked(dapm); + +		snd_soc_dapm_mutex_unlock(dapm);  		break;  	default: @@ -3237,7 +3250,7 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)  	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",  		wm8994->num_retune_mobile_texts); -	wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; +	wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts;  	wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;  	ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, @@ -3293,7 +3306,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)  		for (i = 0; i < pdata->num_drc_cfgs; i++)  			wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; -		wm8994->drc_enum.max = pdata->num_drc_cfgs; +		wm8994->drc_enum.items = pdata->num_drc_cfgs;  		wm8994->drc_enum.texts = wm8994->drc_texts;  		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, @@ -3985,9 +3998,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)  	int ret, i;  	wm8994->hubs.codec = codec; -	codec->control_data = control->regmap; - -	snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);  	mutex_init(&wm8994->accdet_lock);  	INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, @@ -4077,12 +4087,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)  	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT,  			   wm8994_temp_shut, "Thermal shutdown", codec); -	ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE, -				 wm_hubs_dcs_done, "DC servo done", -				 &wm8994->hubs); -	if (ret == 0) -		wm8994->hubs.dcs_done_irq = true; -  	switch (control->type) {  	case WM8994:  		if (wm8994->micdet_irq) { @@ -4313,6 +4317,11 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)  	}  	wm_hubs_add_analogue_routes(codec, 0, 0); +	ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE, +				 wm_hubs_dcs_done, "DC servo done", +				 &wm8994->hubs); +	if (ret == 0) +		wm8994->hubs.dcs_done_irq = true;  	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));  	switch (control->type) { @@ -4423,11 +4432,19 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)  	return 0;  } +static struct regmap *wm8994_get_regmap(struct device *dev) +{ +	struct wm8994 *control = dev_get_drvdata(dev->parent); + +	return control->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {  	.probe =	wm8994_codec_probe,  	.remove =	wm8994_codec_remove,  	.suspend =	wm8994_codec_suspend,  	.resume =	wm8994_codec_resume, +	.get_regmap =   wm8994_get_regmap,  	.set_bias_level = wm8994_set_bias_level,  }; diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index da2899e6c40..863a2c38bcb 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -423,24 +423,24 @@ static const char *in1l_text[] = {  	"Differential", "Single-ended IN1LN", "Single-ended IN1LP"  }; -static const SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, -				  2, in1l_text); +static SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, +			    2, in1l_text);  static const char *in1r_text[] = {  	"Differential", "Single-ended IN1RN", "Single-ended IN1RP"  }; -static const SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, -				  0, in1r_text); +static SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, +			    0, in1r_text);  static const char *dmic_src_text[] = {  	"DMICDAT1", "DMICDAT2", "DMICDAT3"  }; -static const SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, -				  8, dmic_src_text); -static const SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, -				  6, dmic_src_text); +static SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, +			    8, dmic_src_text); +static SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, +			    6, dmic_src_text);  static const struct snd_kcontrol_new wm8995_snd_controls[] = {  	SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME, @@ -561,10 +561,8 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,  			   struct snd_kcontrol *kcontrol, int event)  {  	struct snd_soc_codec *codec; -	struct wm8995_priv *wm8995;  	codec = w->codec; -	wm8995 = snd_soc_codec_get_drvdata(codec);  	switch (event) {  	case SND_SOC_DAPM_PRE_PMU: @@ -783,14 +781,12 @@ static const char *sidetone_text[] = {  	"ADC/DMIC1", "DMIC2",  }; -static const struct soc_enum sidetone1_enum = -	SOC_ENUM_SINGLE(WM8995_SIDETONE, 0, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone1_enum, WM8995_SIDETONE, 0, sidetone_text);  static const struct snd_kcontrol_new sidetone1_mux =  	SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); -static const struct soc_enum sidetone2_enum = -	SOC_ENUM_SINGLE(WM8995_SIDETONE, 1, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone2_enum, WM8995_SIDETONE, 1, sidetone_text);  static const struct snd_kcontrol_new sidetone2_mux =  	SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); @@ -886,27 +882,26 @@ static const char *adc_mux_text[] = {  	"DMIC",  }; -static const struct soc_enum adc_enum = -	SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);  static const struct snd_kcontrol_new adcl_mux = -	SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); +	SOC_DAPM_ENUM("ADCL Mux", adc_enum);  static const struct snd_kcontrol_new adcr_mux = -	SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); +	SOC_DAPM_ENUM("ADCR Mux", adc_enum);  static const char *spk_src_text[] = {  	"DAC1L", "DAC1R", "DAC2L", "DAC2R"  }; -static const SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, -				  0, spk_src_text); -static const SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, -				  0, spk_src_text); -static const SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, -				  0, spk_src_text); -static const SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, -				  0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, +			    0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, +			    0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, +			    0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, +			    0, spk_src_text);  static const struct snd_kcontrol_new spk1l_mux =  	SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum); @@ -953,10 +948,8 @@ static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = {  	SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",  		0, WM8995_POWER_MANAGEMENT_3, 10, 0), -	SND_SOC_DAPM_VIRT_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, -		&adcl_mux), -	SND_SOC_DAPM_VIRT_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, -		&adcr_mux), +	SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, &adcl_mux), +	SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),  	SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8995_POWER_MANAGEMENT_3, 5, 0),  	SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8995_POWER_MANAGEMENT_3, 4, 0), @@ -2047,13 +2040,6 @@ static int wm8995_probe(struct snd_soc_codec *codec)  	wm8995 = snd_soc_codec_get_drvdata(codec);  	wm8995->codec = codec; -	codec->control_data = wm8995->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); -		return ret; -	} -  	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++)  		wm8995->supplies[i].supply = wm8995_supply_names[i]; @@ -2293,7 +2279,7 @@ static struct spi_driver wm8995_spi_driver = {  };  #endif -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm8995_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -2350,7 +2336,7 @@ static int __init wm8995_modinit(void)  {  	int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	ret = i2c_add_driver(&wm8995_i2c_driver);  	if (ret) {  		printk(KERN_ERR "Failed to register wm8995 I2C driver: %d\n", @@ -2371,7 +2357,7 @@ module_init(wm8995_modinit);  static void __exit wm8995_exit(void)  { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  	i2c_del_driver(&wm8995_i2c_driver);  #endif  #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 46fe83d2b22..69266332760 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -311,28 +311,28 @@ static const char *sidetone_hpf_text[] = {  	"2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"  }; -static const struct soc_enum sidetone_hpf = -	SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 7, sidetone_hpf_text); +static SOC_ENUM_SINGLE_DECL(sidetone_hpf, +			    WM8996_SIDETONE, 7, sidetone_hpf_text);  static const char *hpf_mode_text[] = {  	"HiFi", "Custom", "Voice"  }; -static const struct soc_enum dsp1tx_hpf_mode = -	SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 3, 3, hpf_mode_text); +static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_mode, +			    WM8996_DSP1_TX_FILTERS, 3, hpf_mode_text); -static const struct soc_enum dsp2tx_hpf_mode = -	SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 3, 3, hpf_mode_text); +static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_mode, +			    WM8996_DSP2_TX_FILTERS, 3, hpf_mode_text);  static const char *hpf_cutoff_text[] = {  	"50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"  }; -static const struct soc_enum dsp1tx_hpf_cutoff = -	SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text); +static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_cutoff, +			    WM8996_DSP1_TX_FILTERS, 0, hpf_cutoff_text); -static const struct soc_enum dsp2tx_hpf_cutoff = -	SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text); +static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_cutoff, +			    WM8996_DSP2_TX_FILTERS, 0, hpf_cutoff_text);  static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)  { @@ -412,7 +412,7 @@ static int wm8996_get_retune_mobile_block(const char *name)  static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,  					 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);  	struct wm8996_pdata *pdata = &wm8996->pdata;  	int block = wm8996_get_retune_mobile_block(kcontrol->id.name); @@ -434,10 +434,12 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,  static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,  					 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);  	int block = wm8996_get_retune_mobile_block(kcontrol->id.name); +	if (block < 0) +		return block;  	ucontrol->value.enumerated.item[0] = wm8996->retune_mobile_cfg[block];  	return 0; @@ -608,7 +610,7 @@ static int bg_event(struct snd_soc_dapm_widget *w,  		wm8996_bg_disable(codec);  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		ret = -EINVAL;  	} @@ -625,7 +627,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,  		msleep(5);  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		ret = -EINVAL;  	} @@ -646,7 +648,7 @@ static int rmv_short_event(struct snd_soc_dapm_widget *w,  		wm8996->hpout_pending |= w->shift;  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		return -EINVAL;  	} @@ -767,7 +769,7 @@ static int dcs_start(struct snd_soc_dapm_widget *w,  		wm8996->dcs_pending |= 1 << w->shift;  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		return -EINVAL;  	} @@ -778,14 +780,14 @@ static const char *sidetone_text[] = {  	"IN1", "IN2",  }; -static const struct soc_enum left_sidetone_enum = -	SOC_ENUM_SINGLE(WM8996_SIDETONE, 0, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(left_sidetone_enum, +			    WM8996_SIDETONE, 0, sidetone_text);  static const struct snd_kcontrol_new left_sidetone =  	SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum); -static const struct soc_enum right_sidetone_enum = -	SOC_ENUM_SINGLE(WM8996_SIDETONE, 1, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(right_sidetone_enum, +			    WM8996_SIDETONE, 1, sidetone_text);  static const struct snd_kcontrol_new right_sidetone =  	SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum); @@ -794,14 +796,14 @@ static const char *spk_text[] = {  	"DAC1L", "DAC1R", "DAC2L", "DAC2R"  }; -static const struct soc_enum spkl_enum = -	SOC_ENUM_SINGLE(WM8996_LEFT_PDM_SPEAKER, 0, 4, spk_text); +static SOC_ENUM_SINGLE_DECL(spkl_enum, +			    WM8996_LEFT_PDM_SPEAKER, 0, spk_text);  static const struct snd_kcontrol_new spkl_mux =  	SOC_DAPM_ENUM("SPKL", spkl_enum); -static const struct soc_enum spkr_enum = -	SOC_ENUM_SINGLE(WM8996_RIGHT_PDM_SPEAKER, 0, 4, spk_text); +static SOC_ENUM_SINGLE_DECL(spkr_enum, +			    WM8996_RIGHT_PDM_SPEAKER, 0, spk_text);  static const struct snd_kcontrol_new spkr_mux =  	SOC_DAPM_ENUM("SPKR", spkr_enum); @@ -810,8 +812,8 @@ static const char *dsp1rx_text[] = {  	"AIF1", "AIF2"  }; -static const struct soc_enum dsp1rx_enum = -	SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text); +static SOC_ENUM_SINGLE_DECL(dsp1rx_enum, +			    WM8996_POWER_MANAGEMENT_8, 0, dsp1rx_text);  static const struct snd_kcontrol_new dsp1rx =  	SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum); @@ -820,8 +822,8 @@ static const char *dsp2rx_text[] = {  	 "AIF2", "AIF1"  }; -static const struct soc_enum dsp2rx_enum = -	SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text); +static SOC_ENUM_SINGLE_DECL(dsp2rx_enum, +			    WM8996_POWER_MANAGEMENT_8, 4, dsp2rx_text);  static const struct snd_kcontrol_new dsp2rx =  	SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum); @@ -830,8 +832,8 @@ static const char *aif2tx_text[] = {  	"DSP2", "DSP1", "AIF1"  }; -static const struct soc_enum aif2tx_enum = -	SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 6, 3, aif2tx_text); +static SOC_ENUM_SINGLE_DECL(aif2tx_enum, +			    WM8996_POWER_MANAGEMENT_8, 6, aif2tx_text);  static const struct snd_kcontrol_new aif2tx =  	SOC_DAPM_ENUM("AIF2TX", aif2tx_enum); @@ -840,14 +842,14 @@ static const char *inmux_text[] = {  	"ADC", "DMIC1", "DMIC2"  }; -static const struct soc_enum in1_enum = -	SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 0, 3, inmux_text); +static SOC_ENUM_SINGLE_DECL(in1_enum, +			    WM8996_POWER_MANAGEMENT_7, 0, inmux_text);  static const struct snd_kcontrol_new in1_mux =  	SOC_DAPM_ENUM("IN1 Mux", in1_enum); -static const struct soc_enum in2_enum = -	SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 4, 3, inmux_text); +static SOC_ENUM_SINGLE_DECL(in2_enum, +			    WM8996_POWER_MANAGEMENT_7, 4, inmux_text);  static const struct snd_kcontrol_new in2_mux =  	SOC_DAPM_ENUM("IN2 Mux", in2_enum); @@ -1606,8 +1608,8 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,  				msleep(5);  			} -			regcache_cache_only(codec->control_data, false); -			regcache_sync(codec->control_data); +			regcache_cache_only(wm8996->regmap, false); +			regcache_sync(wm8996->regmap);  		}  		/* Bypass the MICBIASes for lowest power */ @@ -1618,10 +1620,10 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_OFF: -		regcache_cache_only(codec->control_data, true); +		regcache_cache_only(wm8996->regmap, true);  		if (wm8996->pdata.ldo_ena >= 0) {  			gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); -			regcache_cache_only(codec->control_data, true); +			regcache_cache_only(wm8996->regmap, true);  		}  		regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),  				       wm8996->supplies); @@ -1656,7 +1658,7 @@ static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  		lrclk_rx_reg = WM8996_AIF2_RX_LRCLK_2;  		break;  	default: -		BUG(); +		WARN(1, "Invalid dai id %d\n", dai->id);  		return -EINVAL;  	} @@ -1768,7 +1770,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,  		dsp_shift = WM8996_DSP2_DIV_SHIFT;  		break;  	default: -		BUG(); +		WARN(1, "Invalid dai id %d\n", dai->id);  		return -EINVAL;  	} @@ -2249,6 +2251,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,  		  wm8996_polarity_fn polarity_cb)  {  	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = &codec->dapm;  	wm8996->jack = jack;  	wm8996->detecting = true; @@ -2265,8 +2268,12 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,  			    WM8996_MICB2_DISCH, 0);  	/* LDO2 powers the microphones, SYSCLK clocks detection */ -	snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); -	snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); +	snd_soc_dapm_mutex_lock(dapm); + +	snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); +	snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); + +	snd_soc_dapm_mutex_unlock(dapm);  	/* We start off just enabling microphone detection - even a  	 * plain headphone will trigger detection. @@ -2593,7 +2600,7 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)  	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",  		wm8996->num_retune_mobile_texts); -	wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts; +	wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts;  	wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;  	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); @@ -2626,14 +2633,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)  	init_completion(&wm8996->dcs_done);  	init_completion(&wm8996->fll_lock); -	codec->control_data = wm8996->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		goto err; -	} -  	if (wm8996->pdata.num_retune_mobile_cfgs)  		wm8996_retune_mobile_pdata(codec);  	else @@ -2672,13 +2671,11 @@ static int wm8996_probe(struct snd_soc_codec *codec)  		} else {  			dev_err(codec->dev, "Failed to request IRQ: %d\n",  				ret); +			return ret;  		}  	}  	return 0; - -err: -	return ret;  }  static int wm8996_remove(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 6ec3de3efa4..bb9b47b956a 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -86,7 +86,7 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,  {  	struct snd_soc_codec *codec = w->codec;  	struct arizona *arizona = dev_get_drvdata(codec->dev->parent); -	struct regmap *regmap = codec->control_data; +	struct regmap *regmap = arizona->regmap;  	const struct reg_default *patch = NULL;  	int i, patch_size; @@ -103,8 +103,8 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,  	case SND_SOC_DAPM_POST_PMU:  		if (patch)  			for (i = 0; i < patch_size; i++) -				regmap_write(regmap, patch[i].reg, -					     patch[i].def); +				regmap_write_async(regmap, patch[i].reg, +						   patch[i].def);  		break;  	default:  		break; @@ -123,10 +123,12 @@ static const unsigned int wm8997_osr_val[] = {  static const struct soc_enum wm8997_hpout_osr[] = {  	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, -			      ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, +			      ARIZONA_OUT1_OSR_SHIFT, 0x7, +			      ARRAY_SIZE(wm8997_osr_text),  			      wm8997_osr_text, wm8997_osr_val),  	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, -			      ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, +			      ARIZONA_OUT3_OSR_SHIFT, 0x7, +			      ARRAY_SIZE(wm8997_osr_text),  			      wm8997_osr_text, wm8997_osr_val),  }; @@ -170,15 +172,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, -		   ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, -		   ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, -		   ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, -		   ARIZONA_EQ4_ENA_MASK), - +SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), +SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -190,6 +185,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), +SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -201,6 +198,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), +SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -212,6 +211,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,  SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,  	       24, 0, eq_tlv), +SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), +SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),  SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,  	       24, 0, eq_tlv),  SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, @@ -244,8 +245,8 @@ SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),  SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),  SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),  ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -285,8 +286,8 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,  		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,  		 0xbf, 0, digital_tlv), -SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]), -SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]), +SOC_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]), +SOC_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),  SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),  SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), @@ -404,7 +405,7 @@ static const struct soc_enum wm8997_aec_loopback =  			      wm8997_aec_loopback_values);  static const struct snd_kcontrol_new wm8997_aec_loopback_mux = -	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback); +	SOC_DAPM_ENUM("AEC Loopback", wm8997_aec_loopback);  static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -603,7 +604,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,  		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,  		    ARIZONA_SLIMRX8_ENA_SHIFT, 0), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,  		       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,  		       &wm8997_aec_loopback_mux), @@ -887,7 +888,7 @@ static const struct snd_soc_dapm_route wm8997_dapm_routes[] = {  	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),  	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), -	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC2INT2"), +	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),  	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),  	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), @@ -1050,13 +1051,6 @@ static struct snd_soc_dai_driver wm8997_dai[] = {  static int wm8997_codec_probe(struct snd_soc_codec *codec)  {  	struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = priv->core.arizona->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); -	if (ret != 0) -		return ret;  	arizona_init_spk(codec); @@ -1087,9 +1081,17 @@ static unsigned int wm8997_digital_vu[] = {  	ARIZONA_DAC_DIGITAL_VOLUME_5R,  }; +static struct regmap *wm8997_get_regmap(struct device *dev) +{ +	struct wm8997_priv *priv = dev_get_drvdata(dev); + +	return priv->core.arizona->regmap; +} +  static struct snd_soc_codec_driver soc_codec_dev_wm8997 = {  	.probe = wm8997_codec_probe,  	.remove = wm8997_codec_remove, +	.get_regmap =   wm8997_get_regmap,  	.idle_bias_off = true, diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 630b3d776ec..185eb97769e 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -268,8 +268,7 @@ static const char *drc_high_text[] = {  	"0",  }; -static const struct soc_enum drc_high = -	SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text); +static SOC_ENUM_SINGLE_DECL(drc_high, WM9081_DRC_3, 3, drc_high_text);  static const char *drc_low_text[] = {  	"1", @@ -279,8 +278,7 @@ static const char *drc_low_text[] = {  	"0",  }; -static const struct soc_enum drc_low = -	SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text); +static SOC_ENUM_SINGLE_DECL(drc_low, WM9081_DRC_3, 0, drc_low_text);  static const char *drc_atk_text[] = {  	"181us", @@ -297,8 +295,7 @@ static const char *drc_atk_text[] = {  	"185.6ms",  }; -static const struct soc_enum drc_atk = -	SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text); +static SOC_ENUM_SINGLE_DECL(drc_atk, WM9081_DRC_2, 12, drc_atk_text);  static const char *drc_dcy_text[] = {  	"186ms", @@ -312,8 +309,7 @@ static const char *drc_dcy_text[] = {  	"47.56s",  }; -static const struct soc_enum drc_dcy = -	SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text); +static SOC_ENUM_SINGLE_DECL(drc_dcy, WM9081_DRC_2, 8, drc_dcy_text);  static const char *drc_qr_dcy_text[] = {  	"0.725ms", @@ -321,8 +317,7 @@ static const char *drc_qr_dcy_text[] = {  	"5.8ms",  }; -static const struct soc_enum drc_qr_dcy = -	SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text); +static SOC_ENUM_SINGLE_DECL(drc_qr_dcy, WM9081_DRC_2, 4, drc_qr_dcy_text);  static const char *dac_deemph_text[] = {  	"None", @@ -331,21 +326,21 @@ static const char *dac_deemph_text[] = {  	"48kHz",  }; -static const struct soc_enum dac_deemph = -	SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text); +static SOC_ENUM_SINGLE_DECL(dac_deemph, WM9081_DAC_DIGITAL_2, 1, +			    dac_deemph_text);  static const char *speaker_mode_text[] = {  	"Class D",  	"Class AB",  }; -static const struct soc_enum speaker_mode = -	SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text); +static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6, +			    speaker_mode_text);  static int speaker_mode_get(struct snd_kcontrol *kcontrol,  			    struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg;  	reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); @@ -366,7 +361,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol,  static int speaker_mode_put(struct snd_kcontrol *kcontrol,  			    struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);  	unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); @@ -1265,15 +1260,6 @@ static struct snd_soc_dai_driver wm9081_dai = {  static int wm9081_probe(struct snd_soc_codec *codec)  {  	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); -	int ret; - -	codec->control_data = wm9081->regmap; - -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	}  	/* Enable zero cross by default */  	snd_soc_update_bits(codec, WM9081_ANALOGUE_LINEOUT, @@ -1288,7 +1274,7 @@ static int wm9081_probe(struct snd_soc_codec *codec)  				     ARRAY_SIZE(wm9081_eq_controls));  	} -	return ret; +	return 0;  }  static int wm9081_remove(struct snd_soc_codec *codec) @@ -1326,7 +1312,7 @@ static const struct regmap_config wm9081_regmap = {  	.cache_type = REGCACHE_RBTREE,  }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C)  static int wm9081_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index a07fe1618ee..87934171f06 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -522,16 +522,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,  static int wm9090_probe(struct snd_soc_codec *codec)  { -	struct wm9090_priv *wm9090 = dev_get_drvdata(codec->dev); -	int ret; - -	codec->control_data = wm9090->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} -  	/* Configure some defaults; they will be written out when we  	 * bring the bias up.  	 */ diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 70ce6793c5b..c0b7f45dfa3 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -67,12 +67,12 @@ static const char *wm9705_mic[] = {"Mic 1", "Mic 2"};  static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC",  	"Line", "Stereo Mix", "Mono Mix", "Phone"}; -static const struct soc_enum wm9705_enum_mic = -	SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic); -static const struct soc_enum wm9705_enum_rec_l = -	SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel); -static const struct soc_enum wm9705_enum_rec_r = -	SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel); +static SOC_ENUM_SINGLE_DECL(wm9705_enum_mic, +			    AC97_GENERAL_PURPOSE, 8, wm9705_mic); +static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_l, +			    AC97_REC_SEL, 8, wm9705_rec_sel); +static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_r, +			    AC97_REC_SEL, 0, wm9705_rec_sel);  /* Headphone Mixer */  static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = { diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index a53e175c015..2a9c6d11330 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -74,8 +74,7 @@ static const char *wm9713_rec_src[] =  	"Mono Out", "Zh"};  static const char *wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};  static const char *wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"}; -static const char *wm9713_mono_pga[] = {"Vmid", "Zh", "Mono", "Inv", -	"Mono Vmid", "Inv Vmid"}; +static const char *wm9713_mono_pga[] = {"Vmid", "Zh", "Mono", "Inv"};  static const char *wm9713_spk_pga[] =  	{"Vmid", "Zh", "Headphone", "Speaker", "Inv", "Headphone Vmid",  	"Speaker Vmid", "Inv Vmid"}; @@ -221,7 +220,8 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,  	struct snd_soc_codec *codec = w->codec;  	u16 status, rate; -	BUG_ON(event != SND_SOC_DAPM_PRE_PMD); +	if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD)) +		return -EINVAL;  	/* Gracefully shut down the voice interface. */  	status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b38f3506418..060027182dc 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -242,7 +242,7 @@ struct wm_coeff_ctl {  static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;  	struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); @@ -254,7 +254,7 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,  static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,  			  struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;  	struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); @@ -341,6 +341,8 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,  static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,  					  unsigned int offset)  { +	if (WARN_ON(!region)) +		return offset;  	switch (region->type) {  	case WMFW_ADSP1_PM:  		return region->base + (offset * 3); @@ -353,7 +355,7 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,  	case WMFW_ADSP1_ZM:  		return region->base + (offset * 2);  	default: -		WARN_ON(NULL != "Unknown memory region type"); +		WARN(1, "Unknown memory region type");  		return offset;  	}  } @@ -396,11 +398,12 @@ static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,  	ret = regmap_raw_write(adsp->regmap, reg, scratch,  			       ctl->len);  	if (ret) { -		adsp_err(adsp, "Failed to write %zu bytes to %x\n", -			 ctl->len, reg); +		adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n", +			 ctl->len, reg, ret);  		kfree(scratch);  		return ret;  	} +	adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg);  	kfree(scratch); @@ -450,11 +453,12 @@ static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,  	ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len);  	if (ret) { -		adsp_err(adsp, "Failed to read %zu bytes from %x\n", -			 ctl->len, reg); +		adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n", +			 ctl->len, reg, ret);  		kfree(scratch);  		return ret;  	} +	adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg);  	memcpy(buf, scratch, ctl->len);  	kfree(scratch); @@ -568,6 +572,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)  			 file, header->ver);  		goto out_fw;  	} +	adsp_info(dsp, "Firmware version: %d\n", header->ver);  	if (header->core != dsp->type) {  		adsp_err(dsp, "%s: invalid core %d != %d\n", @@ -602,7 +607,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)  		break;  	default: -		BUG_ON(NULL == "Unknown DSP type"); +		WARN(1, "Unknown DSP type");  		goto out_fw;  	} @@ -642,27 +647,22 @@ static int wm_adsp_load(struct wm_adsp *dsp)  			reg = offset;  			break;  		case WMFW_ADSP1_PM: -			BUG_ON(!mem);  			region_name = "PM";  			reg = wm_adsp_region_to_reg(mem, offset);  			break;  		case WMFW_ADSP1_DM: -			BUG_ON(!mem);  			region_name = "DM";  			reg = wm_adsp_region_to_reg(mem, offset);  			break;  		case WMFW_ADSP2_XM: -			BUG_ON(!mem);  			region_name = "XM";  			reg = wm_adsp_region_to_reg(mem, offset);  			break;  		case WMFW_ADSP2_YM: -			BUG_ON(!mem);  			region_name = "YM";  			reg = wm_adsp_region_to_reg(mem, offset);  			break;  		case WMFW_ADSP1_ZM: -			BUG_ON(!mem);  			region_name = "ZM";  			reg = wm_adsp_region_to_reg(mem, offset);  			break; @@ -684,23 +684,38 @@ static int wm_adsp_load(struct wm_adsp *dsp)  		}  		if (reg) { -			buf = wm_adsp_buf_alloc(region->data, -						le32_to_cpu(region->len), -						&buf_list); -			if (!buf) { -				adsp_err(dsp, "Out of memory\n"); -				return -ENOMEM; -			} +			size_t to_write = PAGE_SIZE; +			size_t remain = le32_to_cpu(region->len); +			const u8 *data = region->data; + +			while (remain > 0) { +				if (remain < PAGE_SIZE) +					to_write = remain; + +				buf = wm_adsp_buf_alloc(data, +							to_write, +							&buf_list); +				if (!buf) { +					adsp_err(dsp, "Out of memory\n"); +					ret = -ENOMEM; +					goto out_fw; +				} -			ret = regmap_raw_write_async(regmap, reg, buf->buf, -						     le32_to_cpu(region->len)); -			if (ret != 0) { -				adsp_err(dsp, -					"%s.%d: Failed to write %d bytes at %d in %s: %d\n", -					file, regions, -					le32_to_cpu(region->len), offset, -					region_name, ret); -				goto out_fw; +				ret = regmap_raw_write_async(regmap, reg, +							     buf->buf, +							     to_write); +				if (ret != 0) { +					adsp_err(dsp, +						"%s.%d: Failed to write %zd bytes at %d in %s: %d\n", +						file, regions, +						to_write, offset, +						region_name, ret); +					goto out_fw; +				} + +				data += to_write; +				reg += to_write / 2; +				remain -= to_write;  			}  		} @@ -901,10 +916,8 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)  		break;  	} -	if (mem == NULL) { -		BUG_ON(mem != NULL); +	if (WARN_ON(!mem))  		return -EINVAL; -	}  	switch (dsp->type) {  	case WMFW_ADSP1: @@ -998,7 +1011,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)  		break;  	default: -		BUG_ON(NULL == "Unknown DSP type"); +		WARN(1, "Unknown DSP type");  		return -EINVAL;  	} @@ -1062,6 +1075,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)  			if (i + 1 < algs) {  				region->len = be32_to_cpu(adsp1_alg[i + 1].dm);  				region->len -= be32_to_cpu(adsp1_alg[i].dm); +				region->len *= 4;  				wm_adsp_create_control(dsp, region);  			} else {  				adsp_warn(dsp, "Missing length info for region DM with ID %x\n", @@ -1079,6 +1093,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)  			if (i + 1 < algs) {  				region->len = be32_to_cpu(adsp1_alg[i + 1].zm);  				region->len -= be32_to_cpu(adsp1_alg[i].zm); +				region->len *= 4;  				wm_adsp_create_control(dsp, region);  			} else {  				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", @@ -1108,6 +1123,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)  			if (i + 1 < algs) {  				region->len = be32_to_cpu(adsp2_alg[i + 1].xm);  				region->len -= be32_to_cpu(adsp2_alg[i].xm); +				region->len *= 4;  				wm_adsp_create_control(dsp, region);  			} else {  				adsp_warn(dsp, "Missing length info for region XM with ID %x\n", @@ -1125,6 +1141,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)  			if (i + 1 < algs) {  				region->len = be32_to_cpu(adsp2_alg[i + 1].ym);  				region->len -= be32_to_cpu(adsp2_alg[i].ym); +				region->len *= 4;  				wm_adsp_create_control(dsp, region);  			} else {  				adsp_warn(dsp, "Missing length info for region YM with ID %x\n", @@ -1142,6 +1159,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)  			if (i + 1 < algs) {  				region->len = be32_to_cpu(adsp2_alg[i + 1].zm);  				region->len -= be32_to_cpu(adsp2_alg[i].zm); +				region->len *= 4;  				wm_adsp_create_control(dsp, region);  			} else {  				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", @@ -1282,6 +1300,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)  					reg = wm_adsp_region_to_reg(mem,  								    reg);  					reg += offset; +					break;  				}  			} @@ -1313,8 +1332,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)  						     le32_to_cpu(blk->len));  			if (ret != 0) {  				adsp_err(dsp, -					"%s.%d: Failed to write to %x in %s\n", -					file, blocks, reg, region_name); +					"%s.%d: Failed to write to %x in %s: %d\n", +					file, blocks, reg, region_name, ret);  			}  		} @@ -1358,6 +1377,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,  	struct snd_soc_codec *codec = w->codec;  	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);  	struct wm_adsp *dsp = &dsps[w->shift]; +	struct wm_adsp_alg_region *alg_region;  	struct wm_coeff_ctl *ctl;  	int ret;  	int val; @@ -1435,6 +1455,14 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,  		list_for_each_entry(ctl, &dsp->ctl_list, list)  			ctl->enabled = 0; + +		while (!list_empty(&dsp->alg_regions)) { +			alg_region = list_first_entry(&dsp->alg_regions, +						      struct wm_adsp_alg_region, +						      list); +			list_del(&alg_region->list); +			kfree(alg_region); +		}  		break;  	default: @@ -1455,19 +1483,23 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)  	unsigned int val;  	int ret, count; -	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, -				 ADSP2_SYS_ENA, ADSP2_SYS_ENA); +	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, +				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);  	if (ret != 0)  		return ret;  	/* Wait for the RAM to start, should be near instantaneous */ -	count = 0; -	do { +	for (count = 0; count < 10; ++count) {  		ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,  				  &val);  		if (ret != 0)  			return ret; -	} while (!(val & ADSP2_RAM_RDY) && ++count < 10); + +		if (val & ADSP2_RAM_RDY) +			break; + +		msleep(1); +	}  	if (!(val & ADSP2_RAM_RDY)) {  		adsp_err(dsp, "Failed to start DSP RAM\n"); @@ -1475,112 +1507,153 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)  	}  	adsp_dbg(dsp, "RAM ready after %d polls\n", count); -	adsp_info(dsp, "RAM ready after %d polls\n", count);  	return 0;  } -int wm_adsp2_event(struct snd_soc_dapm_widget *w, -		   struct snd_kcontrol *kcontrol, int event) +static void wm_adsp2_boot_work(struct work_struct *work)  { -	struct snd_soc_codec *codec = w->codec; -	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); -	struct wm_adsp *dsp = &dsps[w->shift]; -	struct wm_adsp_alg_region *alg_region; -	struct wm_coeff_ctl *ctl; -	unsigned int val; +	struct wm_adsp *dsp = container_of(work, +					   struct wm_adsp, +					   boot_work);  	int ret; +	unsigned int val; -	dsp->card = codec->card; +	/* +	 * For simplicity set the DSP clock rate to be the +	 * SYSCLK rate rather than making it configurable. +	 */ +	ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); +	if (ret != 0) { +		adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); +		return; +	} +	val = (val & ARIZONA_SYSCLK_FREQ_MASK) +		>> ARIZONA_SYSCLK_FREQ_SHIFT; -	switch (event) { -	case SND_SOC_DAPM_POST_PMU: -		/* -		 * For simplicity set the DSP clock rate to be the -		 * SYSCLK rate rather than making it configurable. -		 */ -		ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); -		if (ret != 0) { -			adsp_err(dsp, "Failed to read SYSCLK state: %d\n", -				 ret); -			return ret; -		} -		val = (val & ARIZONA_SYSCLK_FREQ_MASK) -			>> ARIZONA_SYSCLK_FREQ_SHIFT; +	ret = regmap_update_bits_async(dsp->regmap, +				       dsp->base + ADSP2_CLOCKING, +				       ADSP2_CLK_SEL_MASK, val); +	if (ret != 0) { +		adsp_err(dsp, "Failed to set clock rate: %d\n", ret); +		return; +	} -		ret = regmap_update_bits(dsp->regmap, -					 dsp->base + ADSP2_CLOCKING, -					 ADSP2_CLK_SEL_MASK, val); +	if (dsp->dvfs) { +		ret = regmap_read(dsp->regmap, +				  dsp->base + ADSP2_CLOCKING, &val);  		if (ret != 0) { -			adsp_err(dsp, "Failed to set clock rate: %d\n", -				 ret); -			return ret; +			adsp_err(dsp, "Failed to read clocking: %d\n", ret); +			return;  		} -		if (dsp->dvfs) { -			ret = regmap_read(dsp->regmap, -					  dsp->base + ADSP2_CLOCKING, &val); +		if ((val & ADSP2_CLK_SEL_MASK) >= 3) { +			ret = regulator_enable(dsp->dvfs);  			if (ret != 0) { -				dev_err(dsp->dev, -					"Failed to read clocking: %d\n", ret); -				return ret; +				adsp_err(dsp, +					 "Failed to enable supply: %d\n", +					 ret); +				return;  			} -			if ((val & ADSP2_CLK_SEL_MASK) >= 3) { -				ret = regulator_enable(dsp->dvfs); -				if (ret != 0) { -					dev_err(dsp->dev, -						"Failed to enable supply: %d\n", -						ret); -					return ret; -				} - -				ret = regulator_set_voltage(dsp->dvfs, -							    1800000, -							    1800000); -				if (ret != 0) { -					dev_err(dsp->dev, -						"Failed to raise supply: %d\n", -						ret); -					return ret; -				} +			ret = regulator_set_voltage(dsp->dvfs, +						    1800000, +						    1800000); +			if (ret != 0) { +				adsp_err(dsp, +					 "Failed to raise supply: %d\n", +					 ret); +				return;  			}  		} +	} -		ret = wm_adsp2_ena(dsp); -		if (ret != 0) -			return ret; +	ret = wm_adsp2_ena(dsp); +	if (ret != 0) +		return; -		ret = wm_adsp_load(dsp); -		if (ret != 0) -			goto err; +	ret = wm_adsp_load(dsp); +	if (ret != 0) +		goto err; -		ret = wm_adsp_setup_algs(dsp); -		if (ret != 0) -			goto err; +	ret = wm_adsp_setup_algs(dsp); +	if (ret != 0) +		goto err; -		ret = wm_adsp_load_coeff(dsp); -		if (ret != 0) -			goto err; +	ret = wm_adsp_load_coeff(dsp); +	if (ret != 0) +		goto err; -		/* Initialize caches for enabled and unset controls */ -		ret = wm_coeff_init_control_caches(dsp); -		if (ret != 0) -			goto err; +	/* Initialize caches for enabled and unset controls */ +	ret = wm_coeff_init_control_caches(dsp); +	if (ret != 0) +		goto err; -		/* Sync set controls */ -		ret = wm_coeff_sync_controls(dsp); -		if (ret != 0) -			goto err; +	/* Sync set controls */ +	ret = wm_coeff_sync_controls(dsp); +	if (ret != 0) +		goto err; + +	ret = regmap_update_bits_async(dsp->regmap, +				       dsp->base + ADSP2_CONTROL, +				       ADSP2_CORE_ENA, +				       ADSP2_CORE_ENA); +	if (ret != 0) +		goto err; + +	dsp->running = true; + +	return; + +err: +	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, +			   ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); +} + +int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, +		   struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); +	struct wm_adsp *dsp = &dsps[w->shift]; + +	dsp->card = codec->card; + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		queue_work(system_unbound_wq, &dsp->boot_work); +		break; +	default: +		break; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_early_event); + +int wm_adsp2_event(struct snd_soc_dapm_widget *w, +		   struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); +	struct wm_adsp *dsp = &dsps[w->shift]; +	struct wm_adsp_alg_region *alg_region; +	struct wm_coeff_ctl *ctl; +	int ret; + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		flush_work(&dsp->boot_work); + +		if (!dsp->running) +			return -EIO;  		ret = regmap_update_bits(dsp->regmap,  					 dsp->base + ADSP2_CONTROL, -					 ADSP2_CORE_ENA | ADSP2_START, -					 ADSP2_CORE_ENA | ADSP2_START); +					 ADSP2_START, +					 ADSP2_START);  		if (ret != 0)  			goto err; - -		dsp->running = true;  		break;  	case SND_SOC_DAPM_PRE_PMD: @@ -1599,15 +1672,15 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,  			ret = regulator_set_voltage(dsp->dvfs, 1200000,  						    1800000);  			if (ret != 0) -				dev_warn(dsp->dev, -					 "Failed to lower supply: %d\n", -					 ret); +				adsp_warn(dsp, +					  "Failed to lower supply: %d\n", +					  ret);  			ret = regulator_disable(dsp->dvfs);  			if (ret != 0) -				dev_err(dsp->dev, -					"Failed to enable supply: %d\n", -					ret); +				adsp_err(dsp, +					 "Failed to enable supply: %d\n", +					 ret);  		}  		list_for_each_entry(ctl, &dsp->ctl_list, list) @@ -1620,6 +1693,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,  			list_del(&alg_region->list);  			kfree(alg_region);  		} + +		adsp_dbg(dsp, "Shutdown complete\n");  		break;  	default: @@ -1651,33 +1726,31 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)  	INIT_LIST_HEAD(&adsp->alg_regions);  	INIT_LIST_HEAD(&adsp->ctl_list); +	INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work);  	if (dvfs) {  		adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");  		if (IS_ERR(adsp->dvfs)) {  			ret = PTR_ERR(adsp->dvfs); -			dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); +			adsp_err(adsp, "Failed to get DCVDD: %d\n", ret);  			return ret;  		}  		ret = regulator_enable(adsp->dvfs);  		if (ret != 0) { -			dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", -				ret); +			adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret);  			return ret;  		}  		ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);  		if (ret != 0) { -			dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", -				ret); +			adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret);  			return ret;  		}  		ret = regulator_disable(adsp->dvfs);  		if (ret != 0) { -			dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", -				ret); +			adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret);  			return ret;  		}  	} diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index d018dea6254..a4f6b64deb6 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -59,6 +59,8 @@ struct wm_adsp {  	struct regulator *dvfs;  	struct list_head ctl_list; + +	struct work_struct boot_work;  };  #define WM_ADSP1(wname, num) \ @@ -66,8 +68,12 @@ struct wm_adsp {  		wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)  #define WM_ADSP2(wname, num) \ -	SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ -		wm_adsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) +{	.id = snd_soc_dapm_dai_link, .name = wname " Preloader", \ +	.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \ +	.event_flags = SND_SOC_DAPM_PRE_PMU }, \ +{	.id = snd_soc_dapm_out_drv, .name = wname, \ +	.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ +	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }  extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];  extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; @@ -76,6 +82,8 @@ int wm_adsp1_init(struct wm_adsp *adsp);  int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);  int wm_adsp1_event(struct snd_soc_dapm_widget *w,  		   struct snd_kcontrol *kcontrol, int event); +int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, +			 struct snd_kcontrol *kcontrol, int event);  int wm_adsp2_event(struct snd_soc_dapm_widget *w,  		   struct snd_kcontrol *kcontrol, int event); diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 8b50e5958de..916817fe663 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -50,16 +50,16 @@ static const char *speaker_ref_text[] = {  	"VMID",  }; -static const struct soc_enum speaker_ref = -	SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text); +static SOC_ENUM_SINGLE_DECL(speaker_ref, +			    WM8993_SPEAKER_MIXER, 8, speaker_ref_text);  static const char *speaker_mode_text[] = {  	"Class D",  	"Class AB",  }; -static const struct soc_enum speaker_mode = -	SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text); +static SOC_ENUM_SINGLE_DECL(speaker_mode, +			    WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);  static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)  { @@ -337,7 +337,7 @@ static void enable_dc_servo(struct snd_soc_codec *codec)  static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,  			       struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);  	int ret; @@ -530,6 +530,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,  				hubs->hp_startup_mode);  			break;  		} +		break;  	case SND_SOC_DAPM_PRE_PMD:  		snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, @@ -610,7 +611,7 @@ static int earpiece_event(struct snd_soc_dapm_widget *w,  		break;  	default: -		BUG(); +		WARN(1, "Invalid event %d\n", event);  		break;  	} @@ -734,15 +735,15 @@ static const char *hp_mux_text[] = {  	"DAC",  }; -static const struct soc_enum hpl_enum = -	SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text); +static SOC_ENUM_SINGLE_DECL(hpl_enum, +			    WM8993_OUTPUT_MIXER1, 8, hp_mux_text);  const struct snd_kcontrol_new wm_hubs_hpl_mux =  	WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);  EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux); -static const struct soc_enum hpr_enum = -	SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text); +static SOC_ENUM_SINGLE_DECL(hpr_enum, +			    WM8993_OUTPUT_MIXER2, 8, hp_mux_text);  const struct snd_kcontrol_new wm_hubs_hpr_mux =  	WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);  | 
