Просмотр исходного кода

Merge remote-tracking branches 'asoc/topic/88pm860x', 'asoc/topic/ad1836', 'asoc/topic/ad193x', 'asoc/topic/adau1977', 'asoc/topic/ak4104', 'asoc/topic/ak4641', 'asoc/topic/ak4671' and 'asoc/topic/alc5623' into asoc-next

Mark Brown 11 лет назад

+ 45 - 0
include/linux/platform_data/adau1977.h

@@ -0,0 +1,45 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__
+#define __LINUX_PLATFORM_DATA_ADAU1977_H__
+
+/**
+ * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting
+ * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V
+ * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V
+ * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V
+ * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V
+ * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V
+ * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V
+ * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V
+ * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V
+ * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V
+ */
+enum adau1977_micbias {
+	ADAU1977_MICBIAS_5V0 = 0x0,
+	ADAU1977_MICBIAS_5V5 = 0x1,
+	ADAU1977_MICBIAS_6V0 = 0x2,
+	ADAU1977_MICBIAS_6V5 = 0x3,
+	ADAU1977_MICBIAS_7V0 = 0x4,
+	ADAU1977_MICBIAS_7V5 = 0x5,
+	ADAU1977_MICBIAS_8V0 = 0x6,
+	ADAU1977_MICBIAS_8V5 = 0x7,
+	ADAU1977_MICBIAS_9V0 = 0x8,
+};
+
+/**
+ * struct adau1977_platform_data - Platform configuration data for the ADAU1977
+ * @micbias: Specifies the voltage for the MICBIAS pin
+ */
+struct adau1977_platform_data {
+	enum adau1977_micbias micbias;
+};
+
+#endif

+ 1 - 0
sound/core/pcm_lib.c

@@ -1242,6 +1242,7 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
 		return -EINVAL;
 	return 0;
 }
