diff options
Diffstat (limited to 'sound/soc/codecs')
173 files changed, 28919 insertions, 3882 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 75d0ad5d2dc..3c4b10ff48c 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -276,7 +276,7 @@ static int snd_soc_get_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 val[2], val2[2], i; @@ -300,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; @@ -333,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; @@ -353,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; @@ -448,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, @@ -561,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); @@ -572,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); @@ -583,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); @@ -594,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); @@ -605,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); @@ -616,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); @@ -627,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); @@ -638,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); @@ -677,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); @@ -709,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); @@ -720,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); @@ -1327,8 +1327,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x->codec = codec; - codec->control_data = pm860x->regmap; - for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, pm860x_codec_handler, IRQF_ONESHOT, @@ -1360,10 +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, .set_bias_level = pm860x_set_bias_level, + .get_regmap = pm860x_get_regmap, .controls = pm860x_snd_controls, .num_controls = ARRAY_SIZE(pm860x_snd_controls), diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 983d087aa92..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 @@ -182,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 @@ -233,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 @@ -252,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 @@ -283,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 @@ -301,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 @@ -330,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 @@ -342,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 @@ -352,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 @@ -414,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 @@ -480,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 @@ -553,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 1ad92cbf0b2..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,7 +1221,7 @@ 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; @@ -1306,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; @@ -1322,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; diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 77f45986857..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), \ 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 5a42dca535b..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); @@ -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); -} - -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 IS_ENABLED(CONFIG_I2C) - -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; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - 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 IS_ENABLED(CONFIG_I2C) - 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 IS_ENABLED(CONFIG_I2C) - 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 eb836ed5271..1ff7d4d027e 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -345,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[] = { @@ -362,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[] = { @@ -388,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[] = { @@ -409,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[] = { @@ -427,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[] = { @@ -519,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, @@ -576,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), @@ -694,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), @@ -1376,15 +1375,8 @@ static int adau1373_probe(struct snd_soc_codec *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, 0, 0, SND_SOC_REGMAP); - 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; 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 f78b27a7c46..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" @@ -174,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), @@ -317,7 +315,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec) 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]; @@ -332,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; @@ -541,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) { @@ -573,7 +572,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, iclk_ctrl2); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync(dapm); } } else { unsigned int mask; @@ -600,17 +599,21 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, 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; @@ -722,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, @@ -735,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; } @@ -798,15 +801,8 @@ 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, 0, 0, SND_SOC_REGMAP); - 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"); @@ -864,39 +860,26 @@ 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, struct regmap *regmap) +int adav80x_bus_probe(struct device *dev, struct regmap *regmap) { struct adav80x *adav80x; - int ret; if (IS_ERR(regmap)) return PTR_ERR(regmap); - adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); + adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL); if (!adav80x) return -ENOMEM; - dev_set_drvdata(dev, adav80x); 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 regmap_config adav80x_spi_regmap_config = { +const struct regmap_config adav80x_regmap_config = { .val_bits = 8, .pad_bits = 1, .reg_bits = 7, @@ -908,105 +891,7 @@ static const struct regmap_config adav80x_spi_regmap_config = { .reg_defaults = adav80x_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), }; - -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, - devm_regmap_init_spi(spi, &adav80x_spi_regmap_config)); -} - -static int adav80x_spi_remove(struct spi_device *spi) -{ - return adav80x_bus_remove(&spi->dev); -} - -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, -}; -#endif - -#if IS_ENABLED(CONFIG_I2C) -static const struct regmap_config adav80x_i2c_regmap_config = { - .val_bits = 8, - .pad_bits = 1, - .reg_bits = 7, - - .max_register = ADAV80X_PLL_OUTE, - - .cache_type = REGCACHE_RBTREE, - .reg_defaults = adav80x_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), -}; - -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, - devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config)); -} - -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 IS_ENABLED(CONFIG_I2C) - 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 IS_ENABLED(CONFIG_I2C) - 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 b4819dcd4f4..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 @@ -47,6 +48,7 @@ struct ak4104_private { struct regmap *regmap; + struct regulator *regulator; }; static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { @@ -174,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) @@ -198,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), @@ -241,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); 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 94cbe508dd3..7afe8f48208 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -74,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]; @@ -89,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; @@ -113,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), @@ -519,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_REGMAP); - 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); diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 1f646c6e90c..3ba4c0f1141 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -98,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 */ @@ -134,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) * @@ -148,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 = @@ -287,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: @@ -308,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; @@ -465,14 +494,6 @@ static int ak4642_resume(struct snd_soc_codec *codec) static int ak4642_probe(struct snd_soc_codec *codec) { - int ret; - - 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; - } - ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; @@ -513,30 +534,52 @@ static const struct regmap_config ak4648_regmap = { .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, +}; + 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 regmap_config *regmap_config = NULL; + const struct ak4642_drvdata *drvdata = NULL; struct regmap *regmap; + struct ak4642_priv *priv; if (np) { const struct of_device_id *of_id; of_id = of_match_device(ak4642_of_match, &i2c->dev); if (of_id) - regmap_config = of_id->data; + drvdata = of_id->data; } else { - regmap_config = (const struct regmap_config *)id->driver_data; + drvdata = (const struct ak4642_drvdata *)id->driver_data; } - if (!regmap_config) { + if (!drvdata) { dev_err(&i2c->dev, "Unknown device type\n"); return -EINVAL; } - regmap = devm_regmap_init_i2c(i2c, regmap_config); + 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); @@ -551,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 = &ak4642_regmap}, - { .compatible = "asahi-kasei,ak4643", .data = &ak4642_regmap}, - { .compatible = "asahi-kasei,ak4648", .data = &ak4648_regmap}, + { .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)&ak4642_regmap }, - { "ak4643", (kernel_ulong_t)&ak4642_regmap }, - { "ak4648", (kernel_ulong_t)&ak4648_regmap }, + { "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); 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 d3036283482..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); @@ -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 fb001c56cf8..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); @@ -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 e4295fee8f1..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, ...) \ @@ -542,67 +550,76 @@ static const char *arizona_vol_ramp_text[] = { "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" }; -const struct soc_enum arizona_in_hpf_cut_enum = - SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT, - ARRAY_SIZE(arizona_in_hpf_cut_text), - arizona_in_hpf_cut_text); +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[] = { @@ -1377,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; + } - arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); + 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; +} + +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); @@ -1469,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", @@ -1496,14 +1598,18 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); - if (sync) - regmap_update_bits_async(arizona->regmap, base + 0x7, - ARIZONA_FLL1_GAIN_MASK, - cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); - else - regmap_update_bits_async(arizona->regmap, base + 0x9, - ARIZONA_FLL1_GAIN_MASK, - cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + if (sync) { + regmap_update_bits(arizona->regmap, base + 0x7, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + } 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_async(arizona->regmap, base + 2, ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, @@ -1526,13 +1632,12 @@ 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, @@ -1540,23 +1645,21 @@ static void arizona_enable_fll(struct arizona_fll *fll, */ if (fll->ref_src >= 0 && fll->ref_freq && fll->ref_src != fll->sync_src) { - regmap_update_bits_async(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + 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, + 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_async(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_async(arizona->regmap, fll->base + 0x11, @@ -1618,32 +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) { - if (Fref > 0) { - ret = arizona_calc_fll(fll, &ref, 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; - } + if (fll->fout && Fref > 0) { + ret = arizona_validate_fll(fll, Fref, 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; @@ -1653,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 && @@ -1662,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; } @@ -1678,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 16df0f91335..05ae17f5bca 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -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) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 43737a27d79..537327c7f7f 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -138,9 +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->regmap; - - snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP); /* Off, with power on */ cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -155,11 +152,19 @@ 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 = { .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), }; 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 ce05fd93dc7..93cec52f473 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -159,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; @@ -285,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; @@ -295,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]; @@ -540,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; @@ -559,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); @@ -625,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 = { @@ -644,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); @@ -698,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); 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 6e9ea8379a9..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); @@ -503,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 @@ -537,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), @@ -549,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 0bac6d5a4ac..071fc77f2f0 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -50,11 +50,9 @@ struct cs42l52_private { u8 mclksel; u32 mclk; u8 flags; -#if IS_ENABLED(CONFIG_INPUT) struct input_dev *beep; struct work_struct beep_work; int beep_rate; -#endif }; static const struct reg_default cs42l52_reg_defaults[] = { @@ -210,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); @@ -229,26 +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[] = { "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 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); @@ -258,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", @@ -277,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"}; @@ -347,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); @@ -356,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); @@ -365,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); @@ -374,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); @@ -968,7 +960,6 @@ static int cs42l52_resume(struct snd_soc_codec *codec) return 0; } -#if IS_ENABLED(CONFIG_INPUT) static int beep_rates[] = { 261, 522, 585, 667, 706, 774, 889, 1000, 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 @@ -1102,27 +1093,11 @@ 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); @@ -1134,7 +1109,7 @@ static int cs42l52_probe(struct snd_soc_codec *codec) cs42l52->sysclk = CS42L52_DEFAULT_CLK; cs42l52->config.format = CS42L52_DEFAULT_FORMAT; - return ret; + return 0; } static int cs42l52_remove(struct snd_soc_codec *codec) @@ -1242,8 +1217,10 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, } if (cs42l52->pdata.reset_gpio) { - ret = gpio_request_one(cs42l52->pdata.reset_gpio, - GPIOF_OUT_INIT_HIGH, "CS42L52 /RST"); + 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); @@ -1272,7 +1249,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, } dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n", - reg & 0xFF); + reg & CS42L52_CHIP_REV_MASK); /* Set Platform Data */ if (cs42l52->pdata.mica_diff_cfg) diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h index 6fb8f00f419..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 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 549d5d6a3fe..ae3717992d5 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -278,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); @@ -309,9 +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 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"}; @@ -319,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); @@ -337,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); @@ -346,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); @@ -357,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); @@ -1108,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 }; @@ -1241,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, }; @@ -1255,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) @@ -1278,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, @@ -1298,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, @@ -1318,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, @@ -1348,17 +1345,8 @@ 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; - } - cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Set Charge Pump Frequency */ @@ -1371,7 +1359,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec) cs42l73->mclksel = CS42L73_CLKID_MCLK1; cs42l73->mclk = 0; - return ret; + return 0; } static int cs42l73_remove(struct snd_soc_codec *codec) @@ -1455,8 +1443,10 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, cs42l73); if (cs42l73->pdata.reset_gpio) { - ret = gpio_request_one(cs42l73->pdata.reset_gpio, - GPIOF_OUT_INIT_HIGH, "CS42L73 /RST"); + 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); 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 e62e294a803..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]) { @@ -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() */ diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 0c77e7ad742..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); @@ -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 f295b656991..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); @@ -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 52b79a487ac..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; @@ -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 9cb1c7d3e1d..1087fd5f991 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -20,6 +20,7 @@ */ #include <linux/module.h> #include <sound/soc.h> +#include <linux/of.h> #include <linux/of_device.h> #define DRV_NAME "hdmi-audio-codec" diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 5839048ec46..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; @@ -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 ee660e2d3df..9134982807b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -597,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); @@ -626,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]; @@ -650,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; @@ -660,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]; @@ -674,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; @@ -1751,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); @@ -1783,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; @@ -1849,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) @@ -1915,12 +1914,6 @@ static int max98088_probe(struct snd_soc_codec *codec) regcache_mark_dirty(max98088->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; - } - /* initialize private data */ max98088->sysclk = (unsigned)-1; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 51f9b3d16b4..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, @@ -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 3ba1170ebb5..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> @@ -42,6 +43,7 @@ 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; @@ -560,25 +562,27 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai, } 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); @@ -586,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]; @@ -622,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; @@ -632,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]; @@ -646,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; @@ -1391,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).. @@ -1630,6 +1641,19 @@ 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: @@ -1733,7 +1757,7 @@ 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); @@ -1797,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; @@ -1861,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) @@ -1887,7 +1911,7 @@ 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); @@ -1948,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; @@ -2016,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) @@ -2234,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_REGMAP); - 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); @@ -2401,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 82757ebf030..4fdf5aaa236 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -312,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_REGMAP); - 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 */ diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 582c2bbd42c..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> @@ -106,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; @@ -126,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; @@ -408,21 +407,19 @@ 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); @@ -430,8 +427,8 @@ static const struct snd_kcontrol_new samp_ctl = static const char * const speaker_amp_source_text[] = { "CODEC", "Right" }; -static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, - speaker_amp_source_text); +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); @@ -439,8 +436,8 @@ static const char * const headset_amp_source_text[] = { "CODEC", "Mixer" }; -static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, - headset_amp_source_text); +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); @@ -482,9 +479,9 @@ 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, @@ -580,9 +577,9 @@ static struct snd_soc_dapm_route mc13783_routes[] = { 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), @@ -612,14 +609,6 @@ static struct snd_kcontrol_new mc13783_control_list[] = { static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - codec->control_data = dev_get_regmap(codec->dev->parent, NULL); - ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } /* these are the reset values */ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893); @@ -739,9 +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, + .get_regmap = mc13783_get_regmap, .controls = mc13783_control_list, .num_controls = ARRAY_SIZE(mc13783_control_list), .dapm_widgets = mc13783_dapm_widgets, @@ -754,6 +749,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) { struct mc13783_priv *priv; struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -764,7 +760,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) priv->adc_ssi_port = pdata->adc_ssi_port; priv->dac_ssi_port = pdata->dac_ssi_port; } else { - return -ENOSYS; + 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); diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 185fa3bc305..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); @@ -586,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 73f9c3630e2..a722a023c26 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -115,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; @@ -126,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]; @@ -172,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; diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 7146653a8e1..3a80ba4452d 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c @@ -107,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"); 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 a3fb4117963..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,6 +18,7 @@ #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> @@ -30,6 +31,7 @@ #include <sound/initval.h> #include <sound/tlv.h> +#include "rl6231.h" #include "rt5640.h" #define RT5640_DEVICE_ID 0x6231 @@ -59,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 }, @@ -361,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 */ @@ -399,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), @@ -442,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. * @@ -449,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 @@ -481,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; @@ -555,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), @@ -677,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), @@ -708,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), @@ -753,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); @@ -764,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); @@ -776,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); @@ -787,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); @@ -798,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); @@ -809,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); @@ -826,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", @@ -841,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); @@ -860,73 +890,25 @@ 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; -} - static void hp_amp_power_on(struct snd_soc_codec *codec) { struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); @@ -1061,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), @@ -1153,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, @@ -1184,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), @@ -1217,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, @@ -1258,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"}, @@ -1330,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"}, @@ -1403,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"}, @@ -1486,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"}, @@ -1500,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"}, @@ -1530,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; @@ -1583,32 +1626,16 @@ 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; 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 %d for DAI %d\n", rt5640->lrck[dai->id], dai->id); @@ -1630,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: @@ -1752,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; @@ -1771,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 && @@ -1873,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; @@ -1898,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, @@ -1912,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, @@ -1943,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; } @@ -1995,6 +1979,9 @@ static int rt5640_resume(struct snd_soc_codec *codec) msleep(400); } + regcache_cache_only(rt5640->regmap, false); + regcache_sync(rt5640->regmap); + return 0; } #else @@ -2060,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, @@ -2086,13 +2074,25 @@ 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); @@ -2173,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; @@ -2194,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, @@ -2218,6 +2237,7 @@ static struct i2c_driver rt5640_i2c_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, @@ -2225,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 0fcbe90f3ef..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 }, @@ -187,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); @@ -198,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); @@ -294,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; @@ -347,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; @@ -1066,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 @@ -1320,7 +1277,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) return ret; } - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), + ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); if (ret) goto err_ldo_remove; @@ -1328,16 +1285,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) 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); return 0; -err_regulator_free: - regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), - sgtl5000->supplies); err_ldo_remove: if (!external_vddd) ldo_regulator_remove(codec); @@ -1350,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; @@ -1415,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; @@ -1430,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; diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 52e7cb08434..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> @@ -207,12 +208,6 @@ out: return err; } -static int si476x_codec_probe(struct snd_soc_codec *codec) -{ - codec->control_data = dev_get_regmap(codec->dev->parent, NULL); - return 0; -} - static struct snd_soc_dai_ops si476x_dai_ops = { .hw_params = si476x_codec_hw_params, .set_fmt = si476x_codec_set_dai_fmt, @@ -236,8 +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, + .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 13045f2af4d..42dff26b3a2 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -312,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); @@ -328,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); @@ -359,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), @@ -825,8 +825,6 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) { pr_debug("codec_probe called\n"); - snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); - /* PCM interface config * This sets the pcm rx slot conguration to max 6 slots * for max 4 dais (2 stereo and 2 mono) diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index cc8debce752..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[] = { @@ -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 af76bbd1b24..97b0454eb34 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -27,32 +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; + const struct snd_pcm_hw_constraint_list *sysclk_constraints; struct regmap *regmap; @@ -75,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[] = { @@ -197,7 +186,7 @@ static const unsigned int ssm2602_rates_12288000[] = { 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), }; @@ -206,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), }; @@ -529,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; @@ -554,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; @@ -568,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); @@ -597,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; } @@ -620,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, @@ -639,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, @@ -650,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); + if (IS_ERR(regmap)) + return PTR_ERR(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 IS_ENABLED(CONFIG_I2C) -/* - * 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; - - 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 IS_ENABLED(CONFIG_I2C) - 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 IS_ENABLED(CONFIG_I2C) - 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 a895a5e4bdf..d48491a4a19 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -272,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; @@ -283,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]; 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 5d430cc56f5..686b8b85b95 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -23,7 +23,6 @@ #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> @@ -51,7 +50,7 @@ static const struct reg_default tlv320aic23_reg[] = { { 9, 0x0000 }, }; -static const struct regmap_config tlv320aic23_regmap = { +const struct regmap_config tlv320aic23_regmap = { .reg_bits = 7, .val_bits = 9, @@ -60,20 +59,21 @@ static const struct regmap_config tlv320aic23_regmap = { .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); @@ -82,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); @@ -105,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); @@ -400,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); } @@ -557,16 +557,8 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec) return 0; } -static int tlv320aic23_probe(struct snd_soc_codec *codec) +static int tlv320aic23_codec_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; - } - /* Reset codec */ snd_soc_write(codec, TLV320AIC23_RESET, 0); @@ -604,7 +596,7 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { - .probe = tlv320aic23_probe, + .probe = tlv320aic23_codec_probe, .remove = tlv320aic23_remove, .suspend = tlv320aic23_suspend, .resume = tlv320aic23_resume, @@ -617,56 +609,25 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), }; -/* - * 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; - aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); - if (IS_ERR(aic23->regmap)) - return PTR_ERR(aic23->regmap); + aic23->regmap = regmap; - i2c_set_clientdata(i2c, aic23); + dev_set_drvdata(dev, aic23); - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); - return ret; + return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23, + &tlv320aic23_dai, 1); } -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 struct i2c_driver tlv320aic23_i2c_driver = { - .driver = { - .name = "tlv320aic23-codec", - }, - .probe = tlv320aic23_codec_probe, - .remove = __exit_p(tlv320aic23_i2c_remove), - .id_table = tlv320aic23_id, -}; - -module_i2c_driver(tlv320aic23_i2c_driver); +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 94a658fa6d9..43069de3d56 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -238,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 */ @@ -295,8 +296,6 @@ static int aic26_probe(struct snd_soc_codec *codec) struct aic26 *aic26 = dev_get_drvdata(codec->dev); int ret, reg; - snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); - aic26->codec = codec; /* Reset the codec to power on defaults */ 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 688151ba309..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> @@ -66,20 +69,32 @@ struct aic32x4_priv { 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, @@ -90,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), @@ -480,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); @@ -509,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; @@ -586,9 +614,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec) struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); u32 tmp_reg; - snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); - - if (aic32x4->rstn_gpio >= 0) { + if (gpio_is_valid(aic32x4->rstn_gpio)) { ndelay(10); gpio_set_value(aic32x4->rstn_gpio, 1); } @@ -663,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), @@ -686,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; @@ -693,20 +836,44 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->rstn_gpio = -1; } - if (aic32x4->rstn_gpio >= 0) { + 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; } @@ -717,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/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 470fbfb4b38..e12fafbb1e0 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -169,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; @@ -1344,12 +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, 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(aic3x->supplies); i++) { aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; aic3x->disable_nb[i].aic3x = aic3x; @@ -1405,7 +1399,6 @@ static int aic3x_probe(struct snd_soc_codec *codec) } aic3x_add_widgets(codec); - list_add(&aic3x->list, &reset_list); return 0; @@ -1575,7 +1568,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1); - return ret; + + if (ret != 0) + goto err_gpio; + + list_add(&aic3x->list, &reset_list); + + return 0; err_gpio: if (gpio_is_valid(aic3x->gpio_reset) && 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 b27c396037d..8fc5a647453 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -30,6 +30,7 @@ #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" diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 00665ada23e..69e12a311ba 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -415,10 +415,9 @@ 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); @@ -431,10 +430,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = 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); @@ -448,10 +446,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = 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); @@ -460,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); @@ -490,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); @@ -502,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); @@ -836,7 +830,7 @@ static int snd_soc_get_volsw_twl4030(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 shift = mc->shift; unsigned int rshift = mc->rshift; @@ -865,7 +859,7 @@ static int snd_soc_put_volsw_twl4030(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 shift = mc->shift; unsigned int rshift = mc->rshift; @@ -894,7 +888,7 @@ static int snd_soc_get_volsw_r2_twl4030(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; @@ -921,7 +915,7 @@ static int snd_soc_put_volsw_r2_twl4030(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; @@ -955,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, @@ -975,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); } /* @@ -1044,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", @@ -1055,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 */ diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 0afe8bef676..0f6067f04e2 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -81,7 +81,7 @@ struct twl6040_data { }; /* 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, @@ -93,7 +93,7 @@ static unsigned int lp_rates[] = { 96000, }; -static unsigned int hp_rates[] = { +static const unsigned int hp_rates[] = { 8000, 16000, 32000, @@ -101,7 +101,7 @@ 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, }, }; @@ -392,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[] = { @@ -476,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; @@ -494,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; @@ -511,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; @@ -522,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]; 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 726df6d43c2..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 */ 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/wm2000.c b/sound/soc/codecs/wm2000.c index 8ae50274ea8..a4c352cc346 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -607,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; @@ -618,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; @@ -640,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; @@ -651,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; @@ -786,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 4e3e31aaf50..91a9ea2a205 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -390,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); \ @@ -448,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), \ @@ -506,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, @@ -2100,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; @@ -2117,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. @@ -2337,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 ce9c8e14d4b..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; @@ -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 Coefficients", ARIZONA_EQ1_1, 21, - ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, - ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, - ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficients", 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 2c3c962d9a8..2e5fcb559e9 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -136,7 +136,7 @@ static int wm5110_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; @@ -247,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 Coefficients", ARIZONA_EQ1_1, 21, - ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, - ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, - ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficients", 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, @@ -267,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, @@ -278,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, @@ -289,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, @@ -325,13 +324,13 @@ 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_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), -SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), -SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), -SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), -SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1), +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), @@ -368,6 +367,11 @@ SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL, 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, + ARIZONA_OUT6_OSR_SHIFT, 1, 0), + SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), SOC_DOUBLE_R("HPOUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -593,7 +597,7 @@ 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, @@ -775,7 +779,7 @@ SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3, SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3, ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 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, &wm5110_aec_loopback_mux), @@ -1588,13 +1592,8 @@ 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); @@ -1635,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, diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index a183dcf3d5c..392285edb59 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -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 48dc7d2fee3..06e913d3fea 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -93,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; @@ -117,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 */ @@ -422,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); @@ -435,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); @@ -1310,11 +1316,8 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, priv); priv->wm8400 = wm8400; - codec->control_data = wm8400->regmap; priv->codec = codec; - snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); - ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); if (ret != 0) { @@ -1356,11 +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, + .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 7df7d457275..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 */ diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 74d106dc766..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); diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 318989acbbe..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; @@ -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) { diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index d99f948c513..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"); diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index cd89033e84c..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) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 029720366ff..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; @@ -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; } 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 2895c8d3b5e..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"); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 78616a638a5..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); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index be85da93a26..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); 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 ef824672523..70952ceb278 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -430,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); diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 9bc8206a680..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; } 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 e98bc7038a0..d09fdce57f5 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -304,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), @@ -496,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); @@ -1178,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) { 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 53bbfac6a83..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", @@ -858,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); @@ -874,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); @@ -890,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); @@ -991,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); @@ -1019,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); @@ -1981,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); @@ -2022,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); @@ -2047,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: @@ -2063,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 b404c26c175..fc6eec9ad66 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -154,22 +154,22 @@ static const struct reg_default wm8940_reg_defaults[] = { }; 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); @@ -712,12 +712,6 @@ static int wm8940_probe(struct snd_soc_codec *codec) int ret; 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; - } - ret = wm8940_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); 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 b7488f190d2..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)); @@ -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 97db3b45b41..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 IS_ENABLED(CONFIG_INPUT) 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), @@ -2014,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); @@ -2884,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 | @@ -2894,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 */ @@ -2909,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); } @@ -3003,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; @@ -3013,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); @@ -3070,6 +3094,8 @@ static irqreturn_t wm8962_irq(int irq, void *data) msecs_to_jiffies(250)); } + pm_runtime_put(dev); + return IRQ_HANDLED; } @@ -3089,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; @@ -3109,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 IS_ENABLED(CONFIG_INPUT) static int beep_rates[] = { 500, 1000, 2000, 4000, }; @@ -3253,15 +3283,6 @@ 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 wm8962_priv *wm8962, int gpio) { @@ -3400,13 +3421,6 @@ static int wm8962_probe(struct snd_soc_codec *codec) 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; 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 15f45c7bd83..0627c56fa44 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -84,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); @@ -593,12 +593,6 @@ static int wm8974_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 = wm8974_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); 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 271b517911a..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; } diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index a55e1c2c382..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"); diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 0ccd4d8d043..b5c1f0f0705 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -132,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; @@ -157,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 */ @@ -475,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); @@ -488,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); @@ -1292,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_REGMAP); - if (ret < 0) { - printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret); - return ret; - } - wm8990_reset(codec); /* charge output caps */ diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index dba0306c42a..b8fd284fc0c 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -154,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; @@ -171,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 */ @@ -486,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); @@ -499,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); @@ -1251,17 +1248,6 @@ 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, SND_SOC_REGMAP); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); - return ret; - } - wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; 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 b9be9cbc460..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, @@ -4422,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 4300caff178..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]; diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 1a7655b0aa2..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,7 +434,7 @@ 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); @@ -780,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); @@ -796,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); @@ -812,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); @@ -822,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); @@ -832,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); @@ -842,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); @@ -1608,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 */ @@ -1620,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); @@ -2251,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; @@ -2267,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. @@ -2595,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)); @@ -2628,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 @@ -2674,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 555115ee215..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; @@ -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 Coefficients", ARIZONA_EQ1_1, 21, - ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, - ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, - ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficients", 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), @@ -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 0982c1d38ec..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) 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 acea8927905..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"}; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 444626fcab4..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); @@ -684,24 +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"); - ret = -ENOMEM; - goto out_fw; - } + 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; } } @@ -1529,16 +1543,16 @@ static void wm_adsp2_boot_work(struct work_struct *work) ret = regmap_read(dsp->regmap, dsp->base + ADSP2_CLOCKING, &val); if (ret != 0) { - dev_err(dsp->dev, "Failed to read clocking: %d\n", ret); + adsp_err(dsp, "Failed to read clocking: %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); + adsp_err(dsp, + "Failed to enable supply: %d\n", + ret); return; } @@ -1546,9 +1560,9 @@ static void wm_adsp2_boot_work(struct work_struct *work) 1800000, 1800000); if (ret != 0) { - dev_err(dsp->dev, - "Failed to raise supply: %d\n", - ret); + adsp_err(dsp, + "Failed to raise supply: %d\n", + ret); return; } } @@ -1611,7 +1625,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, break; default: break; - }; + } return 0; } @@ -1658,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) @@ -1679,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: @@ -1716,28 +1732,25 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool 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_hubs.c b/sound/soc/codecs/wm_hubs.c index b371066dd5b..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; @@ -735,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); |