+EXPORT_SYMBOL(snd_pcm_hw_constraint_mask64);
 
 /**
  * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval

+ 4 - 2
sound/soc/blackfin/Kconfig

@@ -46,7 +46,8 @@ config SND_SOC_BFIN_EVAL_ADAV80X
 	tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
 	depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
 	select SND_BF5XX_SOC_I2S
-	select SND_SOC_ADAV80X
+	select SND_SOC_ADAV801 if SPI_MASTER
+	select SND_SOC_ADAV803 if I2C
 	help
 	  Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
 	  EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
@@ -67,7 +68,8 @@ config SND_BF5XX_SOC_AD193X
 	tristate "SoC AD193X Audio support for Blackfin"
 	depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
 	select SND_BF5XX_SOC_I2S
-	select SND_SOC_AD193X
+	select SND_SOC_AD193X_I2C if I2C
+	select SND_SOC_AD193X_SPI if SPI_MASTER
 	help
 	  Say Y if you want to add support for AD193X codec on Blackfin.
 	  This driver supports AD1936, AD1937, AD1938 and AD1939.

+ 58 - 58
sound/soc/codecs/88pm860x-codec.c

@@ -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);

+ 103 - 36
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,20 @@ 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_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
@@ -184,6 +191,14 @@ 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
 
@@ -191,41 +206,66 @@ config SND_SOC_AD73311
 	tristate
 
 config SND_SOC_ADAU1701
+	tristate "Analog Devices ADAU1701 CODEC"
+	depends on I2C
 	select SND_SOC_SIGMADSP
-	tristate
 
 config SND_SOC_ADAU1373
 	tristate
 
+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
+
 config SND_SOC_ALC5632
 	tristate
 
@@ -236,14 +276,17 @@ config SND_SOC_CS42L51
 	tristate
 
 config SND_SOC_CS42L52
-	tristate
+	tristate "Cirrus Logic CS42L52 CODEC"
+	depends on I2C
 
 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
@@ -254,7 +297,8 @@ config SND_SOC_CS4270_VD33_ERRATA
 	depends on SND_SOC_CS4270
 
 config SND_SOC_CS4271
-	tristate
+	tristate "Cirrus Logic CS4271 CODEC"
+	depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_CX20442
 	tristate
@@ -285,6 +329,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
 
@@ -303,14 +350,13 @@ 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
@@ -338,7 +384,8 @@ config SND_SOC_RT5640
 
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
-	tristate
+	tristate "Freescale SGTL5000 CODEC"
+	depends on I2C
 
 config SND_SOC_SI476X
 	tristate
@@ -351,7 +398,7 @@ config SND_SOC_SN95031
 	tristate
 
 config SND_SOC_SPDIF
-	tristate
+	tristate "S/PDIF CODEC"
 
 config SND_SOC_SSM2518
 	tristate
@@ -369,7 +416,8 @@ config SND_SOC_STAC9766
 	tristate
 
 config SND_SOC_TAS5086
-	tristate
+	tristate "Texas Instruments TAS5086 speaker amplifier"
+	depends on I2C
 
 config SND_SOC_TLV320AIC23
 	tristate
@@ -382,7 +430,8 @@ config SND_SOC_TLV320AIC32X4
 	tristate
 
 config SND_SOC_TLV320AIC3X
-	tristate
+	tristate "Texas Instruments TLV320AIC3x CODECs"
+	depends on I2C
 
 config SND_SOC_TLV320DAC33
 	tristate
@@ -431,55 +480,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
@@ -497,7 +560,8 @@ config SND_SOC_WM8961
 	tristate
 
 config SND_SOC_WM8962
-	tristate
+	tristate "Wolfson Microelectronics WM8962 CODEC"
+	depends on I2C
 
 config SND_SOC_WM8971
 	tristate
@@ -570,4 +634,7 @@ config SND_SOC_ML26124
 	tristate
 
 config SND_SOC_TPA6130A2
-	tristate
+	tristate "Texas Instruments TPA6130A2 headphone amplifier"
+	depends on I2C
+
+endmenu

+ 14 - 0
sound/soc/codecs/Makefile

@@ -3,11 +3,18 @@ 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-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
@@ -137,11 +144,18 @@ 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_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_ADAU1701)  += snd-soc-adau1701.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

+ 2 - 2
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), \

+ 54 - 0
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");

+ 48 - 0
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");

+ 17 - 127
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,7 +319,7 @@ 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;
@@ -352,7 +351,7 @@ static int ad193x_probe(struct snd_soc_codec *codec)
 }
 
 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 +365,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);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
 
-static int ad193x_i2c_probe(struct i2c_client *client,
-			    const struct i2c_device_id *id)
-{
-	struct ad193x_priv *ad193x;
-
-	ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv),
-			      GFP_KERNEL);
+	ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);
 	if (ad193x == NULL)
 		return -ENOMEM;
 
-	ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config);
-	if (IS_ERR(ad193x->regmap))
-		return PTR_ERR(ad193x->regmap);
-
-	i2c_set_clientdata(client, ad193x);
-
-	return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x,
-			&ad193x_dai, 1);
-}
-
-static int ad193x_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
+	ad193x->regmap = regmap;
 
-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);
-
-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>");

+ 7 - 0
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

+ 59 - 0
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");

+ 76 - 0
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");

+ 1018 - 0
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");

+ 37 - 0
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

+ 53 - 0
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");

+ 50 - 0
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");

+ 9 - 122
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"
 
@@ -869,39 +867,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;
 }
+EXPORT_SYMBOL_GPL(adav80x_bus_probe);
 
-static int adav80x_bus_remove(struct device *dev)
-{
-	snd_soc_unregister_codec(dev);
-	kfree(dev_get_drvdata(dev));
-	return 0;
-}
-
-#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,
@@ -913,105 +898,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>");

+ 7 - 0
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,

+ 0 - 2
sound/soc/codecs/ak4104.c

@@ -174,8 +174,6 @@ 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;
-
 	/* set power-up and non-reset bits */
 	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
 				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,

+ 8 - 8
sound/soc/codecs/ak4641.c

@@ -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),

+ 119 - 121
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,18 +613,14 @@ 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);
+	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;
 	}
 
-	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;
@@ -646,28 +636,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);

+ 0 - 2
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 */

+ 67 - 50
sound/soc/codecs/alc5623.c

@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -38,26 +39,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 +216,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 +331,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 +863,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);
 
@@ -900,14 +904,14 @@ static int alc5623_probe(struct snd_soc_codec *codec)
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type);
+	codec->control_data = alc5623->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;
 	}
 
 	alc5623_reset(codec);
-	alc5623_fill_cache(codec);
 
 	/* power on device */
 	alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -980,9 +984,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,19 +1006,32 @@ static int alc5623_i2c_probe(struct i2c_client *client,
 {
 	struct alc5623_platform_data *pdata;
 	struct alc5623_priv *alc5623;
-	int ret, vid1, vid2;
+	unsigned int vid1, vid2;
+	int ret;
 
-	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;
 	}
 
 	if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
@@ -1021,11 +1044,6 @@ 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;
@@ -1048,7 +1066,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);

+ 24 - 16
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);