Merge branch 'master' of git://git.denx.de/u-boot-usb

- Second half of the USB Gadget DM conversion
diff --git a/.travis.yml b/.travis.yml
index fe2dfce..321fd79 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -336,6 +336,10 @@
     - name: "Check for configs without MAINTAINERS entry"
       script:
         - if [ `./tools/genboardscfg.py -f 2>&1 | wc -l` -ne 0 ]; then exit 1; fi
+    # Ensure host tools build
+    - name: "Build tools-only"
+      script:
+        - make tools-only_config tools-only -j$(nproc)
 
     # test/py
     - name: "test/py sandbox"
diff --git a/Kconfig b/Kconfig
index 42672a9..9e0b8af4 100644
--- a/Kconfig
+++ b/Kconfig
@@ -126,6 +126,7 @@
 config SYS_MALLOC_F
 	bool "Enable malloc() pool before relocation"
 	default y if DM
+
 	help
 	  Before relocation, memory is very limited on many platforms. Still,
 	  we can provide a small malloc() pool if needed. Driver model in
@@ -136,6 +137,7 @@
 	hex "Size of malloc() pool before relocation"
 	depends on SYS_MALLOC_F
 	default 0x1000 if AM33XX
+	default 0x2800 if SANDBOX
 	default 0x400
 	help
 	  Before relocation, memory is very limited on many platforms. Still,
diff --git a/MAINTAINERS b/MAINTAINERS
index 0cec39c..0fb0898 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -719,5 +719,6 @@
 Q:	http://patchwork.ozlabs.org/project/uboot/list/
 S:	Maintained
 T:	git git://git.denx.de/u-boot.git
+F:	configs/tools-only_defconfig
 F:	*
 F:	*/
diff --git a/Makefile b/Makefile
index 5683714..f69aa06 100644
--- a/Makefile
+++ b/Makefile
@@ -724,8 +724,7 @@
 libs-y += env/
 libs-$(CONFIG_API) += api/
 libs-$(CONFIG_HAS_POST) += post/
-libs-y += test/
-libs-y += test/dm/
+libs-$(CONFIG_UNIT_TEST) += test/ test/dm/
 libs-$(CONFIG_UT_ENV) += test/env/
 libs-$(CONFIG_UT_OVERLAY) += test/overlay/
 
diff --git a/arch/Kconfig b/arch/Kconfig
index 947070f..35e2712 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -116,6 +116,7 @@
 	imply VIRTIO_SANDBOX
 	imply VIRTIO_BLK
 	imply VIRTIO_NET
+	imply DM_SOUND
 
 config SH
 	bool "SuperH architecture"
diff --git a/arch/arm/dts/exynos5250-smdk5250.dts b/arch/arm/dts/exynos5250-smdk5250.dts
index 8b69544..e542a79 100644
--- a/arch/arm/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/dts/exynos5250-smdk5250.dts
@@ -60,9 +60,26 @@
 	};
 
 	i2c@12C70000 {
-		soundcodec@1a {
+		wm8994: soundcodec@1a {
 			reg = <0x1a>;
-			compatible = "wolfson,wm8994-codec";
+			u-boot,i2c-offset-len = <2>;
+			compatible = "wolfson,wm8994";
+			#sound-dai-cells = <1>;
+		};
+	};
+
+	sound {
+		compatible = "google,smdk5250-audio-wm8994";
+
+		samsung,model = "SMDK5250-I2S-WM8994";
+		samsung,audio-codec = <&wm8994>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&wm8994 0>;
 		};
 	};
 
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts
index 29c13c1..7587dc0 100644
--- a/arch/arm/dts/exynos5250-snow.dts
+++ b/arch/arm/dts/exynos5250-snow.dts
@@ -40,7 +40,6 @@
 		mmc3 = "/mmc@12230000";
 		serial0 = "/serial@12C30000";
 		console = "/serial@12C30000";
-		i2s = "/sound@3830000";
 	};
 
         memory {
@@ -88,7 +87,7 @@
 
 		ro-boot {
 			label = "u-boot";
-			reg = <0x6000 0x9a000>;
+			reg = <0x6000 0xb0000>;
 			read-only;
 			type = "blob boot,dtb";
 			required;
@@ -214,9 +213,10 @@
 			};
 		};
 
-		soundcodec@22 {
-			reg = <0x22>;
-			compatible = "maxim,max98095-codec";
+		max98095: codec@11 {
+			compatible = "maxim,max98095";
+			reg = <0x11>;
+			#sound-dai-cells = <1>;
 		};
 	};
 
@@ -273,9 +273,20 @@
 		};
 	};
 
-	sound@3830000 {
-		samsung,codec-type = "max98095";
+	sound {
+		compatible = "google,snow-audio-max98095";
+
+		samsung,model = "Snow-I2S-MAX98095";
+		samsung,audio-codec = <&max98095>;
 		codec-enable-gpio = <&gpx1 7 GPIO_ACTIVE_HIGH>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98095 0>;
+		};
 	};
 
 	sound@12d60000 {
diff --git a/arch/arm/dts/exynos5250-spring.dts b/arch/arm/dts/exynos5250-spring.dts
index 7633d36..191e12a 100644
--- a/arch/arm/dts/exynos5250-spring.dts
+++ b/arch/arm/dts/exynos5250-spring.dts
@@ -34,7 +34,6 @@
 		mmc0 = "/mmc@12200000";
 		serial0 = "/serial@12C30000";
 		console = "/serial@12C30000";
-		i2s = "/sound@3830000";
 	};
 
 	memory {
@@ -639,10 +638,27 @@
 		};
 	};
 
-	soundcodec@20 {
-		reg = <0x20>;
-		compatible = "maxim,max98088-codec";
+	max98095: soundcodec@10 {
+		reg = <0x10>;
+		compatible = "maxim,max98095";
+		#sound-dai-cells = <1>;
 	};
+
+	sound {
+		compatible = "google,spring-audio-max98095";
+
+		samsung,model = "Spring-I2S-MAX98095";
+		samsung,audio-codec = <&max98095>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98095 0>;
+		};
+	};
+
 };
 
 #include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi
index 502c687..66c5b6d 100644
--- a/arch/arm/dts/exynos5250.dtsi
+++ b/arch/arm/dts/exynos5250.dtsi
@@ -78,9 +78,12 @@
 		#size-cells = <0>;
 	};
 
-	sound@3830000 {
-		compatible = "samsung,exynos-sound";
-		reg = <0x3830000 0x50>;
+	i2s0: i2s@3830000 {
+		compatible = "samsung,s5pv210-i2s";
+		reg = <0x03830000 0x100>;
+		samsung,idma-addr = <0x03000000>;
+		#clock-cells = <1>;
+		#sound-dai-cells = <1>;
 		samsung,i2s-epll-clock-frequency = <192000000>;
 		samsung,i2s-sampling-rate = <48000>;
 		samsung,i2s-bits-per-sample = <16>;
@@ -90,9 +93,11 @@
 		samsung,i2s-id = <0>;
 	};
 
-	sound@12d60000 {
-		compatible = "samsung,exynos-sound";
+	i2s1: i2s@12d60000 {
+		compatible = "samsung,s5pv210-i2s";
 		reg = <0x12d60000 0x20>;
+		#clock-cells = <1>;
+		#sound-dai-cells = <1>;
 		samsung,i2s-epll-clock-frequency = <192000000>;
 		samsung,i2s-sampling-rate = <48000>;
 		samsung,i2s-bits-per-sample = <16>;
diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts
index c86f9d9..4a96a18 100644
--- a/arch/arm/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/dts/exynos5420-peach-pit.dts
@@ -67,12 +67,28 @@
 		};
 	};
 
+	sound {
+		compatible = "google,peach-audio-max98090";
+
+		samsung,model = "PEACH-I2S-MAX98090";
+		samsung,audio-codec = <&max98090>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98090 0>;
+		};
+	};
+
 	i2c@12CD0000 { /* i2c7 */
 		clock-frequency = <100000>;
-	       soundcodec@20 {
-	              reg = <0x20>;
-	              compatible = "maxim,max98090-codec";
-	       };
+		max98090: soundcodec@10 {
+			reg = <0x10>;
+			compatible = "maxim,max98090";
+			#sound-dai-cells = <1>;
+		};
 
 		edp-lvds-bridge@48 {
 			compatible = "parade,ps8625";
diff --git a/arch/arm/dts/exynos5420-smdk5420.dts b/arch/arm/dts/exynos5420-smdk5420.dts
index cab5ddb..7a5da67 100644
--- a/arch/arm/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/dts/exynos5420-smdk5420.dts
@@ -82,9 +82,26 @@
 	};
 
 	i2c@12C70000 {
-		soundcodec@1a {
+		wm8994: soundcodec@1a {
 			reg = <0x1a>;
-			compatible = "wolfson,wm8994-codec";
+			u-boot,i2c-offset-len = <2>;
+			compatible = "wolfson,wm8994";
+			#sound-dai-cells = <1>;
+		};
+	};
+
+	sound {
+		compatible = "samsung,smdk5420-audio-wm8994";
+
+		samsung,model = "Snow-I2S-MAX98095";
+		samsung,audio-codec = <&wm8994>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&wm8994 0>;
 		};
 	};
 
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi
index 09bef56..221da8b 100644
--- a/arch/arm/dts/exynos54xx.dtsi
+++ b/arch/arm/dts/exynos54xx.dtsi
@@ -104,6 +104,20 @@
 		interrupts = <0 203 0>;
 	};
 
+	i2s0: i2s@3830000 {
+		compatible = "samsung,s5pv210-i2s";
+		reg = <0x03830000 0x100>;
+		#sound-dai-cells = <1>;
+		samsung,idma-addr = <0x03000000>;
+		samsung,i2s-epll-clock-frequency = <192000000>;
+		samsung,i2s-sampling-rate = <48000>;
+		samsung,i2s-bits-per-sample = <16>;
+		samsung,i2s-channels = <2>;
+		samsung,i2s-lr-clk-framesize = <256>;
+		samsung,i2s-bit-clk-framesize = <32>;
+		samsung,i2s-id = <0>;
+	};
+
 	mmc@12200000 {
 		samsung,bus-width = <8>;
 		samsung,timing = <1 3 3>;
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts
index 7498519..63c0b18 100644
--- a/arch/arm/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/dts/exynos5800-peach-pi.dts
@@ -79,12 +79,28 @@
 		};
 	};
 
+	sound {
+		compatible = "google,peach-audio-max98090";
+
+		samsung,model = "PEACH-I2S-MAX98090";
+		samsung,audio-codec = <&max98090>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98090 0>;
+		};
+	};
+
 	i2c@12CD0000 { /* i2c7 */
 		clock-frequency = <100000>;
-	       soundcodec@20 {
-	              reg = <0x20>;
-	              compatible = "maxim,max98090-codec";
-	       };
+		max98090: soundcodec@10 {
+			reg = <0x10>;
+			compatible = "maxim,max98090";
+			#sound-dai-cells = <1>;
+		};
 	};
 
         sound@3830000 {
diff --git a/arch/arm/dts/hi3798cv200-u-boot.dtsi b/arch/arm/dts/hi3798cv200-u-boot.dtsi
index 709ae1c..7844c52 100644
--- a/arch/arm/dts/hi3798cv200-u-boot.dtsi
+++ b/arch/arm/dts/hi3798cv200-u-boot.dtsi
@@ -17,12 +17,6 @@
 };
 
 &uart0 {
-	status = "disabled";
-};
-
-/{
-	chosen {
-		stdout-path = "";
-	};
+	clock = <75000000>;
+	status = "okay";
 };
-
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
index 6a3cd44..73aa4cd 100644
--- a/arch/arm/mach-exynos/clock.c
+++ b/arch/arm/mach-exynos/clock.c
@@ -345,7 +345,7 @@
 	int i;
 	struct clk_bit_info *info;
 
-	if (proid_is_exynos5420() || proid_is_exynos5422())
+	if (proid_is_exynos542x())
 		info = exynos542x_bit_info;
 	else
 		info = exynos5_bit_info;
@@ -557,7 +557,7 @@
 unsigned long clock_get_periph_rate(int peripheral)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos542x_get_periph_rate(peripheral);
 		return exynos5_get_periph_rate(peripheral);
 	} else {
@@ -1317,6 +1317,19 @@
 	return 0;
 }
 
+static int exynos5420_set_i2s_clk_source(void)
+{
+	struct exynos5420_clock *clk =
+		(struct exynos5420_clock *)samsung_get_base_clock();
+
+	setbits_le32(&clk->src_top6, EXYNOS5420_CLK_SRC_MOUT_EPLL);
+	clrsetbits_le32(&clk->src_mau, EXYNOS5420_AUDIO0_SEL_MASK,
+			(EXYNOS5420_CLK_SRC_SCLK_EPLL));
+	setbits_le32(EXYNOS5_AUDIOSS_BASE, 1 << 0);
+
+	return 0;
+}
+
 int exynos5_set_i2s_clk_source(unsigned int i2s_id)
 {
 	struct exynos5_clock *clk =
@@ -1575,7 +1588,7 @@
 unsigned long get_pll_clk(int pllreg)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos542x_get_pll_clk(pllreg);
 		return exynos5_get_pll_clk(pllreg);
 	} else if (cpu_is_exynos4()) {
@@ -1691,7 +1704,7 @@
 		div -= 1;
 
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			exynos5420_set_mmc_clk(dev_index, div);
 		else
 			exynos5_set_mmc_clk(dev_index, div);
@@ -1739,7 +1752,7 @@
 int set_spi_clk(int periph_id, unsigned int rate)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos5420_set_spi_clk(periph_id, rate);
 		return exynos5_set_spi_clk(periph_id, rate);
 	}
@@ -1758,8 +1771,12 @@
 
 int set_i2s_clk_source(unsigned int i2s_id)
 {
-	if (cpu_is_exynos5())
-		return exynos5_set_i2s_clk_source(i2s_id);
+	if (cpu_is_exynos5()) {
+		if (proid_is_exynos542x())
+			return exynos5420_set_i2s_clk_source();
+		else
+			return exynos5_set_i2s_clk_source(i2s_id);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c
index e63ef64..1cb8d39 100644
--- a/arch/arm/mach-exynos/clock_init_exynos5.c
+++ b/arch/arm/mach-exynos/clock_init_exynos5.c
@@ -968,7 +968,7 @@
 
 void system_clock_init(void)
 {
-	if (proid_is_exynos5420() || proid_is_exynos5422())
+	if (proid_is_exynos542x())
 		exynos5420_system_clock_init();
 	else
 		exynos5250_system_clock_init();
diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h
index 2829fb2..4e3702b 100644
--- a/arch/arm/mach-exynos/common_setup.h
+++ b/arch/arm/mach-exynos/common_setup.h
@@ -78,7 +78,7 @@
 		CACHE_TAG_RAM_LATENCY_2_CYCLES |
 		CACHE_DATA_RAM_LATENCY_2_CYCLES;
 
-	if (proid_is_exynos5420() || proid_is_exynos5422()) {
+	if (proid_is_exynos542x()) {
 		val |= CACHE_ECC_AND_PARITY |
 			CACHE_TAG_RAM_LATENCY_3_CYCLES |
 			CACHE_DATA_RAM_LATENCY_3_CYCLES;
@@ -97,7 +97,7 @@
 {
 	uint32_t val;
 
-	if (proid_is_exynos5420() || proid_is_exynos5422()) {
+	if (proid_is_exynos542x()) {
 		mrc_l2_aux_ctlr(val);
 		val |= CACHE_ENABLE_FORCE_L2_LOGIC |
 			CACHE_DISABLE_CLEAN_EVICT;
diff --git a/arch/arm/mach-exynos/include/mach/clock.h b/arch/arm/mach-exynos/include/mach/clock.h
index edf62bd..e4c706a 100644
--- a/arch/arm/mach-exynos/include/mach/clock.h
+++ b/arch/arm/mach-exynos/include/mach/clock.h
@@ -1370,10 +1370,13 @@
 #define AUDIO_1_RATIO_MASK		0x0f
 
 #define AUDIO0_SEL_MASK			0xf
+#define EXYNOS5420_AUDIO0_SEL_MASK	(0x3 << 28)
 #define AUDIO1_SEL_MASK			0xf
 
 #define CLK_SRC_SCLK_EPLL		0x7
+#define EXYNOS5420_CLK_SRC_SCLK_EPLL	(0x6 << 28)
 #define CLK_SRC_MOUT_EPLL		(1<<12)
+#define EXYNOS5420_CLK_SRC_MOUT_EPLL	BIT(20)
 #define AUDIO_CLKMUX_ASS		(1<<0)
 
 /* CON0 bit-fields */
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h
index aeb3755..766edee 100644
--- a/arch/arm/mach-exynos/include/mach/cpu.h
+++ b/arch/arm/mach-exynos/include/mach/cpu.h
@@ -268,6 +268,8 @@
 IS_EXYNOS_TYPE(exynos5420, 0x5420)
 IS_EXYNOS_TYPE(exynos5422, 0x5422)
 
+#define proid_is_exynos542x() (proid_is_exynos5420() || proid_is_exynos5422())
+
 #define SAMSUNG_BASE(device, base)				\
 static inline unsigned long __attribute__((no_instrument_function)) \
 	samsung_get_base_##device(void) \
@@ -277,7 +279,7 @@
 			return EXYNOS4X12_##base;		\
 		return EXYNOS4_##base;				\
 	} else if (cpu_is_exynos5()) {				\
-		if (proid_is_exynos5420() || proid_is_exynos5422())	\
+		if (proid_is_exynos542x())			\
 			return EXYNOS5420_##base;		\
 		return EXYNOS5_##base;				\
 	}							\
diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h
index 272e00b..f9975d7 100644
--- a/arch/arm/mach-exynos/include/mach/gpio.h
+++ b/arch/arm/mach-exynos/include/mach/gpio.h
@@ -1397,7 +1397,7 @@
 static inline struct gpio_info *get_gpio_data(void)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos5420_gpio_data;
 		else
 			return exynos5_gpio_data;
@@ -1414,7 +1414,7 @@
 static inline unsigned int get_bank_num(void)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return EXYNOS5420_GPIO_NUM_PARTS;
 		else
 			return EXYNOS5_GPIO_NUM_PARTS;
diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c
index f6743ca..b24f1bb 100644
--- a/arch/arm/mach-exynos/pinmux.c
+++ b/arch/arm/mach-exynos/pinmux.c
@@ -378,6 +378,20 @@
 	}
 }
 
+static void exynos5420_i2s_config(int peripheral)
+{
+	int i;
+
+	switch (peripheral) {
+	case PERIPH_ID_I2S0:
+		for (i = 0; i < 5; i++)
+			gpio_cfg_pin(EXYNOS5420_GPIO_Z0 + i,
+				     S5P_GPIO_FUNC(0x02));
+		break;
+	}
+}
+
+
 void exynos5_spi_config(int peripheral)
 {
 	int cfg = 0, pin = 0, i;
@@ -550,6 +564,9 @@
 	case PERIPH_ID_I2C10:
 		exynos5420_i2c_config(peripheral);
 		break;
+	case PERIPH_ID_I2S0:
+		exynos5420_i2s_config(peripheral);
+		break;
 	case PERIPH_ID_PWM0:
 		gpio_cfg_pin(EXYNOS5420_GPIO_B20, S5P_GPIO_FUNC(2));
 		break;
@@ -863,7 +880,7 @@
 int exynos_pinmux_config(int peripheral, int flags)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos5420_pinmux_config(peripheral, flags);
 		else if (proid_is_exynos5250())
 			return exynos5_pinmux_config(peripheral, flags);
diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c
index 63c410a..f2a6c00 100644
--- a/arch/arm/mach-exynos/power.c
+++ b/arch/arm/mach-exynos/power.c
@@ -124,7 +124,7 @@
 void set_usbdrd_phy_ctrl(unsigned int enable)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			exynos5420_set_usbdev_phy_ctrl(enable);
 		else
 			exynos5_set_usbdrd_phy_ctrl(enable);
diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c
index c7a8d94..f668f53 100644
--- a/arch/sandbox/cpu/sdl.c
+++ b/arch/sandbox/cpu/sdl.c
@@ -4,13 +4,24 @@
  */
 
 #include <errno.h>
+#include <unistd.h>
 #include <linux/input.h>
 #include <SDL/SDL.h>
-#include <sound.h>
 #include <asm/state.h>
 
-enum {
-	SAMPLE_RATE	= 22050,
+/**
+ * struct buf_info - a data buffer holding audio data
+ *
+ * @pos:	Current position playing in audio buffer
+ * @size:	Size of data in audio buffer (0=empty)
+ * @alloced:	Allocated size of audio buffer (max size it can hold)
+ * @data:	Audio data
+ */
+struct buf_info {
+	uint pos;
+	uint size;
+	uint alloced;
+	uint8_t *data;
 };
 
 static struct sdl_info {
@@ -20,12 +31,12 @@
 	int depth;
 	int pitch;
 	uint frequency;
-	uint audio_pos;
-	uint audio_size;
 	uint sample_rate;
-	uint8_t *audio_data;
 	bool audio_active;
 	bool inited;
+	int cur_buf;
+	struct buf_info buf[2];
+	bool running;
 } sdl;
 
 static void sandbox_sdl_poll_events(void)
@@ -243,24 +254,37 @@
 
 void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
 {
+	struct buf_info *buf;
 	int avail;
+	int i;
 
-	avail = sdl.audio_size - sdl.audio_pos;
-	if (avail < len)
-		len = avail;
+	for (i = 0; i < 2; i++) {
+		buf = &sdl.buf[sdl.cur_buf];
+		avail = buf->size - buf->pos;
+		if (avail <= 0) {
+			sdl.cur_buf = 1 - sdl.cur_buf;
+			continue;
+		}
+		if (avail > len)
+			avail = len;
 
-	SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len,
-		     SDL_MIX_MAXVOLUME);
-	sdl.audio_pos += len;
+		SDL_MixAudio(stream, buf->data + buf->pos, avail,
+			     SDL_MIX_MAXVOLUME);
+		buf->pos += avail;
+		len -= avail;
 
-	/* Loop if we are at the end */
-	if (sdl.audio_pos == sdl.audio_size)
-		sdl.audio_pos = 0;
+		/* Move to next buffer if we are at the end */
+		if (buf->pos == buf->size)
+			buf->size = 0;
+		else
+			break;
+	}
 }
 
-int sandbox_sdl_sound_init(void)
+int sandbox_sdl_sound_init(int rate, int channels)
 {
 	SDL_AudioSpec wanted;
+	int i;
 
 	if (sandbox_sdl_ensure_init())
 		return -1;
@@ -269,20 +293,27 @@
 		return 0;
 
 	/* Set the audio format */
-	wanted.freq = SAMPLE_RATE;
+	wanted.freq = rate;
 	wanted.format = AUDIO_S16;
-	wanted.channels = 1;    /* 1 = mono, 2 = stereo */
+	wanted.channels = channels;
 	wanted.samples = 1024;  /* Good low-latency value for callback */
 	wanted.callback = sandbox_sdl_fill_audio;
 	wanted.userdata = NULL;
 
-	sdl.audio_size = sizeof(uint16_t) * wanted.freq;
-	sdl.audio_data = malloc(sdl.audio_size);
-	if (!sdl.audio_data) {
-		printf("%s: Out of memory\n", __func__);
-		return -1;
+	for (i = 0; i < 2; i++) {
+		struct buf_info *buf = &sdl.buf[i];
+
+		buf->alloced = sizeof(uint16_t) * wanted.freq * wanted.channels;
+		buf->data = malloc(buf->alloced);
+		if (!buf->data) {
+			printf("%s: Out of memory\n", __func__);
+			if (i == 1)
+				free(sdl.buf[0].data);
+			return -1;
+		}
+		buf->pos = 0;
+		buf->size = 0;
 	}
-	sdl.audio_pos = 0;
 
 	if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
 		printf("Unable to initialize SDL audio: %s\n", SDL_GetError());
@@ -296,33 +327,50 @@
 	}
 	sdl.audio_active = true;
 	sdl.sample_rate = wanted.freq;
+	sdl.cur_buf = 0;
+	sdl.running = 0;
 
 	return 0;
 
 err:
-	free(sdl.audio_data);
+	for (i = 0; i < 2; i++)
+		free(sdl.buf[i].data);
 	return -1;
 }
 
-int sandbox_sdl_sound_start(uint frequency)
+int sandbox_sdl_sound_play(const void *data, uint size)
 {
+	struct buf_info *buf;
+
 	if (!sdl.audio_active)
-		return -1;
-	sdl.frequency = frequency;
-	sound_create_square_wave(sdl.sample_rate,
-				 (unsigned short *)sdl.audio_data,
-				 sdl.audio_size, frequency);
-	sdl.audio_pos = 0;
-	SDL_PauseAudio(0);
+		return 0;
+
+	buf = &sdl.buf[0];
+	if (buf->size)
+		buf = &sdl.buf[1];
+	while (buf->size)
+		usleep(1000);
+
+	if (size > buf->alloced)
+		return -E2BIG;
+
+	memcpy(buf->data, data, size);
+	buf->size = size;
+	buf->pos = 0;
+	if (!sdl.running) {
+		SDL_PauseAudio(0);
+		sdl.running = 1;
+	}
 
 	return 0;
 }
 
 int sandbox_sdl_sound_stop(void)
 {
-	if (!sdl.audio_active)
-		return -1;
-	SDL_PauseAudio(1);
+	if (sdl.running) {
+		SDL_PauseAudio(1);
+		sdl.running = 0;
+	}
 
 	return 0;
 }
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index ce3c88c..ae3189e 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -18,6 +18,11 @@
 		stdout-path = "/serial";
 	};
 
+	audio: audio-codec {
+		compatible = "sandbox,audio-codec";
+		#sound-dai-cells = <1>;
+	};
+
 	cros_ec: cros-ec {
 		reg = <0 0>;
 		u-boot,dm-pre-reloc;
@@ -127,6 +132,11 @@
 		};
 	};
 
+	i2s: i2s {
+		compatible = "sandbox,i2s";
+		#sound-dai-cells = <1>;
+	};
+
 	lcd {
 		u-boot,dm-pre-reloc;
 		compatible = "sandbox,lcd-sdl";
@@ -190,6 +200,17 @@
 		compatible = "sandbox,reset";
 	};
 
+	sound {
+		compatible = "sandbox,sound";
+		cpu {
+			sound-dai = <&i2s 0>;
+		};
+
+		codec {
+			sound-dai = <&audio 0>;
+		};
+	};
+
 	spi@0 {
 		u-boot,dm-pre-reloc;
 		#address-cells = <1>;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 6b1c269..3790b4c 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -42,6 +42,11 @@
 		osd0 = "/osd";
 	};
 
+	audio: audio-codec {
+		compatible = "sandbox,audio-codec";
+		#sound-dai-cells = <1>;
+	};
+
 	cros_ec: cros-ec {
 		reg = <0 0>;
 		compatible = "google,cros-ec-sandbox";
@@ -82,6 +87,8 @@
 		test2-gpios = <&gpio_a 1>, <&gpio_a 4>, <&gpio_b 6 1 3 2 1>,
 			<&gpio_b 7 2 3 2 1>, <&gpio_b 8 4 3 2 1>,
 			<&gpio_b 9 0xc 3 2 1>;
+		int-value = <1234>;
+		uint-value = <(-1234)>;
 	};
 
 	junk {
@@ -373,6 +380,11 @@
 		u-boot,dm-pre-reloc;
 	};
 
+	i2s: i2s {
+		compatible = "sandbox,i2s";
+		#sound-dai-cells = <1>;
+	};
+
 	misc-test {
 		compatible = "sandbox,misc_sandbox";
 	};
@@ -528,6 +540,17 @@
 		compatible = "sandbox,smem";
 	};
 
+	sound {
+		compatible = "sandbox,sound";
+		cpu {
+			sound-dai = <&i2s 0>;
+		};
+
+		codec {
+			sound-dai = <&audio 0>;
+		};
+	};
+
 	spi@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/sandbox/include/asm/sdl.h b/arch/sandbox/include/asm/sdl.h
index 1c4380c..1027b59 100644
--- a/arch/sandbox/include/asm/sdl.h
+++ b/arch/sandbox/include/asm/sdl.h
@@ -54,12 +54,12 @@
 int sandbox_sdl_key_pressed(int keycode);
 
 /**
- * sandbox_sdl_sound_start() - start playing a sound
+ * sandbox_sdl_sound_play() - Play a sound
  *
- * @frequency:	Frequency of sounds in Hertz
- * @return 0 if OK, -ENODEV if no sound is available
+ * @data:	Data to play (typically 16-bit)
+ * @count:	Number of bytes in data
  */
-int sandbox_sdl_sound_start(uint frequency);
+int sandbox_sdl_sound_play(const void *data, uint count);
 
 /**
  * sandbox_sdl_sound_stop() - stop playing a sound
@@ -71,9 +71,11 @@
 /**
  * sandbox_sdl_sound_init() - set up the sound system
  *
+ * @rate:	Sample rate to use
+ * @channels:	Number of channels to use (1=mono, 2=stereo)
  * @return 0 if OK, -ENODEV if no sound is available
  */
-int sandbox_sdl_sound_init(void);
+int sandbox_sdl_sound_init(int rate, int channels);
 
 #else
 static inline int sandbox_sdl_init_display(int width, int height,
@@ -102,12 +104,17 @@
 	return -ENODEV;
 }
 
+int sandbox_sdl_sound_play(const void *data, uint count)
+{
+	return -ENODEV;
+}
+
 static inline int sandbox_sdl_sound_stop(void)
 {
 	return -ENODEV;
 }
 
-static inline int sandbox_sdl_sound_init(void)
+int sandbox_sdl_sound_init(int rate, int channels)
 {
 	return -ENODEV;
 }
diff --git a/arch/sandbox/include/asm/sound.h b/arch/sandbox/include/asm/sound.h
deleted file mode 100644
index a6015b0..0000000
--- a/arch/sandbox/include/asm/sound.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2013 Google, Inc
- */
-
-#ifndef __SANDBOX_SOUND_H
-#define __SANDBOX_SOUND_H
-
-int sound_play(unsigned int msec, unsigned int frequency);
-
-int sound_init(const void *blob);
-
-#endif
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 5e81839..74f9618 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -121,4 +121,44 @@
  */
 void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask);
 
+/**
+ * sandbox_get_codec_params() - Read back codec parameters
+ *
+ * This reads back the parameters set by audio_codec_set_params() for the
+ * sandbox audio driver. Arguments are as for that function.
+ */
+void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
+			      int *mclk_freqp, int *bits_per_samplep,
+			      uint *channelsp);
+
+/**
+ * sandbox_get_i2s_sum() - Read back the sum of the audio data so far
+ *
+ * This data is provided to the sandbox driver by the I2S tx_data() method.
+ *
+ * @dev: Device to check
+ * @return sum of audio data
+ */
+int sandbox_get_i2s_sum(struct udevice *dev);
+
+/**
+ * sandbox_get_setup_called() - Returns the number of times setup(*) was called
+ *
+ * This is used in the sound test
+ *
+ * @dev: Device to check
+ * @return call count for the setup() method
+ */
+int sandbox_get_setup_called(struct udevice *dev);
+
+/**
+ * sandbox_get_sound_sum() - Read back the sum of the sound data so far
+ *
+ * This data is provided to the sandbox driver by the sound play() method.
+ *
+ * @dev: Device to check
+ * @return sum of audio data
+ */
+int sandbox_get_sound_sum(struct udevice *dev);
+
 #endif
diff --git a/board/hisilicon/poplar/MAINTAINERS b/board/hisilicon/poplar/MAINTAINERS
index 0cc01c8..622e5cb 100644
--- a/board/hisilicon/poplar/MAINTAINERS
+++ b/board/hisilicon/poplar/MAINTAINERS
@@ -1,5 +1,6 @@
 Poplar BOARD
 M:     Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+M:     Shawn Guo <shawn.guo@linaro.org>
 S:     Maintained
 F:     board/hisilicon/poplar
 F:     include/configs/poplar.h
diff --git a/board/hisilicon/poplar/poplar.c b/board/hisilicon/poplar/poplar.c
index 9e8eac7..8adc750 100644
--- a/board/hisilicon/poplar/poplar.c
+++ b/board/hisilicon/poplar/poplar.c
@@ -35,6 +35,7 @@
 
 struct mm_region *mem_map = poplar_mem_map;
 
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 static const struct pl01x_serial_platdata serial_platdata = {
 	.base = REG_BASE_UART0,
 	.type = TYPE_PL010,
@@ -45,6 +46,7 @@
 	.name = "serial_pl01x",
 	.platdata = &serial_platdata,
 };
+#endif
 
 int checkboard(void)
 {
diff --git a/cmd/Makefile b/cmd/Makefile
index 4998643..15ae4d2 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -40,6 +40,7 @@
 obj-$(CONFIG_DATAFLASH_MMC_SELECT) += dataflash_mmc_mux.o
 obj-$(CONFIG_CMD_DATE) += date.o
 obj-$(CONFIG_CMD_DEMO) += demo.o
+obj-$(CONFIG_CMD_DM) += dm.o
 obj-$(CONFIG_CMD_SOUND) += sound.o
 ifdef CONFIG_POST
 obj-$(CONFIG_CMD_DIAG) += diag.o
diff --git a/test/dm/cmd_dm.c b/cmd/dm.c
similarity index 100%
rename from test/dm/cmd_dm.c
rename to cmd/dm.c
diff --git a/cmd/sound.c b/cmd/sound.c
index d1cbc14..638f29d 100644
--- a/cmd/sound.c
+++ b/cmd/sound.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <sound.h>
 
@@ -14,11 +15,14 @@
 /* Initilaise sound subsystem */
 static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
+	struct udevice *dev;
 	int ret;
 
-	ret = sound_init(gd->fdt_blob);
+	ret = uclass_first_device_err(UCLASS_SOUND, &dev);
+	if (!ret)
+		ret = sound_setup(dev);
 	if (ret) {
-		printf("Initialise Audio driver failed\n");
+		printf("Initialise Audio driver failed (ret=%d)\n", ret);
 		return CMD_RET_FAILURE;
 	}
 
@@ -28,6 +32,7 @@
 /* play sound from buffer */
 static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
+	struct udevice *dev;
 	int ret = 0;
 	int msec = 1000;
 	int freq = 400;
@@ -37,9 +42,11 @@
 	if (argc > 2)
 		freq = simple_strtoul(argv[2], NULL, 10);
 
-	ret = sound_play(msec, freq);
+	ret = uclass_first_device_err(UCLASS_SOUND, &dev);
+	if (!ret)
+		ret = sound_beep(dev, msec, freq);
 	if (ret) {
-		printf("play failed");
+		printf("Sound device failed to play (err=%d)\n", ret);
 		return CMD_RET_FAILURE;
 	}
 
diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig
index 338eae2..14c835c 100644
--- a/configs/peach-pi_defconfig
+++ b/configs/peach-pi_defconfig
@@ -21,6 +21,7 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
+CONFIG_CMD_SOUND=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_TPM=y
@@ -28,7 +29,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5800-peach-pi"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
@@ -52,6 +52,7 @@
 CONFIG_SOUND=y
 CONFIG_I2S=y
 CONFIG_I2S_SAMSUNG=y
+CONFIG_SOUND_MAX98090=y
 CONFIG_SOUND_MAX98095=y
 CONFIG_SOUND_WM8994=y
 CONFIG_EXYNOS_SPI=y
diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig
index 933c823..9a3a115 100644
--- a/configs/peach-pit_defconfig
+++ b/configs/peach-pit_defconfig
@@ -20,6 +20,7 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
+CONFIG_CMD_SOUND=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_TPM=y
@@ -27,7 +28,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5420-peach-pit"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
@@ -51,6 +51,7 @@
 CONFIG_SOUND=y
 CONFIG_I2S=y
 CONFIG_I2S_SAMSUNG=y
+CONFIG_SOUND_MAX98090=y
 CONFIG_SOUND_MAX98095=y
 CONFIG_SOUND_WM8994=y
 CONFIG_EXYNOS_SPI=y
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index e6680d9..aede145 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_SANDBOX64=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 5b65c61..1e7d41d 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DEBUG_UART=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 756b839..4f3757c 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_FIT=y
diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig
index e71e2d3..6c7d08e 100644
--- a/configs/sandbox_noblk_defconfig
+++ b/configs/sandbox_noblk_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_FIT=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 452a2ef..2f83812 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -1,7 +1,6 @@
 CONFIG_SYS_TEXT_BASE=0
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_SPL_SERIAL_SUPPORT=y
 CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
 CONFIG_SPL=y
diff --git a/configs/smdk5250_defconfig b/configs/smdk5250_defconfig
index 161454b..21018d8 100644
--- a/configs/smdk5250_defconfig
+++ b/configs/smdk5250_defconfig
@@ -30,7 +30,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5250-smdk5250"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_S5P=y
diff --git a/configs/smdk5420_defconfig b/configs/smdk5420_defconfig
index 433e9a8..4e45589 100644
--- a/configs/smdk5420_defconfig
+++ b/configs/smdk5420_defconfig
@@ -25,7 +25,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5420-smdk5420"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_S5P=y
diff --git a/configs/snow_defconfig b/configs/snow_defconfig
index 2108009..e0c1bf8 100644
--- a/configs/snow_defconfig
+++ b/configs/snow_defconfig
@@ -34,7 +34,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5250-snow"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_LDO=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
diff --git a/configs/spring_defconfig b/configs/spring_defconfig
index ca17998..c089517 100644
--- a/configs/spring_defconfig
+++ b/configs/spring_defconfig
@@ -34,7 +34,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5250-spring"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_LDO=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig
new file mode 100644
index 0000000..fb06076
--- /dev/null
+++ b/configs/tools-only_defconfig
@@ -0,0 +1,24 @@
+CONFIG_SYS_TEXT_BASE=0
+CONFIG_ANDROID_BOOT_IMAGE=y
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_DATE is not set
+CONFIG_OF_CONTROL=y
+CONFIG_OF_HOSTFILE=y
+CONFIG_DEFAULT_DEVICE_TREE="sandbox"
+# CONFIG_UDP_FUNCTION_FASTBOOT is not set
+CONFIG_SANDBOX_GPIO=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_PCI_SANDBOX=y
+CONFIG_DM_RTC=y
+CONFIG_SOUND=y
+CONFIG_SYSRESET=y
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTIO_SANDBOX is not set
+# CONFIG_EFI_LOADER is not set
diff --git a/drivers/core/read.c b/drivers/core/read.c
index cdd78be..3c46b36 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -21,6 +21,29 @@
 	return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
 }
 
+int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp)
+{
+	return ofnode_read_u32(dev_ofnode(dev), propname, (u32 *)outp);
+}
+
+int dev_read_s32_default(struct udevice *dev, const char *propname, int def)
+{
+	return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
+}
+
+int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp)
+{
+	u32 val;
+	int ret;
+
+	ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
+	if (ret)
+		return ret;
+	*outp = val;
+
+	return 0;
+}
+
 const char *dev_read_string(struct udevice *dev, const char *propname)
 {
 	return ofnode_read_string(dev_ofnode(dev), propname);
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
index 661cf61..3cf9dd9 100644
--- a/drivers/core/syscon-uclass.c
+++ b/drivers/core/syscon-uclass.c
@@ -146,52 +146,31 @@
  * The syscon node can be bound to another driver, but still works
  * as a syscon provider.
  */
-static LIST_HEAD(syscon_list);
-
-struct syscon {
-	ofnode node;
-	struct regmap *regmap;
-	struct list_head list;
-};
-
-static struct syscon *of_syscon_register(ofnode node)
+struct regmap *syscon_node_to_regmap(ofnode node)
 {
-	struct syscon *syscon;
+	struct udevice *dev, *parent;
 	int ret;
 
+	if (!uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
+		return syscon_get_regmap(dev);
+
 	if (!ofnode_device_is_compatible(node, "syscon"))
 		return ERR_PTR(-EINVAL);
 
-	syscon = malloc(sizeof(*syscon));
-	if (!syscon)
-		return ERR_PTR(-ENOMEM);
+	/* bound to driver with same ofnode or to root if not found */
+	if (device_find_global_by_ofnode(node, &parent))
+		parent = dm_root();
 
-	ret = regmap_init_mem(node, &syscon->regmap);
-	if (ret) {
-		free(syscon);
+	/* force bound to syscon class */
+	ret = device_bind_driver_to_node(parent, "syscon",
+					 ofnode_get_name(node),
+					 node, &dev);
+	if (ret)
 		return ERR_PTR(ret);
-	}
-
-	list_add_tail(&syscon->list, &syscon_list);
-
-	return syscon;
-}
 
-struct regmap *syscon_node_to_regmap(ofnode node)
-{
-	struct syscon *entry, *syscon = NULL;
-
-	list_for_each_entry(entry, &syscon_list, list)
-		if (ofnode_equal(entry->node, node)) {
-			syscon = entry;
-			break;
-		}
-
-	if (!syscon)
-		syscon = of_syscon_register(node);
-
-	if (IS_ERR(syscon))
-		return ERR_CAST(syscon);
+	ret = device_probe(dev);
+	if (ret)
+		return ERR_PTR(ret);
 
-	return syscon->regmap;
+	return syscon_get_regmap(dev);
 }
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index 31b43ee..e31c87b 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <clk.h>
 #include <dm.h>
+#include <reset.h>
 #include <serial.h>
 #include <watchdog.h>
 #include <asm/io.h>
@@ -171,6 +172,7 @@
 {
 	struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
 	struct clk clk;
+	struct reset_ctl reset;
 	int ret;
 
 	plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev);
@@ -185,6 +187,13 @@
 		return ret;
 	}
 
+	ret = reset_get_by_index(dev, 0, &reset);
+	if (!ret) {
+		reset_assert(&reset);
+		udelay(2);
+		reset_deassert(&reset);
+	}
+
 	plat->clock_rate = clk_get_rate(&clk);
 	if (plat->clock_rate < 0) {
 		clk_disable(&clk);
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index 5de86c0..c0d97cc 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -31,6 +31,14 @@
 	  option provides an implementation for sound_init() and
 	  sound_play().
 
+config SOUND_MAX98090
+	bool "Support Maxim max98090 audio codec"
+	depends on I2S_SAMSUNG
+	help
+	  Enable the max98090 audio codec. This is connected via I2S for
+	  audio data and I2C for codec control. At present it only works
+	  with the Samsung I2S driver.
+
 config SOUND_MAX98095
 	bool "Support Maxim max98095 audio codec"
 	depends on I2S_SAMSUNG
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 696c5ae..1de4346 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -4,8 +4,12 @@
 # R. Chandrasekar <rcsekar@samsung.com>
 
 obj-$(CONFIG_SOUND)	+= sound.o
-obj-$(CONFIG_I2S)	+= sound-i2s.o
+obj-$(CONFIG_SOUND)	+= codec-uclass.o
+obj-$(CONFIG_SOUND)	+= i2s-uclass.o
+obj-$(CONFIG_SOUND)	+= sound-uclass.o
 obj-$(CONFIG_I2S_SAMSUNG)	+= samsung-i2s.o
 obj-$(CONFIG_SOUND_SANDBOX)	+= sandbox.o
+obj-$(CONFIG_I2S_SAMSUNG)	+= samsung_sound.o
 obj-$(CONFIG_SOUND_WM8994)	+= wm8994.o
-obj-$(CONFIG_SOUND_MAX98095)	+= max98095.o
+obj-$(CONFIG_SOUND_MAX98090)	+= max98090.o maxim_codec.o
+obj-$(CONFIG_SOUND_MAX98095)	+= max98095.o maxim_codec.o
diff --git a/drivers/sound/codec-uclass.c b/drivers/sound/codec-uclass.c
new file mode 100644
index 0000000..1ec77ac
--- /dev/null
+++ b/drivers/sound/codec-uclass.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <audio_codec.h>
+
+int audio_codec_set_params(struct udevice *dev, int interface, int rate,
+			   int mclk_freq, int bits_per_sample, uint channels)
+{
+	struct audio_codec_ops *ops = audio_codec_get_ops(dev);
+
+	if (!ops->set_params)
+		return -ENOSYS;
+
+	return ops->set_params(dev, interface, rate, mclk_freq, bits_per_sample,
+			       channels);
+}
+
+UCLASS_DRIVER(audio_codec) = {
+	.id		= UCLASS_AUDIO_CODEC,
+	.name		= "audio-codec",
+};
diff --git a/drivers/sound/i2s-uclass.c b/drivers/sound/i2s-uclass.c
new file mode 100644
index 0000000..b741e39
--- /dev/null
+++ b/drivers/sound/i2s-uclass.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+
+int i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+	struct i2s_ops *ops = i2s_get_ops(dev);
+
+	if (!ops->tx_data)
+		return -ENOSYS;
+
+	return ops->tx_data(dev, data, data_size);
+}
+
+UCLASS_DRIVER(i2s) = {
+	.id		= UCLASS_I2S,
+	.name		= "i2s",
+	.per_device_auto_alloc_size	= sizeof(struct i2s_uc_priv),
+};
diff --git a/drivers/sound/max98090.c b/drivers/sound/max98090.c
new file mode 100644
index 0000000..346ff5f
--- /dev/null
+++ b/drivers/sound/max98090.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * max98090.c -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <div64.h>
+#include <dm.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include "maxim_codec.h"
+#include "max98090.h"
+
+/*
+ * Sets hw params for max98090
+ *
+ * @priv: max98090 information pointer
+ * @rate: Sampling rate
+ * @bits_per_sample: Bits per sample
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_hw_params(struct maxim_priv *priv, unsigned int rate,
+		       unsigned int bits_per_sample)
+{
+	int error;
+	unsigned char value;
+
+	switch (bits_per_sample) {
+	case 16:
+		maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
+		error = maxim_bic_or(priv, M98090_REG_INTERFACE_FORMAT,
+				     M98090_WS_MASK, 0);
+		maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
+		break;
+	default:
+		debug("%s: Illegal bits per sample %d.\n",
+		      __func__, bits_per_sample);
+		return -1;
+	}
+
+	/* Update filter mode */
+	if (rate < 240000)
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_MODE_MASK, 0);
+	else
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_MODE_MASK, M98090_MODE_MASK);
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_DHF_MASK, 0);
+	else
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_DHF_MASK, M98090_DHF_MASK);
+
+	if (error < 0) {
+		debug("%s: Error setting hardware params.\n", __func__);
+		return -EIO;
+	}
+	priv->rate = rate;
+
+	return 0;
+}
+
+/*
+ * Configures Audio interface system clock for the given frequency
+ *
+ * @priv: max98090 information
+ * @freq: Sampling frequency in Hz
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_set_sysclk(struct maxim_priv *priv, unsigned int freq)
+{
+	int error = 0;
+
+	/* Requested clock frequency is already setup */
+	if (freq == priv->sysclk)
+		return 0;
+
+	/* Setup clocks for slave mode, and using the PLL
+	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+	 *	0x02 (when master clk is 20MHz to 40MHz)..
+	 *	0x03 (when master clk is 40MHz to 60MHz)..
+	 */
+	if (freq >= 10000000 && freq < 20000000) {
+		error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+					M98090_PSCLK_DIV1);
+	} else if (freq >= 20000000 && freq < 40000000) {
+		error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+					M98090_PSCLK_DIV2);
+	} else if (freq >= 40000000 && freq < 60000000) {
+		error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+					M98090_PSCLK_DIV4);
+	} else {
+		debug("%s: Invalid master clock frequency\n", __func__);
+		return -1;
+	}
+
+	debug("%s: Clock at %uHz\n", __func__, freq);
+
+	if (error < 0)
+		return -1;
+
+	priv->sysclk = freq;
+
+	return 0;
+}
+
+/*
+ * Sets Max98090 I2S format
+ *
+ * @priv: max98090 information
+ * @fmt: i2S format - supports a subset of the options defined in i2s.h.
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_set_fmt(struct maxim_priv *priv, int fmt)
+{
+	u8 regval = 0;
+	int error = 0;
+
+	if (fmt == priv->fmt)
+		return 0;
+
+	priv->fmt = fmt;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* Set to slave mode PLL - MAS mode off */
+		error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB,
+					 0x00);
+		error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB,
+					 0x00);
+		error |= maxim_bic_or(priv, M98090_REG_CLOCK_MODE,
+				      M98090_USE_M1_MASK, 0);
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* Set to master mode */
+		debug("Master mode not supported\n");
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		debug("%s: Clock mode unsupported\n", __func__);
+		return -EINVAL;
+	}
+
+	error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, regval);
+
+	regval = 0;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		regval |= M98090_DLY_MASK;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		regval |= M98090_RJ_MASK;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* Not supported mode */
+	default:
+		debug("%s: Unrecognized format.\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		regval |= M98090_WCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		regval |= M98090_BCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		regval |= M98090_BCI_MASK | M98090_WCI_MASK;
+		break;
+	default:
+		debug("%s: Unrecognized inversion settings.\n", __func__);
+		return -EINVAL;
+	}
+
+	error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, regval);
+
+	if (error < 0) {
+		debug("%s: Error setting i2s format.\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * resets the audio codec
+ *
+ * @priv: max98090 information
+ * @return -EIO for error, 0 for success.
+ */
+static int max98090_reset(struct maxim_priv *priv)
+{
+	int ret;
+
+	/*
+	 * Gracefully reset the DSP core and the codec hardware in a proper
+	 * sequence.
+	 */
+	ret = maxim_i2c_write(priv, M98090_REG_SOFTWARE_RESET,
+			      M98090_SWRESET_MASK);
+	if (ret != 0) {
+		debug("%s: Failed to reset DSP: %d\n", __func__, ret);
+		return ret;
+	}
+	mdelay(20);
+
+	return 0;
+}
+
+/*
+ * Initialise max98090 codec device
+ *
+ * @priv: max98090 information
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_device_init(struct maxim_priv *priv)
+{
+	unsigned char id;
+	int error = 0;
+
+	/* Enable codec clock */
+	set_xclkout();
+
+	/* reset the codec, the DSP core, and disable all interrupts */
+	error = max98090_reset(priv);
+	if (error != 0) {
+		debug("Reset\n");
+		return error;
+	}
+
+	/* initialize private data */
+	priv->sysclk = -1U;
+	priv->rate = -1U;
+	priv->fmt = -1U;
+
+	error = maxim_i2c_read(priv, M98090_REG_REVISION_ID, &id);
+	if (error < 0) {
+		debug("%s: Failure reading hardware revision: %d\n",
+		      __func__, id);
+		return -EIO;
+	}
+	debug("%s: Hardware revision: %d\n", __func__, id);
+
+	return 0;
+}
+
+static int max98090_setup_interface(struct maxim_priv *priv)
+{
+	unsigned char id;
+	int error;
+
+	/* Reading interrupt status to clear them */
+	error = maxim_i2c_read(priv, M98090_REG_DEVICE_STATUS, &id);
+
+	error |= maxim_i2c_write(priv, M98090_REG_DAC_CONTROL,
+				 M98090_DACHP_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_BIAS_CONTROL,
+				 M98090_VCM_MODE_MASK);
+
+	error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_MIXER, 0x1);
+	error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_MIXER, 0x2);
+
+	error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_VOLUME, 0x25);
+	error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_VOLUME, 0x25);
+
+	error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
+				 M98090_SDIEN_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_DEVICE_SHUTDOWN,
+				 M98090_SHDNN_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_OUTPUT_ENABLE,
+				 M98090_HPREN_MASK | M98090_HPLEN_MASK |
+				 M98090_SPREN_MASK | M98090_SPLEN_MASK |
+				 M98090_DAREN_MASK | M98090_DALEN_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
+				 M98090_SDOEN_MASK | M98090_SDIEN_MASK);
+
+	if (error < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int max98090_do_init(struct maxim_priv *priv, int sampling_rate,
+			    int mclk_freq, int bits_per_sample)
+{
+	int ret = 0;
+
+	ret = max98090_setup_interface(priv);
+	if (ret < 0) {
+		debug("%s: max98090 setup interface failed\n", __func__);
+		return ret;
+	}
+
+	ret = max98090_set_sysclk(priv, mclk_freq);
+	if (ret < 0) {
+		debug("%s: max98090 codec set sys clock failed\n", __func__);
+		return ret;
+	}
+
+	ret = max98090_hw_params(priv, sampling_rate, bits_per_sample);
+
+	if (ret == 0) {
+		ret = max98090_set_fmt(priv, SND_SOC_DAIFMT_I2S |
+				       SND_SOC_DAIFMT_NB_NF |
+				       SND_SOC_DAIFMT_CBS_CFS);
+	}
+
+	return ret;
+}
+
+static int max98090_set_params(struct udevice *dev, int interface, int rate,
+			       int mclk_freq, int bits_per_sample,
+			       uint channels)
+{
+	struct maxim_priv *priv = dev_get_priv(dev);
+
+	return max98090_do_init(priv, rate, mclk_freq, bits_per_sample);
+}
+
+static int max98090_probe(struct udevice *dev)
+{
+	struct maxim_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->dev = dev;
+	ret = max98090_device_init(priv);
+	if (ret < 0) {
+		debug("%s: max98090 codec chip init failed\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct audio_codec_ops max98090_ops = {
+	.set_params	= max98090_set_params,
+};
+
+static const struct udevice_id max98090_ids[] = {
+	{ .compatible = "maxim,max98090" },
+	{ }
+};
+
+U_BOOT_DRIVER(max98090) = {
+	.name		= "max98090",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= max98090_ids,
+	.probe		= max98090_probe,
+	.ops		= &max98090_ops,
+	.priv_auto_alloc_size	= sizeof(struct maxim_priv),
+};
diff --git a/drivers/sound/max98090.h b/drivers/sound/max98090.h
new file mode 100644
index 0000000..3a6983b
--- /dev/null
+++ b/drivers/sound/max98090.h
@@ -0,0 +1,663 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * max98090.h -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#ifndef _MAX98090_H
+#define _MAX98090_H
+
+#include "maxim_codec.h"
+
+/* MAX98090 Registers Definition */
+
+#define M98090_REG_SOFTWARE_RESET               0x00
+#define M98090_REG_DEVICE_STATUS                0x01
+
+#define M98090_REG_QUICK_SAMPLE_RATE            0x05
+#define M98090_REG_DAI_INTERFACE                0x06
+#define M98090_REG_DAC_PATH                     0x07
+
+#define M98090_REG_MIC_BIAS_VOLTAGE		0x12
+#define M98090_REG_DIGITAL_MIC_ENABLE		0x13
+#define M98090_REG_DIGITAL_MIC_CONFIG		0x14
+#define M98090_REG_SYSTEM_CLOCK			0x1B
+#define M98090_REG_CLOCK_RATIO_NI_MSB		0x1D
+#define M98090_REG_CLOCK_MODE			0x1C
+#define M98090_REG_CLOCK_RATIO_NI_LSB		0x1E
+
+#define M98090_REG_MASTER_MODE			0x21
+#define M98090_REG_INTERFACE_FORMAT		0x22
+#define M98090_REG_IO_CONFIGURATION             0x25
+#define M98090_REG_FILTER_CONFIG                0x26
+
+#define M98090_REG_LEFT_HP_MIXER                0x29
+#define M98090_REG_RIGHT_HP_MIXER               0x2a
+#define M98090_REG_HP_CONTROL                   0x2b
+#define M98090_REG_LEFT_HP_VOLUME               0x2c
+#define M98090_REG_RIGHT_HP_VOLUME              0x2d
+#define M98090_REG_LEFT_SPK_MIXER               0x2e
+#define M98090_REG_RIGHT_SPK_MIXER              0x2f
+#define M98090_REG_SPK_CONTROL                  0x30
+#define M98090_REG_LEFT_SPK_VOLUME              0x31
+#define M98090_REG_RIGHT_SPK_VOLUME             0x32
+
+#define M98090_REG_RCV_LOUTL_CONTROL            0x38
+#define M98090_REG_RCV_LOUTL_VOLUME             0x39
+#define M98090_REG_LOUTR_MIXER                  0x3a
+#define M98090_REG_LOUTR_CONTROL                0x3b
+#define M98090_REG_LOUTR_VOLUME                 0x3c
+#define M98090_REG_JACK_DETECT                  0x3d
+#define M98090_REG_INPUT_ENABLE                 0x3e
+#define M98090_REG_OUTPUT_ENABLE                0x3f
+#define M98090_REG_LEVEL_CONTROL                0x40
+#define M98090_REG_DSP_FILTER_ENABLE            0x41
+#define M98090_REG_BIAS_CONTROL                 0x42
+#define M98090_REG_DAC_CONTROL                  0x43
+#define M98090_REG_ADC_CONTROL                  0x44
+#define M98090_REG_DEVICE_SHUTDOWN              0x45
+
+#define M98090_REG_REVISION_ID                  0xff
+
+#define M98090_REG_CNT				(0xff + 1)
+#define M98090_REG_MAX_CACHed			0x45
+
+/* MAX98090 Registers Bit Fields */
+
+/*
+ * M98090_REG_SOFTWARE_RESET		0x00
+ */
+#define M98090_SWRESET_MASK             BIT(7)
+
+/*
+ * M98090_REG_QUICK_SAMPLE_RATE		0x05
+ */
+#define M98090_SR_96K_MASK              BIT(5)
+#define M98090_SR_96K_SHIFT             5
+#define M98090_SR_96K_WIDTH             1
+#define M98090_SR_32K_MASK              BIT(4)
+#define M98090_SR_32K_SHIFT             4
+#define M98090_SR_32K_WIDTH             1
+#define M98090_SR_48K_MASK              BIT(3)
+#define M98090_SR_48K_SHIFT             3
+#define M98090_SR_48K_WIDTH             1
+#define M98090_SR_44K1_MASK             BIT(2)
+#define M98090_SR_44K1_SHIFT            2
+#define M98090_SR_44K1_WIDTH            1
+#define M98090_SR_16K_MASK              BIT(1)
+#define M98090_SR_16K_SHIFT             1
+#define M98090_SR_16K_WIDTH             1
+#define M98090_SR_8K_MASK               BIT(0)
+#define M98090_SR_8K_SHIFT              0
+#define M98090_SR_8K_WIDTH              1
+#define M98090_SR_MASK                  0x3F
+#define M98090_SR_ALL_SHIFT             0
+#define M98090_SR_ALL_WIDTH             8
+#define M98090_SR_ALL_NUM               BIT(M98090_SR_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAI_INTERFACE		0x06
+ */
+#define M98090_RJ_M_MASK                BIT(5)
+#define M98090_RJ_M_SHIFT               5
+#define M98090_RJ_M_WIDTH               1
+#define M98090_RJ_S_MASK                BIT(4)
+#define M98090_RJ_S_SHIFT               4
+#define M98090_RJ_S_WIDTH               1
+#define M98090_LJ_M_MASK                BIT(3)
+#define M98090_LJ_M_SHIFT               3
+#define M98090_LJ_M_WIDTH               1
+#define M98090_LJ_S_MASK                BIT(2)
+#define M98090_LJ_S_SHIFT               2
+#define M98090_LJ_S_WIDTH               1
+#define M98090_I2S_M_MASK               BIT(1)
+#define M98090_I2S_M_SHIFT              1
+#define M98090_I2S_M_WIDTH              1
+#define M98090_I2S_S_MASK               BIT(0)
+#define M98090_I2S_S_SHIFT              0
+#define M98090_I2S_S_WIDTH              1
+#define M98090_DAI_ALL_SHIFT            0
+#define M98090_DAI_ALL_WIDTH            8
+#define M98090_DAI_ALL_NUM              BIT(M98090_DAI_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAC_PATH			0x07
+ */
+#define M98090_DIG2_HP_MASK             BIT(7)
+#define M98090_DIG2_HP_SHIFT            7
+#define M98090_DIG2_HP_WIDTH            1
+#define M98090_DIG2_EAR_MASK            BIT(6)
+#define M98090_DIG2_EAR_SHIFT           6
+#define M98090_DIG2_EAR_WIDTH           1
+#define M98090_DIG2_SPK_MASK            BIT(5)
+#define M98090_DIG2_SPK_SHIFT           5
+#define M98090_DIG2_SPK_WIDTH           1
+#define M98090_DIG2_LOUT_MASK           BIT(4)
+#define M98090_DIG2_LOUT_SHIFT          4
+#define M98090_DIG2_LOUT_WIDTH          1
+#define M98090_DIG2_ALL_SHIFT           0
+#define M98090_DIG2_ALL_WIDTH           8
+#define M98090_DIG2_ALL_NUM             BIT(M98090_DIG2_ALL_WIDTH)
+
+/*
+ * M98090_REG_MIC_BIAS_VOLTAGE		0x12
+ */
+#define M98090_MBVSEL_MASK              (3 << 0)
+#define M98090_MBVSEL_SHIFT             0
+#define M98090_MBVSEL_WIDTH             2
+#define M98090_MBVSEL_2V8               (3 << 0)
+#define M98090_MBVSEL_2V55              (2 << 0)
+#define M98090_MBVSEL_2V4               BIT(0)
+#define M98090_MBVSEL_2V2               (0 << 0)
+
+/*
+ * M98090_REG_DIGITAL_MIC_ENABLE	0x13
+ */
+#define M98090_MICCLK_MASK		(7 << 4)
+#define M98090_MICCLK_SHIFT		4
+#define M98090_MICCLK_WIDTH		3
+#define M98090_DIGMIC4_MASK		BIT(3)
+#define M98090_DIGMIC4_SHIFT		3
+#define M98090_DIGMIC4_WIDTH		1
+#define M98090_DIGMIC4_NUM		BIT(M98090_DIGMIC4_WIDTH)
+#define M98090_DIGMIC3_MASK		BIT(2)
+#define M98090_DIGMIC3_SHIFT		2
+#define M98090_DIGMIC3_WIDTH		1
+#define M98090_DIGMIC3_NUM		BIT(M98090_DIGMIC3_WIDTH)
+#define M98090_DIGMICR_MASK		BIT(1)
+#define M98090_DIGMICR_SHIFT		1
+#define M98090_DIGMICR_WIDTH		1
+#define M98090_DIGMICR_NUM		BIT(M98090_DIGMICR_WIDTH)
+#define M98090_DIGMICL_MASK		BIT(0)
+#define M98090_DIGMICL_SHIFT		0
+#define M98090_DIGMICL_WIDTH		1
+#define M98090_DIGMICL_NUM		BIT(M98090_DIGMICL_WIDTH)
+
+/*
+ * M98090_REG_DIGITAL_MIC_CONFIG	0x14
+ */
+#define M98090_DMIC_COMP_MASK		(15 << 4)
+#define M98090_DMIC_COMP_SHIFT		4
+#define M98090_DMIC_COMP_WIDTH		4
+#define M98090_DMIC_COMP_NUM		BIT(M98090_DMIC_COMP_WIDTH)
+#define M98090_DMIC_FREQ_MASK		(3 << 0)
+#define M98090_DMIC_FREQ_SHIFT		0
+#define M98090_DMIC_FREQ_WIDTH		2
+
+/*
+ * M98090_REG_CLOCK_MODE		0x1B
+ */
+#define M98090_PSCLK_MASK               (3 << 4)
+#define M98090_PSCLK_SHIFT              4
+#define M98090_PSCLK_WIDTH              2
+#define M98090_PSCLK_DISABLED           (0 << 4)
+#define M98090_PSCLK_DIV1               BIT(4)
+#define M98090_PSCLK_DIV2               (2 << 4)
+#define M98090_PSCLK_DIV4               (3 << 4)
+
+/*
+ * M98090_REG_INTERFACE_FORMAT		0x22
+ */
+#define M98090_RJ_MASK			BIT(5)
+#define M98090_RJ_SHIFT			5
+#define M98090_RJ_WIDTH			1
+#define M98090_WCI_MASK			BIT(4)
+#define M98090_WCI_SHIFT		4
+#define M98090_WCI_WIDTH		1
+#define M98090_BCI_MASK			BIT(3)
+#define M98090_BCI_SHIFT		3
+#define M98090_BCI_WIDTH		1
+#define M98090_DLY_MASK			BIT(2)
+#define M98090_DLY_SHIFT		2
+#define M98090_DLY_WIDTH		1
+#define M98090_WS_MASK			(3 << 0)
+#define M98090_WS_SHIFT			0
+#define M98090_WS_WIDTH			2
+#define M98090_WS_NUM			BIT(M98090_WS_WIDTH)
+
+/* M98090_REG_IO_CONFIGURATION	0x25 */
+#define M98090_LTEN_MASK                BIT(5)
+#define M98090_LTEN_SHIFT               5
+#define M98090_LTEN_WIDTH               1
+#define M98090_LTEN_NUM                 BIT(M98090_LTEN_WIDTH)
+#define M98090_LBEN_MASK                BIT(4)
+#define M98090_LBEN_SHIFT               4
+#define M98090_LBEN_WIDTH               1
+#define M98090_LBEN_NUM                 BIT(M98090_LBEN_WIDTH)
+#define M98090_DMONO_MASK               BIT(3)
+#define M98090_DMONO_SHIFT              3
+#define M98090_DMONO_WIDTH              1
+#define M98090_DMONO_NUM                BIT(M98090_DMONO_WIDTH)
+#define M98090_HIZOFF_MASK              BIT(2)
+#define M98090_HIZOFF_SHIFT             2
+#define M98090_HIZOFF_WIDTH             1
+#define M98090_HIZOFF_NUM               BIT(M98090_HIZOFF_WIDTH)
+#define M98090_SDOEN_MASK               BIT(1)
+#define M98090_SDOEN_SHIFT              1
+#define M98090_SDOEN_WIDTH              1
+#define M98090_SDOEN_NUM                BIT(M98090_SDOEN_WIDTH)
+#define M98090_SDIEN_MASK               BIT(0)
+#define M98090_SDIEN_SHIFT              0
+#define M98090_SDIEN_WIDTH              1
+#define M98090_SDIEN_NUM                BIT(M98090_SDIEN_WIDTH)
+
+/*
+ * M98090_REG_FILTER_CONFIG		0x26
+ */
+#define M98090_MODE_MASK                BIT(7)
+#define M98090_MODE_SHIFT               7
+#define M98090_MODE_WIDTH               1
+#define M98090_AHPF_MASK                BIT(6)
+#define M98090_AHPF_SHIFT               6
+#define M98090_AHPF_WIDTH               1
+#define M98090_AHPF_NUM                 BIT(M98090_AHPF_WIDTH)
+#define M98090_DHPF_MASK                BIT(5)
+#define M98090_DHPF_SHIFT               5
+#define M98090_DHPF_WIDTH               1
+#define M98090_DHPF_NUM                 BIT(M98090_DHPF_WIDTH)
+#define M98090_DHF_MASK                 BIT(4)
+#define M98090_DHF_SHIFT                4
+#define M98090_DHF_WIDTH                1
+#define M98090_FLT_DMIC34MODE_MASK      BIT(3)
+#define M98090_FLT_DMIC34MODE_SHIFT     3
+#define M98090_FLT_DMIC34MODE_WIDTH     1
+#define M98090_FLT_DMIC34HPF_MASK       BIT(2)
+#define M98090_FLT_DMIC34HPF_SHIFT      2
+#define M98090_FLT_DMIC34HPF_WIDTH      1
+#define M98090_FLT_DMIC34HPF_NUM        BIT(M98090_FLT_DMIC34HPF_WIDTH)
+
+/*
+ * M98090_REG_CLOCK_MODE
+ */
+#define M98090_FREQ_MASK		(15 << 4)
+#define M98090_FREQ_SHIFT		4
+#define M98090_FREQ_WIDTH		4
+#define M98090_USE_M1_MASK		BIT(0)
+#define M98090_USE_M1_SHIFT		0
+#define M98090_USE_M1_WIDTH		1
+#define M98090_USE_M1_NUM		BIT(M98090_USE_M1_WIDTH)
+
+/*
+ * M98090_REG_LEFT_HP_MIXER		0x29
+ */
+#define M98090_MIXHPL_MIC2_MASK         BIT(5)
+#define M98090_MIXHPL_MIC2_SHIFT        5
+#define M98090_MIXHPL_MIC2_WIDTH        1
+#define M98090_MIXHPL_MIC1_MASK         BIT(4)
+#define M98090_MIXHPL_MIC1_SHIFT        4
+#define M98090_MIXHPL_MIC1_WIDTH        1
+#define M98090_MIXHPL_LINEB_MASK        BIT(3)
+#define M98090_MIXHPL_LINEB_SHIFT       3
+#define M98090_MIXHPL_LINEB_WIDTH       1
+#define M98090_MIXHPL_LINEA_MASK        BIT(2)
+#define M98090_MIXHPL_LINEA_SHIFT       2
+#define M98090_MIXHPL_LINEA_WIDTH       1
+#define M98090_MIXHPL_DACR_MASK         BIT(1)
+#define M98090_MIXHPL_DACR_SHIFT        1
+#define M98090_MIXHPL_DACR_WIDTH        1
+#define M98090_MIXHPL_DACL_MASK         BIT(0)
+#define M98090_MIXHPL_DACL_SHIFT        0
+#define M98090_MIXHPL_DACL_WIDTH        1
+#define M98090_MIXHPL_MASK              (63 << 0)
+#define M98090_MIXHPL_SHIFT             0
+#define M98090_MIXHPL_WIDTH             6
+
+/*
+ * M98090_REG_RIGHT_HP_MIXER		0x2A
+ */
+#define M98090_MIXHPR_MIC2_MASK         BIT(5)
+#define M98090_MIXHPR_MIC2_SHIFT        5
+#define M98090_MIXHPR_MIC2_WIDTH        1
+#define M98090_MIXHPR_MIC1_MASK         BIT(4)
+#define M98090_MIXHPR_MIC1_SHIFT        4
+#define M98090_MIXHPR_MIC1_WIDTH        1
+#define M98090_MIXHPR_LINEB_MASK        BIT(3)
+#define M98090_MIXHPR_LINEB_SHIFT       3
+#define M98090_MIXHPR_LINEB_WIDTH       1
+#define M98090_MIXHPR_LINEA_MASK        BIT(2)
+#define M98090_MIXHPR_LINEA_SHIFT       2
+#define M98090_MIXHPR_LINEA_WIDTH       1
+#define M98090_MIXHPR_DACR_MASK         BIT(1)
+#define M98090_MIXHPR_DACR_SHIFT        1
+#define M98090_MIXHPR_DACR_WIDTH        1
+#define M98090_MIXHPR_DACL_MASK         BIT(0)
+#define M98090_MIXHPR_DACL_SHIFT        0
+#define M98090_MIXHPR_DACL_WIDTH        1
+#define M98090_MIXHPR_MASK              (63 << 0)
+#define M98090_MIXHPR_SHIFT             0
+#define M98090_MIXHPR_WIDTH             6
+
+/*
+ * M98090_REG_LEFT_HP_VOLUME		0x2C
+ */
+#define M98090_HPLM_MASK                BIT(7)
+#define M98090_HPLM_SHIFT               7
+#define M98090_HPLM_WIDTH               1
+#define M98090_HPVOLL_MASK              (31 << 0)
+#define M98090_HPVOLL_SHIFT             0
+#define M98090_HPVOLL_WIDTH             5
+#define M98090_HPVOLL_NUM               BIT(M98090_HPVOLL_WIDTH)
+
+/*
+ * M98090_REG_RIGHT_HP_VOLUME	0x2D
+ */
+#define M98090_HPRM_MASK                BIT(7)
+#define M98090_HPRM_SHIFT               7
+#define M98090_HPRM_WIDTH               1
+#define M98090_HPVOLR_MASK              (31 << 0)
+#define M98090_HPVOLR_SHIFT             0
+#define M98090_HPVOLR_WIDTH             5
+#define M98090_HPVOLR_NUM               BIT(M98090_HPVOLR_WIDTH)
+
+/*
+ * M98090_REG_LEFT_SPK_MIXER		0x2E
+ */
+#define M98090_MIXSPL_MIC2_MASK         BIT(5)
+#define M98090_MIXSPL_MIC2_SHIFT        5
+#define M98090_MIXSPL_MIC2_WIDTH        1
+#define M98090_MIXSPL_MIC1_MASK         BIT(4)
+#define M98090_MIXSPL_MIC1_SHIFT        4
+#define M98090_MIXSPL_MIC1_WIDTH        1
+#define M98090_MIXSPL_LINEB_MASK        BIT(3)
+#define M98090_MIXSPL_LINEB_SHIFT       3
+#define M98090_MIXSPL_LINEB_WIDTH       1
+#define M98090_MIXSPL_LINEA_MASK        BIT(2)
+#define M98090_MIXSPL_LINEA_SHIFT       2
+#define M98090_MIXSPL_LINEA_WIDTH       1
+#define M98090_MIXSPL_DACR_MASK         BIT(1)
+#define M98090_MIXSPL_DACR_SHIFT        1
+#define M98090_MIXSPL_DACR_WIDTH        1
+#define M98090_MIXSPL_DACL_MASK         BIT(0)
+#define M98090_MIXSPL_DACL_SHIFT        0
+#define M98090_MIXSPL_DACL_WIDTH        1
+#define M98090_MIXSPL_MASK              (63 << 0)
+#define M98090_MIXSPL_SHIFT             0
+#define M98090_MIXSPL_WIDTH             6
+#define M98090_MIXSPR_DACR_MASK         BIT(1)
+#define M98090_MIXSPR_DACR_SHIFT        1
+#define M98090_MIXSPR_DACR_WIDTH        1
+
+/*
+ * M98090_REG_RIGHT_SPK_MIXER		0x2F
+ */
+#define M98090_SPK_SLAVE_MASK           BIT(6)
+#define M98090_SPK_SLAVE_SHIFT          6
+#define M98090_SPK_SLAVE_WIDTH          1
+#define M98090_MIXSPR_MIC2_MASK         BIT(5)
+#define M98090_MIXSPR_MIC2_SHIFT        5
+#define M98090_MIXSPR_MIC2_WIDTH        1
+#define M98090_MIXSPR_MIC1_MASK         BIT(4)
+#define M98090_MIXSPR_MIC1_SHIFT        4
+#define M98090_MIXSPR_MIC1_WIDTH        1
+#define M98090_MIXSPR_LINEB_MASK        BIT(3)
+#define M98090_MIXSPR_LINEB_SHIFT       3
+#define M98090_MIXSPR_LINEB_WIDTH       1
+#define M98090_MIXSPR_LINEA_MASK        BIT(2)
+#define M98090_MIXSPR_LINEA_SHIFT       2
+#define M98090_MIXSPR_LINEA_WIDTH       1
+#define M98090_MIXSPR_DACR_MASK         BIT(1)
+#define M98090_MIXSPR_DACR_SHIFT        1
+#define M98090_MIXSPR_DACR_WIDTH        1
+#define M98090_MIXSPR_DACL_MASK         BIT(0)
+#define M98090_MIXSPR_DACL_SHIFT        0
+#define M98090_MIXSPR_DACL_WIDTH        1
+#define M98090_MIXSPR_MASK              (63 << 0)
+#define M98090_MIXSPR_SHIFT             0
+#define M98090_MIXSPR_WIDTH             6
+
+/*
+ * M98090_REG_LEFT_SPK_VOLUME		0x31
+ */
+#define M98090_SPLM_MASK                BIT(7)
+#define M98090_SPLM_SHIFT               7
+#define M98090_SPLM_WIDTH               1
+#define M98090_SPVOLL_MASK              (63 << 0)
+#define M98090_SPVOLL_SHIFT             0
+#define M98090_SPVOLL_WIDTH             6
+#define M98090_SPVOLL_NUM               40
+
+/*
+ * M98090_REG_RIGHT_SPK_VOLUME		0x32
+ */
+#define M98090_SPRM_MASK                BIT(7)
+#define M98090_SPRM_SHIFT               7
+#define M98090_SPRM_WIDTH               1
+#define M98090_SPVOLR_MASK              (63 << 0)
+#define M98090_SPVOLR_SHIFT             0
+#define M98090_SPVOLR_WIDTH             6
+#define M98090_SPVOLR_NUM               40
+
+/*
+ * M98090_REG_RCV_LOUTL_MIXER		0x37
+ */
+#define M98090_MIXRCVL_MIC2_MASK        BIT(5)
+#define M98090_MIXRCVL_MIC2_SHIFT       5
+#define M98090_MIXRCVL_MIC2_WIDTH       1
+#define M98090_MIXRCVL_MIC1_MASK        BIT(4)
+#define M98090_MIXRCVL_MIC1_SHIFT       4
+#define M98090_MIXRCVL_MIC1_WIDTH       1
+#define M98090_MIXRCVL_LINEB_MASK       BIT(3)
+#define M98090_MIXRCVL_LINEB_SHIFT      3
+#define M98090_MIXRCVL_LINEB_WIDTH      1
+#define M98090_MIXRCVL_LINEA_MASK       BIT(2)
+#define M98090_MIXRCVL_LINEA_SHIFT      2
+#define M98090_MIXRCVL_LINEA_WIDTH      1
+#define M98090_MIXRCVL_DACR_MASK        BIT(1)
+#define M98090_MIXRCVL_DACR_SHIFT       1
+#define M98090_MIXRCVL_DACR_WIDTH       1
+#define M98090_MIXRCVL_DACL_MASK        BIT(0)
+#define M98090_MIXRCVL_DACL_SHIFT       0
+#define M98090_MIXRCVL_DACL_WIDTH       1
+#define M98090_MIXRCVL_MASK             (63 << 0)
+#define M98090_MIXRCVL_SHIFT            0
+#define M98090_MIXRCVL_WIDTH            6
+
+/*
+ * M98090_REG_RCV_LOUTL_CONTROL		0x38
+ */
+#define M98090_MIXRCVLG_MASK            (3 << 0)
+#define M98090_MIXRCVLG_SHIFT           0
+#define M98090_MIXRCVLG_WIDTH           2
+#define M98090_MIXRCVLG_NUM             BIT(M98090_MIXRCVLG_WIDTH)
+
+/*
+ * M98090_REG_RCV_LOUTL_VOLUME		0x39
+ */
+#define M98090_RCVLM_MASK               BIT(7)
+#define M98090_RCVLM_SHIFT              7
+#define M98090_RCVLM_WIDTH              1
+#define M98090_RCVLVOL_MASK             (31 << 0)
+#define M98090_RCVLVOL_SHIFT            0
+#define M98090_RCVLVOL_WIDTH            5
+#define M98090_RCVLVOL_NUM              BIT(M98090_RCVLVOL_WIDTH)
+
+/*
+ * M98090_REG_LOUTR_MIXER		0x3A
+ */
+#define M98090_LINMOD_MASK              BIT(7)
+#define M98090_LINMOD_SHIFT             7
+#define M98090_LINMOD_WIDTH             1
+#define M98090_MIXRCVR_MIC2_MASK        BIT(5)
+#define M98090_MIXRCVR_MIC2_SHIFT       5
+#define M98090_MIXRCVR_MIC2_WIDTH       1
+#define M98090_MIXRCVR_MIC1_MASK        BIT(4)
+#define M98090_MIXRCVR_MIC1_SHIFT       4
+#define M98090_MIXRCVR_MIC1_WIDTH       1
+#define M98090_MIXRCVR_LINEB_MASK       BIT(3)
+#define M98090_MIXRCVR_LINEB_SHIFT      3
+#define M98090_MIXRCVR_LINEB_WIDTH      1
+#define M98090_MIXRCVR_LINEA_MASK       BIT(2)
+#define M98090_MIXRCVR_LINEA_SHIFT      2
+#define M98090_MIXRCVR_LINEA_WIDTH      1
+#define M98090_MIXRCVR_DACR_MASK        BIT(1)
+#define M98090_MIXRCVR_DACR_SHIFT       1
+#define M98090_MIXRCVR_DACR_WIDTH       1
+#define M98090_MIXRCVR_DACL_MASK        BIT(0)
+#define M98090_MIXRCVR_DACL_SHIFT       0
+#define M98090_MIXRCVR_DACL_WIDTH       1
+#define M98090_MIXRCVR_MASK             (63 << 0)
+#define M98090_MIXRCVR_SHIFT            0
+#define M98090_MIXRCVR_WIDTH            6
+
+/*
+ * M98090_REG_LOUTR_VOLUME		0x3C
+ */
+#define M98090_RCVRM_MASK               BIT(7)
+#define M98090_RCVRM_SHIFT              7
+#define M98090_RCVRM_WIDTH              1
+#define M98090_RCVRVOL_MASK             (31 << 0)
+#define M98090_RCVRVOL_SHIFT            0
+#define M98090_RCVRVOL_WIDTH            5
+#define M98090_RCVRVOL_NUM              BIT(M98090_RCVRVOL_WIDTH)
+
+/*
+ * M98090_REG_JACK_DETECT		0x3D
+ */
+#define M98090_JDETEN_MASK              BIT(7)
+#define M98090_JDETEN_SHIFT             7
+#define M98090_JDETEN_WIDTH             1
+#define M98090_JDWK_MASK                BIT(6)
+#define M98090_JDWK_SHIFT               6
+#define M98090_JDWK_WIDTH               1
+#define M98090_JDEB_MASK                (3 << 0)
+#define M98090_JDEB_SHIFT               0
+#define M98090_JDEB_WIDTH               2
+#define M98090_JDEB_25MS                (0 << 0)
+#define M98090_JDEB_50MS                BIT(0)
+#define M98090_JDEB_100MS               (2 << 0)
+#define M98090_JDEB_200MS               (3 << 0)
+
+/*
+ * M98090_REG_INPUT_ENABLE		0x3E
+ */
+#define M98090_MBEN_MASK                BIT(4)
+#define M98090_MBEN_SHIFT               4
+#define M98090_MBEN_WIDTH               1
+#define M98090_LINEAEN_MASK             BIT(3)
+#define M98090_LINEAEN_SHIFT            3
+#define M98090_LINEAEN_WIDTH            1
+#define M98090_LINEBEN_MASK             BIT(2)
+#define M98090_LINEBEN_SHIFT            2
+#define M98090_LINEBEN_WIDTH            1
+#define M98090_ADREN_MASK               BIT(1)
+#define M98090_ADREN_SHIFT              1
+#define M98090_ADREN_WIDTH              1
+#define M98090_ADLEN_MASK               BIT(0)
+#define M98090_ADLEN_SHIFT              0
+#define M98090_ADLEN_WIDTH              1
+
+/*
+ * M98090_REG_OUTPUT_ENABLE		0x3F
+ */
+#define M98090_HPREN_MASK               BIT(7)
+#define M98090_HPREN_SHIFT              7
+#define M98090_HPREN_WIDTH              1
+#define M98090_HPLEN_MASK               BIT(6)
+#define M98090_HPLEN_SHIFT              6
+#define M98090_HPLEN_WIDTH              1
+#define M98090_SPREN_MASK               BIT(5)
+#define M98090_SPREN_SHIFT              5
+#define M98090_SPREN_WIDTH              1
+#define M98090_SPLEN_MASK               BIT(4)
+#define M98090_SPLEN_SHIFT              4
+#define M98090_SPLEN_WIDTH              1
+#define M98090_RCVLEN_MASK              BIT(3)
+#define M98090_RCVLEN_SHIFT             3
+#define M98090_RCVLEN_WIDTH             1
+#define M98090_RCVREN_MASK              BIT(2)
+#define M98090_RCVREN_SHIFT             2
+#define M98090_RCVREN_WIDTH             1
+#define M98090_DAREN_MASK               BIT(1)
+#define M98090_DAREN_SHIFT              1
+#define M98090_DAREN_WIDTH              1
+#define M98090_DALEN_MASK               BIT(0)
+#define M98090_DALEN_SHIFT              0
+#define M98090_DALEN_WIDTH              1
+
+/*
+ * M98090_REG_LEVEL_CONTROL		0x40
+ */
+#define M98090_ZDENN_MASK               BIT(2)
+#define M98090_ZDENN_SHIFT              2
+#define M98090_ZDENN_WIDTH              1
+#define M98090_ZDENN_NUM                BIT(M98090_ZDENN_WIDTH)
+#define M98090_VS2ENN_MASK              BIT(1)
+#define M98090_VS2ENN_SHIFT             1
+#define M98090_VS2ENN_WIDTH             1
+#define M98090_VS2ENN_NUM               BIT(M98090_VS2ENN_WIDTH)
+#define M98090_VSENN_MASK               BIT(0)
+#define M98090_VSENN_SHIFT              0
+#define M98090_VSENN_WIDTH              1
+#define M98090_VSENN_NUM                BIT(M98090_VSENN_WIDTH)
+
+/*
+ * M98090_REG_BIAS_CONTROL		0x42
+ */
+#define M98090_VCM_MODE_MASK            BIT(0)
+#define M98090_VCM_MODE_SHIFT           0
+#define M98090_VCM_MODE_WIDTH           1
+#define M98090_VCM_MODE_NUM             BIT(M98090_VCM_MODE_WIDTH)
+
+/*
+ * M98090_REG_DAC_CONTROL		0x43
+ */
+#define M98090_PERFMODE_MASK            BIT(1)
+#define M98090_PERFMODE_SHIFT           1
+#define M98090_PERFMODE_WIDTH           1
+#define M98090_PERFMODE_NUM             BIT(M98090_PERFMODE_WIDTH)
+#define M98090_DACHP_MASK               BIT(0)
+#define M98090_DACHP_SHIFT              0
+#define M98090_DACHP_WIDTH              1
+#define M98090_DACHP_NUM                BIT(M98090_DACHP_WIDTH)
+
+/*
+ * M98090_REG_ADC_CONTROL		0x44
+ */
+#define M98090_OSR128_MASK              BIT(2)
+#define M98090_OSR128_SHIFT             2
+#define M98090_OSR128_WIDTH             1
+#define M98090_ADCDITHER_MASK           BIT(1)
+#define M98090_ADCDITHER_SHIFT          1
+#define M98090_ADCDITHER_WIDTH          1
+#define M98090_ADCDITHER_NUM            BIT(M98090_ADCDITHER_WIDTH)
+#define M98090_ADCHP_MASK               BIT(0)
+#define M98090_ADCHP_SHIFT              0
+#define M98090_ADCHP_WIDTH              1
+#define M98090_ADCHP_NUM                BIT(M98090_ADCHP_WIDTH)
+
+/*
+ * M98090_REG_DEVICE_SHUTDOWN		0x45
+ */
+#define M98090_SHDNN_MASK               BIT(7)
+#define M98090_SHDNN_SHIFT              7
+#define M98090_SHDNN_WIDTH              1
+
+/*
+ * M98090_REG_REVISION_ID		0xFF
+ */
+#define M98090_REVID_MASK               (255 << 0)
+#define M98090_REVID_SHIFT              0
+#define M98090_REVID_WIDTH              8
+#define M98090_REVID_NUM                BIT(M98090_REVID_WIDTH)
+
+/* function prototype */
+
+/*
+ * initialise max98090 sound codec device for the given configuration
+ *
+ * @param blob			FDT node for codec values
+ * @param sampling_rate		Sampling rate (Hz)
+ * @param mclk_freq		MCLK Frequency (Hz)
+ * @param bits_per_sample	bits per Sample (must be 16 or 24)
+ *
+ * @returns -1 for error and 0 Success.
+ */
+int max98090_init(const void *blob, int sampling_rate, int mclk_freq,
+		  int bits_per_sample);
+int max98090_set_sysclk(struct maxim_priv *max98090, uint freq);
+int max98090_hw_params(struct maxim_priv *max98090, uint rate,
+		       uint bits_per_sample);
+int max98090_device_init(struct maxim_priv *max98090);
+int max98090_set_fmt(struct maxim_priv *max98090, int fmt);
+#endif
diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c
index 7c37bd0..99c0e99 100644
--- a/drivers/sound/max98095.c
+++ b/drivers/sound/max98095.c
@@ -1,113 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * max98095.c -- MAX98095 ALSA SoC Audio driver
  *
  * Copyright 2011 Maxim Integrated Products
  *
- * Modified for uboot by R. Chandrasekar (rcsekar@samsung.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Modified for U-Boot by R. Chandrasekar (rcsekar@samsung.com)
  */
 
 #include <common.h>
-#include <asm/arch/clk.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/power.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
 #include <div64.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
 #include "i2s.h"
 #include "max98095.h"
 
-enum max98095_type {
-	MAX98095,
-};
-
-struct max98095_priv {
-	enum max98095_type devtype;
-	unsigned int sysclk;
-	unsigned int rate;
-	unsigned int fmt;
-};
-
-static struct sound_codec_info g_codec_info;
-struct max98095_priv g_max98095_info;
-unsigned int g_max98095_i2c_dev_addr;
-
 /* Index 0 is reserved. */
 int rate_table[] = {0, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
 		88200, 96000};
 
 /*
- * Writes value to a device register through i2c
- *
- * @param reg	reg number to be write
- * @param data	data to be writen to the above registor
- *
- * @return	int value 1 for change, 0 for no change or negative error code.
- */
-static int max98095_i2c_write(unsigned int reg, unsigned char data)
-{
-	debug("%s: Write Addr : 0x%02X, Data :  0x%02X\n",
-	      __func__, reg, data);
-	return i2c_write(g_max98095_i2c_dev_addr, reg, 1, &data, 1);
-}
-
-/*
- * Read a value from a device register through i2c
- *
- * @param reg	reg number to be read
- * @param data	address of read data to be stored
- *
- * @return	int value 0 for success, -1 in case of error.
- */
-static unsigned int max98095_i2c_read(unsigned int reg, unsigned char *data)
-{
-	int ret;
-
-	ret = i2c_read(g_max98095_i2c_dev_addr, reg, 1, data, 1);
-	if (ret != 0) {
-		debug("%s: Error while reading register %#04x\n",
-		      __func__, reg);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * update device register bits through i2c
- *
- * @param reg	codec register
- * @param mask	register mask
- * @param value	new value
- *
- * @return int value 0 for success, non-zero error code.
- */
-static int max98095_update_bits(unsigned int reg, unsigned char mask,
-				unsigned char value)
-{
-	int change, ret = 0;
-	unsigned char old, new;
-
-	if (max98095_i2c_read(reg, &old) != 0)
-		return -1;
-	new = (old & ~mask) | (value & mask);
-	change  = (old != new) ? 1 : 0;
-	if (change)
-		ret = max98095_i2c_write(reg, new);
-	if (ret < 0)
-		return ret;
-
-	return change;
-}
-
-/*
  * codec mclk clock divider coefficients based on sampling rate
  *
  * @param rate sampling rate
@@ -127,19 +46,19 @@
 	}
 	*value = 1;
 
-	return -1;
+	return -EINVAL;
 }
 
 /*
  * Sets hw params for max98095
  *
- * @param max98095	max98095 information pointer
+ * @param priv		max98095 information pointer
  * @param rate		Sampling rate
  * @param bits_per_sample	Bits per sample
  *
- * @return -1 for error  and 0  Success.
+ * @return	0 for success or negative error code.
  */
-static int max98095_hw_params(struct max98095_priv *max98095,
+static int max98095_hw_params(struct maxim_priv *priv,
 			      enum en_max_audio_interface aif_id,
 			      unsigned int rate, unsigned int bits_per_sample)
 {
@@ -161,40 +80,39 @@
 
 	switch (bits_per_sample) {
 	case 16:
-		error = max98095_update_bits(M98095_DAI_FORMAT,
-					     M98095_DAI_WS, 0);
+		error = maxim_bic_or(priv, M98095_DAI_FORMAT, M98095_DAI_WS, 0);
 		break;
 	case 24:
-		error = max98095_update_bits(M98095_DAI_FORMAT,
-					     M98095_DAI_WS, M98095_DAI_WS);
+		error = maxim_bic_or(priv, M98095_DAI_FORMAT, M98095_DAI_WS,
+				     M98095_DAI_WS);
 		break;
 	default:
 		debug("%s: Illegal bits per sample %d.\n",
 		      __func__, bits_per_sample);
-		return -1;
+		return -EINVAL;
 	}
 
 	if (rate_value(rate, &regval)) {
 		debug("%s: Failed to set sample rate to %d.\n",
 		      __func__, rate);
-		return -1;
+		return -EINVAL;
 	}
-	max98095->rate = rate;
+	priv->rate = rate;
 
-	error |= max98095_update_bits(M98095_DAI_CLKMODE,
-				      M98095_CLKMODE_MASK, regval);
+	error |= maxim_bic_or(priv, M98095_DAI_CLKMODE, M98095_CLKMODE_MASK,
+				 regval);
 
 	/* Update sample rate mode */
 	if (rate < 50000)
-		error |= max98095_update_bits(M98095_DAI_FILTERS,
-					      M98095_DAI_DHF, 0);
+		error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
+					 M98095_DAI_DHF, 0);
 	else
-		error |= max98095_update_bits(M98095_DAI_FILTERS,
-					      M98095_DAI_DHF, M98095_DAI_DHF);
+		error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
+					 M98095_DAI_DHF, M98095_DAI_DHF);
 
 	if (error < 0) {
 		debug("%s: Error setting hardware params.\n", __func__);
-		return -1;
+		return -EIO;
 	}
 
 	return 0;
@@ -203,18 +121,17 @@
 /*
  * Configures Audio interface system clock for the given frequency
  *
- * @param max98095	max98095 information
+ * @param priv		max98095 information
  * @param freq		Sampling frequency in Hz
  *
- * @return -1 for error and 0 success.
+ * @return	0 for success or negative error code.
  */
-static int max98095_set_sysclk(struct max98095_priv *max98095,
-			       unsigned int freq)
+static int max98095_set_sysclk(struct maxim_priv *priv, unsigned int freq)
 {
 	int error = 0;
 
 	/* Requested clock frequency is already setup */
-	if (freq == max98095->sysclk)
+	if (freq == priv->sysclk)
 		return 0;
 
 	/* Setup clocks for slave mode, and using the PLL
@@ -223,35 +140,35 @@
 	 *	0x03 (when master clk is 40MHz to 60MHz)..
 	 */
 	if ((freq >= 10000000) && (freq < 20000000)) {
-		error = max98095_i2c_write(M98095_026_SYS_CLK, 0x10);
+		error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x10);
 	} else if ((freq >= 20000000) && (freq < 40000000)) {
-		error = max98095_i2c_write(M98095_026_SYS_CLK, 0x20);
+		error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x20);
 	} else if ((freq >= 40000000) && (freq < 60000000)) {
-		error = max98095_i2c_write(M98095_026_SYS_CLK, 0x30);
+		error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x30);
 	} else {
 		debug("%s: Invalid master clock frequency\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
 	debug("%s: Clock at %uHz\n", __func__, freq);
 
 	if (error < 0)
-		return -1;
+		return -EIO;
 
-	max98095->sysclk = freq;
+	priv->sysclk = freq;
 	return 0;
 }
 
 /*
  * Sets Max98095 I2S format
  *
- * @param max98095	max98095 information
+ * @param priv		max98095 information
  * @param fmt		i2S format - supports a subset of the options defined
  *			in i2s.h.
  *
- * @return -1 for error and 0  Success.
+ * @return	0 for success or negative error code.
  */
-static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
+static int max98095_set_fmt(struct maxim_priv *priv, int fmt,
 			    enum en_max_audio_interface aif_id)
 {
 	u8 regval = 0;
@@ -261,10 +178,10 @@
 	unsigned short M98095_DAI_FORMAT;
 	unsigned short M98095_DAI_CLOCK;
 
-	if (fmt == max98095->fmt)
+	if (fmt == priv->fmt)
 		return 0;
 
-	max98095->fmt = fmt;
+	priv->fmt = fmt;
 
 	if (aif_id == AIF1) {
 		M98095_DAI_CLKCFG_HI = M98095_028_DAI1_CLKCFG_HI;
@@ -281,10 +198,8 @@
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* Slave mode PLL */
-		error |= max98095_i2c_write(M98095_DAI_CLKCFG_HI,
-					0x80);
-		error |= max98095_i2c_write(M98095_DAI_CLKCFG_LO,
-					0x00);
+		error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_HI, 0x80);
+		error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_LO, 0x00);
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 		/* Set to master mode */
@@ -294,7 +209,7 @@
 	case SND_SOC_DAIFMT_CBM_CFS:
 	default:
 		debug("%s: Clock mode unsupported\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -305,7 +220,7 @@
 		break;
 	default:
 		debug("%s: Unrecognized format.\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -322,20 +237,18 @@
 		break;
 	default:
 		debug("%s: Unrecognized inversion settings.\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
-	error |= max98095_update_bits(M98095_DAI_FORMAT,
-				      M98095_DAI_MAS | M98095_DAI_DLY |
-				      M98095_DAI_BCI | M98095_DAI_WCI,
-				      regval);
+	error |= maxim_bic_or(priv, M98095_DAI_FORMAT,
+				 M98095_DAI_MAS | M98095_DAI_DLY |
+				 M98095_DAI_BCI | M98095_DAI_WCI, regval);
 
-	error |= max98095_i2c_write(M98095_DAI_CLOCK,
-				    M98095_DAI_BSEL64);
+	error |= maxim_i2c_write(priv, M98095_DAI_CLOCK, M98095_DAI_BSEL64);
 
 	if (error < 0) {
 		debug("%s: Error setting i2s format.\n", __func__);
-		return -1;
+		return -EIO;
 	}
 
 	return 0;
@@ -344,9 +257,10 @@
 /*
  * resets the audio codec
  *
- * @return -1 for error and 0 success.
+ * @param priv	Private data for driver
+ * @return	0 for success or negative error code.
  */
-static int max98095_reset(void)
+static int max98095_reset(struct maxim_priv *priv)
 {
 	int i, ret;
 
@@ -354,13 +268,13 @@
 	 * Gracefully reset the DSP core and the codec hardware in a proper
 	 * sequence.
 	 */
-	ret = max98095_i2c_write(M98095_00F_HOST_CFG, 0);
+	ret = maxim_i2c_write(priv, M98095_00F_HOST_CFG, 0);
 	if (ret != 0) {
 		debug("%s: Failed to reset DSP: %d\n", __func__, ret);
 		return ret;
 	}
 
-	ret = max98095_i2c_write(M98095_097_PWR_SYS, 0);
+	ret = maxim_i2c_write(priv, M98095_097_PWR_SYS, 0);
 	if (ret != 0) {
 		debug("%s: Failed to reset codec: %d\n", __func__, ret);
 		return ret;
@@ -371,7 +285,7 @@
 	 * reset hardware control register.
 	 */
 	for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
-		ret = max98095_i2c_write(i, 0);
+		ret = maxim_i2c_write(priv, i, 0);
 		if (ret < 0) {
 			debug("%s: Failed to reset: %d\n", __func__, ret);
 			return ret;
@@ -384,132 +298,128 @@
 /*
  * Intialise max98095 codec device
  *
- * @param max98095	max98095 information
- *
- * @returns -1 for error  and 0 Success.
+ * @param priv		max98095 information
+ * @return	0 for success or negative error code.
  */
-static int max98095_device_init(struct max98095_priv *max98095,
-				enum en_max_audio_interface aif_id)
+static int max98095_device_init(struct maxim_priv *priv)
 {
 	unsigned char id;
-	int error = 0;
+	int ret;
+
+	/* Enable codec clock */
+	set_xclkout();
 
 	/* reset the codec, the DSP core, and disable all interrupts */
-	error = max98095_reset();
-	if (error != 0) {
+	ret = max98095_reset(priv);
+	if (ret != 0) {
 		debug("Reset\n");
-		return error;
+		return ret;
 	}
 
 	/* initialize private data */
-	max98095->sysclk = -1U;
-	max98095->rate = -1U;
-	max98095->fmt = -1U;
+	priv->sysclk = -1U;
+	priv->rate = -1U;
+	priv->fmt = -1U;
 
-	error = max98095_i2c_read(M98095_0FF_REV_ID, &id);
-	if (error < 0) {
+	ret = maxim_i2c_read(priv, M98095_0FF_REV_ID, &id);
+	if (ret < 0) {
 		debug("%s: Failure reading hardware revision: %d\n",
 		      __func__, id);
-		goto err_access;
+		return ret;
 	}
 	debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A');
 
-	error |= max98095_i2c_write(M98095_097_PWR_SYS, M98095_PWRSV);
+	return 0;
+}
+
+static int max98095_setup_interface(struct maxim_priv *priv,
+				    enum en_max_audio_interface aif_id)
+{
+	int error;
+
+	error = maxim_i2c_write(priv, M98095_097_PWR_SYS, M98095_PWRSV);
 
 	/*
 	 * initialize registers to hardware default configuring audio
 	 * interface2 to DAC
 	 */
 	if (aif_id == AIF1)
-		error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
+		error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
 					    M98095_DAI1L_TO_DACL |
 					    M98095_DAI1R_TO_DACR);
 	else
-		error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
+		error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
 					    M98095_DAI2M_TO_DACL |
 					    M98095_DAI2M_TO_DACR);
 
-	error |= max98095_i2c_write(M98095_092_PWR_EN_OUT,
+	error |= maxim_i2c_write(priv, M98095_092_PWR_EN_OUT,
 				    M98095_SPK_SPREADSPECTRUM);
-	error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL);
+	error |= maxim_i2c_write(priv, M98095_04E_CFG_HP, M98095_HPNORMAL);
 	if (aif_id == AIF1)
-		error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG,
+		error |= maxim_i2c_write(priv, M98095_02C_DAI1_IOCFG,
 					    M98095_S1NORMAL | M98095_SDATA);
 	else
-		error |= max98095_i2c_write(M98095_036_DAI2_IOCFG,
+		error |= maxim_i2c_write(priv, M98095_036_DAI2_IOCFG,
 					    M98095_S2NORMAL | M98095_SDATA);
 
 	/* take the codec out of the shut down */
-	error |= max98095_update_bits(M98095_097_PWR_SYS, M98095_SHDNRUN,
-				      M98095_SHDNRUN);
-	/* route DACL and DACR output to HO and Spekers */
-	error |= max98095_i2c_write(M98095_050_MIX_SPK_LEFT, 0x01); /* DACL */
-	error |= max98095_i2c_write(M98095_051_MIX_SPK_RIGHT, 0x01);/* DACR */
-	error |= max98095_i2c_write(M98095_04C_MIX_HP_LEFT, 0x01);  /* DACL */
-	error |= max98095_i2c_write(M98095_04D_MIX_HP_RIGHT, 0x01); /* DACR */
+	error |= maxim_bic_or(priv, M98095_097_PWR_SYS, M98095_SHDNRUN,
+				 M98095_SHDNRUN);
+	/*
+	 * route DACL and DACR output to HO and Speakers
+	 * Ordering: DACL, DACR, DACL, DACR
+	 */
+	error |= maxim_i2c_write(priv, M98095_050_MIX_SPK_LEFT, 0x01);
+	error |= maxim_i2c_write(priv, M98095_051_MIX_SPK_RIGHT, 0x01);
+	error |= maxim_i2c_write(priv, M98095_04C_MIX_HP_LEFT, 0x01);
+	error |= maxim_i2c_write(priv, M98095_04D_MIX_HP_RIGHT, 0x01);
 
 	/* power Enable */
-	error |= max98095_i2c_write(M98095_091_PWR_EN_OUT, 0xF3);
+	error |= maxim_i2c_write(priv, M98095_091_PWR_EN_OUT, 0xF3);
 
 	/* set Volume */
-	error |= max98095_i2c_write(M98095_064_LVL_HP_L, 15);
-	error |= max98095_i2c_write(M98095_065_LVL_HP_R, 15);
-	error |= max98095_i2c_write(M98095_067_LVL_SPK_L, 16);
-	error |= max98095_i2c_write(M98095_068_LVL_SPK_R, 16);
+	error |= maxim_i2c_write(priv, M98095_064_LVL_HP_L, 15);
+	error |= maxim_i2c_write(priv, M98095_065_LVL_HP_R, 15);
+	error |= maxim_i2c_write(priv, M98095_067_LVL_SPK_L, 16);
+	error |= maxim_i2c_write(priv, M98095_068_LVL_SPK_R, 16);
 
 	/* Enable DAIs */
-	error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30);
+	error |= maxim_i2c_write(priv, M98095_093_BIAS_CTRL, 0x30);
 	if (aif_id == AIF1)
-		error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x01);
+		error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x01);
 	else
-		error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07);
+		error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x07);
 
-err_access:
 	if (error < 0)
-		return -1;
+		return -EIO;
 
 	return 0;
 }
 
-static int max98095_do_init(struct sound_codec_info *pcodec_info,
+static int max98095_do_init(struct maxim_priv *priv,
 			    enum en_max_audio_interface aif_id,
 			    int sampling_rate, int mclk_freq,
 			    int bits_per_sample)
 {
 	int ret = 0;
 
-	/* Enable codec clock */
-	set_xclkout();
-
-	/* shift the device address by 1 for 7 bit addressing */
-	g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1;
-
-	if (pcodec_info->codec_type == CODEC_MAX_98095) {
-		g_max98095_info.devtype = MAX98095;
-	} else {
-		debug("%s: Codec id [%d] not defined\n", __func__,
-		      pcodec_info->codec_type);
-		return -1;
-	}
-
-	ret = max98095_device_init(&g_max98095_info, aif_id);
+	ret = max98095_setup_interface(priv, aif_id);
 	if (ret < 0) {
-		debug("%s: max98095 codec chip init failed\n", __func__);
+		debug("%s: max98095 setup interface failed\n", __func__);
 		return ret;
 	}
 
-	ret = max98095_set_sysclk(&g_max98095_info, mclk_freq);
+	ret = max98095_set_sysclk(priv, mclk_freq);
 	if (ret < 0) {
 		debug("%s: max98095 codec set sys clock failed\n", __func__);
 		return ret;
 	}
 
-	ret = max98095_hw_params(&g_max98095_info, aif_id, sampling_rate,
+	ret = max98095_hw_params(priv, aif_id, sampling_rate,
 				 bits_per_sample);
 
 	if (ret == 0) {
-		ret = max98095_set_fmt(&g_max98095_info,
-				       SND_SOC_DAIFMT_I2S |
+		ret = max98095_set_fmt(priv, SND_SOC_DAIFMT_I2S |
 				       SND_SOC_DAIFMT_NB_NF |
 				       SND_SOC_DAIFMT_CBS_CFS,
 				       aif_id);
@@ -518,76 +428,45 @@
 	return ret;
 }
 
-static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
-				const void *blob)
+static int max98095_set_params(struct udevice *dev, int interface, int rate,
+			       int mclk_freq, int bits_per_sample,
+			       uint channels)
 {
-	int error = 0;
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-	enum fdt_compat_id compat;
-	int node;
-	int parent;
+	struct maxim_priv *priv = dev_get_priv(dev);
 
-	/* Get the node from FDT for codec */
-	node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC);
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for codec in device tree\n");
-		debug("node = %d\n", node);
-		return -1;
-	}
+	return max98095_do_init(priv, interface, rate, mclk_freq,
+				bits_per_sample);
+}
 
-	parent = fdt_parent_offset(blob, node);
-	if (parent < 0) {
-		debug("%s: Cannot find node parent\n", __func__);
-		return -1;
-	}
+static int max98095_probe(struct udevice *dev)
+{
+	struct maxim_priv *priv = dev_get_priv(dev);
+	int ret;
 
-	compat = fdtdec_lookup(blob, parent);
-	switch (compat) {
-	case COMPAT_SAMSUNG_S3C2440_I2C:
-		pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
-		error |= pcodec_info->i2c_bus;
-		debug("i2c bus = %d\n", pcodec_info->i2c_bus);
-		pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
-							"reg", 0);
-		error |= pcodec_info->i2c_dev_addr;
-		debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr);
-		break;
-	default:
-		debug("%s: Unknown compat id %d\n", __func__, compat);
-		return -1;
-	}
-#else
-	pcodec_info->i2c_bus = AUDIO_I2C_BUS;
-	pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
-	debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
-#endif
-	pcodec_info->codec_type = CODEC_MAX_98095;
-	if (error == -1) {
-		debug("fail to get max98095 codec node properties\n");
-		return -1;
+	priv->dev = dev;
+	ret = max98095_device_init(priv);
+	if (ret < 0) {
+		debug("%s: max98095 codec chip init failed\n", __func__);
+		return ret;
 	}
 
 	return 0;
 }
 
-/* max98095 Device Initialisation */
-int max98095_init(const void *blob, enum en_max_audio_interface aif_id,
-		  int sampling_rate, int mclk_freq,
-		  int bits_per_sample)
-{
-	int ret;
-	int old_bus = i2c_get_bus_num();
-	struct sound_codec_info *pcodec_info = &g_codec_info;
-
-	if (get_max98095_codec_values(pcodec_info, blob) < 0) {
-		debug("FDT Codec values failed\n");
-		return -1;
-	}
+static const struct audio_codec_ops max98095_ops = {
+	.set_params	= max98095_set_params,
+};
 
-	i2c_set_bus_num(pcodec_info->i2c_bus);
-	ret = max98095_do_init(pcodec_info, aif_id, sampling_rate, mclk_freq,
-			       bits_per_sample);
-	i2c_set_bus_num(old_bus);
+static const struct udevice_id max98095_ids[] = {
+	{ .compatible = "maxim,max98095" },
+	{ }
+};
 
-	return ret;
-}
+U_BOOT_DRIVER(max98095) = {
+	.name		= "max98095",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= max98095_ids,
+	.probe		= max98095_probe,
+	.ops		= &max98095_ops,
+	.priv_auto_alloc_size	= sizeof(struct maxim_priv),
+};
diff --git a/drivers/sound/max98095.h b/drivers/sound/max98095.h
index 44b1e3a..1521f3f 100644
--- a/drivers/sound/max98095.h
+++ b/drivers/sound/max98095.h
@@ -1,19 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * max98095.h -- MAX98095 ALSA SoC Audio driver
  *
  * Copyright 2011 Maxim Integrated Products
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef _MAX98095_H
 #define _MAX98095_H
 
+#include "maxim_codec.h"
+
 /*  Available audio interface ports in wm8994 codec */
 enum en_max_audio_interface {
-	AIF1 = 1,
+	AIF1,
 	AIF2,
 };
 
diff --git a/drivers/sound/maxim_codec.c b/drivers/sound/maxim_codec.c
new file mode 100644
index 0000000..dcaf081
--- /dev/null
+++ b/drivers/sound/maxim_codec.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * maxim_codec.c -- MAXIM CODEC Common driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include "maxim_codec.h"
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be write
+ * @param data	data to be writen to the above registor
+ *
+ * @return	int value 1 for change, 0 for no change or negative error code.
+ */
+int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
+		    unsigned char data)
+{
+	debug("%s: Write Addr : 0x%02X, Data :  0x%02X\n",
+	      __func__, reg, data);
+	return dm_i2c_write(priv->dev, reg, &data, 1);
+}
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be read
+ * @param data	address of read data to be stored
+ *
+ * @return	int value 0 for success, -1 in case of error.
+ */
+unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
+			    unsigned char *data)
+{
+	int ret;
+
+	return dm_i2c_read(priv->dev, reg, data, 1);
+	if (ret != 0) {
+		debug("%s: Error while reading register %#04x\n",
+		      __func__, reg);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * update device register bits through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	codec register
+ * @param mask	register mask
+ * @param value	new value
+ *
+ * @return int value 0 for success, non-zero error code.
+ */
+int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
+		 unsigned char value)
+{
+	int change, ret = 0;
+	unsigned char old, new;
+
+	if (maxim_i2c_read(priv, reg, &old) != 0)
+		return -1;
+	new = (old & ~mask) | (value & mask);
+	change  = (old != new) ? 1 : 0;
+	if (change)
+		ret = maxim_i2c_write(priv, reg, new);
+	if (ret < 0)
+		return ret;
+
+	return change;
+}
diff --git a/drivers/sound/maxim_codec.h b/drivers/sound/maxim_codec.h
new file mode 100644
index 0000000..a3128e0
--- /dev/null
+++ b/drivers/sound/maxim_codec.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * maxim_codec.h -- MAXIM codec common interface file
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * D Krishna Mohan <krishna.md@samsung.com>
+ */
+
+#ifndef __MAXIM_COMMON_H__
+#define __MAXIM_COMMON_H__
+
+enum maxim_codec_type {
+	MAX98095,
+	MAX98090,
+};
+
+struct maxim_priv {
+	enum maxim_codec_type devtype;
+	unsigned int sysclk;
+	unsigned int rate;
+	unsigned int fmt;
+	struct udevice *dev;
+};
+
+#define MAXIM_AUDIO_I2C_BUS		7
+#define MAXIM_AUDIO_I2C_REG_98095	0x22
+
+#define MAXIM_AUDIO_I2C_REG		MAXIM_AUDIO_I2C_REG_98095
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be write
+ * @param data	data to be writen to the above registor
+ *
+ * @return	int value 1 for change, 0 for no change or negative error code.
+ */
+int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
+		    unsigned char data);
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be read
+ * @param data	address of read data to be stored
+ *
+ * @return	int value 0 for success, -1 in case of error.
+ */
+unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
+			    unsigned char *data);
+
+/*
+ * update device register bits through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	codec register
+ * @param mask	register mask
+ * @param value	new value
+ *
+ * @return int value 0 for success, non-zero error code.
+ */
+int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
+		 unsigned char value);
+
+#endif /* __MAXIM_COMMON_H__ */
diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c
index f39abf5..c19e08e 100644
--- a/drivers/sound/samsung-i2s.c
+++ b/drivers/sound/samsung-i2s.c
@@ -4,13 +4,14 @@
  * R. Chandrasekar <rcsekar@samsung.com>
  */
 
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
 #include <asm/arch/clk.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/i2s-regs.h>
 #include <asm/io.h>
-#include <common.h>
-#include <sound.h>
-#include <i2s.h>
 
 #define FIC_TX2COUNT(x)		(((x) >>  24) & 0xf)
 #define FIC_TX1COUNT(x)		(((x) >>  16) & 0xf)
@@ -111,7 +112,7 @@
  * @param flush		Tx fifo flush command (0x00 - do not flush
  *				0x80 - flush tx fifo)
  */
-void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
+static void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
 {
 	/* Flush the FIFO */
 	setbits_le32(&i2s_reg->fic, flush);
@@ -126,7 +127,7 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
+static int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
 {
 	unsigned int mod = readl(&i2s_reg->mod);
 
@@ -148,7 +149,7 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
+static int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
 {
 	unsigned int mod = readl(&i2s_reg->mod);
 	unsigned int tmp = 0;
@@ -170,7 +171,7 @@
 	default:
 		debug("%s: Invalid format priority [0x%x]\n", __func__,
 		      (fmt & SND_SOC_DAIFMT_FORMAT_MASK));
-		return -1;
+		return -ERANGE;
 	}
 
 	/*
@@ -189,7 +190,7 @@
 	default:
 		debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
 		      (fmt & SND_SOC_DAIFMT_INV_MASK));
-		return -1;
+		return -ERANGE;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -201,13 +202,13 @@
 		ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT);
 		if (ret != 0) {
 			debug("%s:set i2s clock direction failed\n", __func__);
-			return -1;
+			return ret;
 		}
 		break;
 	default:
 		debug("%s: Invalid master selection [0x%x]\n", __func__,
 		      (fmt & SND_SOC_DAIFMT_MASTER_MASK));
-		return -1;
+		return -ERANGE;
 	}
 
 	mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
@@ -225,7 +226,7 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
+static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
 {
 	unsigned int mod = readl(&i2s_reg->mod);
 
@@ -248,43 +249,43 @@
 	default:
 		debug("%s: Invalid sample size input [0x%x]\n",
 		      __func__, blc);
-		return -1;
+		return -ERANGE;
 	}
 	writel(mod, &i2s_reg->mod);
 
 	return 0;
 }
 
-int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
-				unsigned long data_size)
+int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
+			 uint data_size)
 {
+	struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
+	u32 *ptr;
 	int i;
 	int start;
-	struct i2s_reg *i2s_reg =
-				(struct i2s_reg *)pi2s_tx->base_address;
 
 	if (data_size < FIFO_LENGTH) {
 		debug("%s : Invalid data size\n", __func__);
-		return -1; /* invalid pcm data size */
+		return -ENODATA; /* invalid pcm data size */
 	}
 
 	/* fill the tx buffer before stating the tx transmit */
-	for (i = 0; i < FIFO_LENGTH; i++)
-		writel(*data++, &i2s_reg->txd);
+	for (i = 0, ptr = data; i < FIFO_LENGTH; i++)
+		writel(*ptr++, &i2s_reg->txd);
 
-	data_size -= FIFO_LENGTH;
+	data_size -= sizeof(*ptr) * FIFO_LENGTH;
 	i2s_txctrl(i2s_reg, I2S_TX_ON);
 
 	while (data_size > 0) {
 		start = get_timer(0);
 		if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
-			writel(*data++, &i2s_reg->txd);
-			data_size--;
+			writel(*ptr++, &i2s_reg->txd);
+			data_size -= sizeof(*ptr);
 		} else {
 			if (get_timer(start) > TIMEOUT_I2S_TX) {
 				i2s_txctrl(i2s_reg, I2S_TX_OFF);
 				debug("%s: I2S Transfer Timeout\n", __func__);
-				return -1;
+				return -ETIMEDOUT;
 			}
 		}
 	}
@@ -293,11 +294,11 @@
 	return 0;
 }
 
-int i2s_tx_init(struct i2stx_info *pi2s_tx)
+int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
 {
 	int ret;
-	struct i2s_reg *i2s_reg =
-				(struct i2s_reg *)pi2s_tx->base_address;
+	struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
+
 	if (pi2s_tx->id == 0) {
 		/* Initialize GPIO for I2S-0 */
 		exynos_pinmux_config(PERIPH_ID_I2S0, 0);
@@ -312,20 +313,20 @@
 		ret = set_epll_clk(pi2s_tx->audio_pll_clk);
 	} else {
 		debug("%s: unsupported i2s-%d bus\n", __func__, pi2s_tx->id);
-		return -1;
+		return -ERANGE;
 	}
 
-	if (ret != 0) {
+	if (ret) {
 		debug("%s: epll clock set rate failed\n", __func__);
-		return -1;
+		return ret;
 	}
 
 	/* Select Clk Source for Audio 0 or 1 */
 	ret = set_i2s_clk_source(pi2s_tx->id);
-	if (ret == -1) {
+	if (ret) {
 		debug("%s: unsupported clock for i2s-%d\n", __func__,
 		      pi2s_tx->id);
-		return -1;
+		return ret;
 	}
 
 	if (pi2s_tx->id == 0) {
@@ -341,21 +342,21 @@
 				(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
 				pi2s_tx->id);
 	}
-	if (ret == -1) {
+	if (ret) {
 		debug("%s: unsupported prescalar for i2s-%d\n", __func__,
 		      pi2s_tx->id);
-		return -1;
+		return ret;
 	}
 
 	/* Configure I2s format */
-	ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-			  SND_SOC_DAIFMT_CBM_CFM));
+	ret = i2s_set_fmt(i2s_reg, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			  SND_SOC_DAIFMT_CBM_CFM);
 	if (ret == 0) {
 		i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
 		ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
 		if (ret != 0) {
 			debug("%s:set sample rate failed\n", __func__);
-			return -1;
+			return ret;
 		}
 
 		i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs);
@@ -368,3 +369,87 @@
 
 	return ret;
 }
+
+static int samsung_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+	return i2s_transfer_tx_data(priv, data, data_size);
+}
+
+static int samsung_i2s_probe(struct udevice *dev)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+	return i2s_tx_init(priv);
+}
+
+static int samsung_i2s_ofdata_to_platdata(struct udevice *dev)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+	ulong base;
+
+	/*
+	 * Get the pre-defined sound specific values from FDT.
+	 * All of these are expected to be correct otherwise
+	 * wrong register values in i2s setup parameters
+	 * may result in no sound play.
+	 */
+	base = dev_read_addr(dev);
+	if (base == FDT_ADDR_T_NONE) {
+		debug("%s: Missing  i2s base\n", __func__);
+		return -EINVAL;
+	}
+	priv->base_address = base;
+
+	if (dev_read_u32u(dev, "samsung,i2s-epll-clock-frequency",
+			  &priv->audio_pll_clk))
+		goto err;
+	debug("audio_pll_clk = %d\n", priv->audio_pll_clk);
+	if (dev_read_u32u(dev, "samsung,i2s-sampling-rate",
+			  &priv->samplingrate))
+		goto err;
+	debug("samplingrate = %d\n", priv->samplingrate);
+	if (dev_read_u32u(dev, "samsung,i2s-bits-per-sample",
+			  &priv->bitspersample))
+		goto err;
+	debug("bitspersample = %d\n", priv->bitspersample);
+	if (dev_read_u32u(dev, "samsung,i2s-channels", &priv->channels))
+		goto err;
+	debug("channels = %d\n", priv->channels);
+	if (dev_read_u32u(dev, "samsung,i2s-lr-clk-framesize", &priv->rfs))
+		goto err;
+	debug("rfs = %d\n", priv->rfs);
+	if (dev_read_u32u(dev, "samsung,i2s-bit-clk-framesize", &priv->bfs))
+		goto err;
+	debug("bfs = %d\n", priv->bfs);
+
+	if (dev_read_u32u(dev, "samsung,i2s-id", &priv->id))
+		goto err;
+	debug("id = %d\n", priv->id);
+
+	return 0;
+
+err:
+	debug("fail to get sound i2s node properties\n");
+
+	return -EINVAL;
+}
+
+static const struct i2s_ops samsung_i2s_ops = {
+	.tx_data	= samsung_i2s_tx_data,
+};
+
+static const struct udevice_id samsung_i2s_ids[] = {
+	{ .compatible = "samsung,s5pv210-i2s" },
+	{ }
+};
+
+U_BOOT_DRIVER(samsung_i2s) = {
+	.name		= "samsung_i2s",
+	.id		= UCLASS_I2S,
+	.of_match	= samsung_i2s_ids,
+	.probe		= samsung_i2s_probe,
+	.ofdata_to_platdata	= samsung_i2s_ofdata_to_platdata,
+	.ops		= &samsung_i2s_ops,
+};
diff --git a/drivers/sound/samsung_sound.c b/drivers/sound/samsung_sound.c
new file mode 100644
index 0000000..1d711c8
--- /dev/null
+++ b/drivers/sound/samsung_sound.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google, LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+
+static int samsung_sound_setup(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct i2s_uc_priv *i2c_priv = dev_get_uclass_priv(uc_priv->i2s);
+	int ret;
+
+	if (uc_priv->setup_done)
+		return -EALREADY;
+	ret = audio_codec_set_params(uc_priv->codec, i2c_priv->id,
+				     i2c_priv->samplingrate,
+				     i2c_priv->samplingrate * i2c_priv->rfs,
+				     i2c_priv->bitspersample,
+				     i2c_priv->channels);
+	if (ret)
+		return ret;
+	uc_priv->setup_done = true;
+
+	return 0;
+}
+
+static int samsung_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int samsung_sound_probe(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct ofnode_phandle_args args;
+	struct gpio_desc en_gpio;
+	ofnode node;
+	int ret;
+
+	ret = gpio_request_by_name(dev, "codec-enable-gpio", 0, &en_gpio,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+	/* Turn on the GPIO which connects to the codec's "enable" line. */
+	if (!ret)
+		gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
+
+	ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
+					   "samsung,audio-codec",
+					   &uc_priv->codec);
+	if (ret) {
+		debug("Failed to probe audio codec\n");
+		return ret;
+	}
+	node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
+	if (!ofnode_valid(node)) {
+		debug("Failed to find /cpu subnode\n");
+		return -EINVAL;
+	}
+	ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+					     "#sound-dai-cells", 0, 0, &args);
+	if (ret) {
+		debug("Cannot find phandle: %d\n", ret);
+		return ret;
+	}
+	ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+	if (ret) {
+		debug("Cannot find i2s: %d\n", ret);
+		return ret;
+	}
+	debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+	      uc_priv->codec->name, uc_priv->i2s->name);
+
+	return 0;
+}
+
+static const struct sound_ops samsung_sound_ops = {
+	.setup	= samsung_sound_setup,
+	.play	= samsung_sound_play,
+};
+
+static const struct udevice_id samsung_sound_ids[] = {
+	{ .compatible = "google,snow-audio-max98095" },
+	{ .compatible = "google,spring-audio-max98095" },
+	{ .compatible = "samsung,smdk5420-audio-wm8994" },
+	{ .compatible = "google,peach-audio-max98090" },
+	{ }
+};
+
+U_BOOT_DRIVER(samsung_sound) = {
+	.name		= "samsung_sound",
+	.id		= UCLASS_SOUND,
+	.of_match	= samsung_sound_ids,
+	.probe		= samsung_sound_probe,
+	.ops		= &samsung_sound_ops,
+};
diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c
index 94eff54..b0b07f3 100644
--- a/drivers/sound/sandbox.c
+++ b/drivers/sound/sandbox.c
@@ -4,19 +4,185 @@
  */
 
 #include <common.h>
-#include <asm/sound.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
 #include <asm/sdl.h>
 
-int sound_play(uint32_t msec, uint32_t frequency)
+struct sandbox_codec_priv {
+	int interface;
+	int rate;
+	int mclk_freq;
+	int bits_per_sample;
+	uint channels;
+};
+
+struct sandbox_i2s_priv {
+	int sum;	/* Use to sum the provided audio data */
+};
+
+struct sandbox_sound_priv {
+	int setup_called;
+	int sum;	/* Use to sum the provided audio data */
+};
+
+void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
+			      int *mclk_freqp, int *bits_per_samplep,
+			      uint *channelsp)
+{
+	struct sandbox_codec_priv *priv = dev_get_priv(dev);
+
+	*interfacep = priv->interface;
+	*ratep = priv->rate;
+	*mclk_freqp = priv->mclk_freq;
+	*bits_per_samplep = priv->bits_per_sample;
+	*channelsp = priv->channels;
+}
+
+int sandbox_get_i2s_sum(struct udevice *dev)
+{
+	struct sandbox_i2s_priv *priv = dev_get_priv(dev);
+
+	return priv->sum;
+}
+
+int sandbox_get_setup_called(struct udevice *dev)
+{
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+	return priv->setup_called;
+}
+
+int sandbox_get_sound_sum(struct udevice *dev)
+{
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+	return priv->sum;
+}
+
+static int sandbox_codec_set_params(struct udevice *dev, int interface,
+				    int rate, int mclk_freq,
+				    int bits_per_sample, uint channels)
+{
+	struct sandbox_codec_priv *priv = dev_get_priv(dev);
+
+	priv->interface = interface;
+	priv->rate = rate;
+	priv->mclk_freq = mclk_freq;
+	priv->bits_per_sample = bits_per_sample;
+	priv->channels = channels;
+
+	return 0;
+}
+
+static int sandbox_i2s_tx_data(struct udevice *dev, void *data,
+			       uint data_size)
+{
+	struct sandbox_i2s_priv *priv = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < data_size; i++)
+		priv->sum += ((uint8_t *)data)[i];
+
+	return sandbox_sdl_sound_play(data, data_size);
+}
+
+static int sandbox_i2s_probe(struct udevice *dev)
 {
-	sandbox_sdl_sound_start(frequency);
-	mdelay(msec);
-	sandbox_sdl_sound_stop();
+	struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	/* Use hard-coded values here */
+	uc_priv->rfs = 256;
+	uc_priv->bfs = 32;
+	uc_priv->audio_pll_clk = 192000000;
+	uc_priv->samplingrate = 48000;
+	uc_priv->bitspersample = 16;
+	uc_priv->channels = 2;
+	uc_priv->id = 1;
+
+	/* Ignore any error here - we'll just have no sound */
+	sandbox_sdl_sound_init(uc_priv->samplingrate, uc_priv->channels);
 
 	return 0;
 }
 
+static int sandbox_sound_setup(struct udevice *dev)
+{
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+	priv->setup_called++;
+
+	return 0;
+}
+
+static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < data_size; i++)
+		priv->sum += ((uint8_t *)data)[i];
+
+	return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
-int sound_init(const void *blob)
+static int sandbox_sound_probe(struct udevice *dev)
 {
-	return sandbox_sdl_sound_init();
+	return sound_find_codec_i2s(dev);
 }
+
+static const struct audio_codec_ops sandbox_codec_ops = {
+	.set_params	= sandbox_codec_set_params,
+};
+
+static const struct udevice_id sandbox_codec_ids[] = {
+	{ .compatible = "sandbox,audio-codec" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_codec) = {
+	.name		= "sandbox_codec",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= sandbox_codec_ids,
+	.ops		= &sandbox_codec_ops,
+	.priv_auto_alloc_size	= sizeof(struct sandbox_codec_priv),
+};
+
+static const struct i2s_ops sandbox_i2s_ops = {
+	.tx_data	= sandbox_i2s_tx_data,
+};
+
+static const struct udevice_id sandbox_i2s_ids[] = {
+	{ .compatible = "sandbox,i2s" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_i2s) = {
+	.name		= "sandbox_i2s",
+	.id		= UCLASS_I2S,
+	.of_match	= sandbox_i2s_ids,
+	.ops		= &sandbox_i2s_ops,
+	.probe		= sandbox_i2s_probe,
+	.priv_auto_alloc_size	= sizeof(struct sandbox_i2s_priv),
+};
+
+static const struct sound_ops sandbox_sound_ops = {
+	.setup	= sandbox_sound_setup,
+	.play	= sandbox_sound_play,
+};
+
+static const struct udevice_id sandbox_sound_ids[] = {
+	{ .compatible = "sandbox,sound" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_sound) = {
+	.name		= "sandbox_sound",
+	.id		= UCLASS_SOUND,
+	.of_match	= sandbox_sound_ids,
+	.ops		= &sandbox_sound_ops,
+	.priv_auto_alloc_size	= sizeof(struct sandbox_sound_priv),
+	.probe		= sandbox_sound_probe,
+};
diff --git a/drivers/sound/sound-i2s.c b/drivers/sound/sound-i2s.c
deleted file mode 100644
index f0f0b79..0000000
--- a/drivers/sound/sound-i2s.c
+++ /dev/null
@@ -1,208 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2012 Samsung Electronics
- * R. Chandrasekar <rcsekar@samsung.com>
- */
-
-#include <malloc.h>
-#include <common.h>
-#include <asm/io.h>
-#include <linux/libfdt.h>
-#include <fdtdec.h>
-#include <i2c.h>
-#include <i2s.h>
-#include <sound.h>
-#include <asm/arch/sound.h>
-#include "wm8994.h"
-#include "max98095.h"
-
-/* defines */
-#define SOUND_400_HZ 400
-#define SOUND_BITS_IN_BYTE 8
-
-static struct i2stx_info g_i2stx_pri;
-
-/*
- * get_sound_i2s_values gets values for i2s parameters
- *
- * @param i2stx_info	i2s transmitter transfer param structure
- * @param blob		FDT blob if enabled else NULL
- */
-static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)
-{
-	int node;
-	int error = 0;
-	int base;
-
-	node = fdt_path_offset(blob, "i2s");
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for sound in device tree\n");
-		return -1;
-	}
-
-	/*
-	 * Get the pre-defined sound specific values from FDT.
-	 * All of these are expected to be correct otherwise
-	 * wrong register values in i2s setup parameters
-	 * may result in no sound play.
-	 */
-	base = fdtdec_get_addr(blob, node, "reg");
-	if (base == FDT_ADDR_T_NONE) {
-		debug("%s: Missing  i2s base\n", __func__);
-		return -1;
-	}
-	i2s->base_address = base;
-
-	i2s->audio_pll_clk = fdtdec_get_int(blob,
-				node, "samsung,i2s-epll-clock-frequency", -1);
-	error |= i2s->audio_pll_clk;
-	debug("audio_pll_clk = %d\n", i2s->audio_pll_clk);
-	i2s->samplingrate = fdtdec_get_int(blob,
-				node, "samsung,i2s-sampling-rate", -1);
-	error |= i2s->samplingrate;
-	debug("samplingrate = %d\n", i2s->samplingrate);
-	i2s->bitspersample = fdtdec_get_int(blob,
-				node, "samsung,i2s-bits-per-sample", -1);
-	error |= i2s->bitspersample;
-	debug("bitspersample = %d\n", i2s->bitspersample);
-	i2s->channels = fdtdec_get_int(blob,
-			node, "samsung,i2s-channels", -1);
-	error |= i2s->channels;
-	debug("channels = %d\n", i2s->channels);
-	i2s->rfs = fdtdec_get_int(blob,
-				node, "samsung,i2s-lr-clk-framesize", -1);
-	error |= i2s->rfs;
-	debug("rfs = %d\n", i2s->rfs);
-	i2s->bfs = fdtdec_get_int(blob,
-				node, "samsung,i2s-bit-clk-framesize", -1);
-	error |= i2s->bfs;
-	debug("bfs = %d\n", i2s->bfs);
-
-	i2s->id = fdtdec_get_int(blob, node, "samsung,i2s-id", -1);
-	error |= i2s->id;
-	debug("id = %d\n", i2s->id);
-
-	if (error == -1) {
-		debug("fail to get sound i2s node properties\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * Init codec
- *
- * @param blob          FDT blob
- * @param pi2s_tx	i2s parameters required by codec
- * @return              int value, 0 for success
- */
-static int codec_init(const void *blob, struct i2stx_info *pi2s_tx)
-{
-	int ret;
-	const char *codectype;
-	int node;
-
-	/* Get the node from FDT for sound */
-	node = fdt_path_offset(blob, "i2s");
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for sound in device tree\n");
-		debug("node = %d\n", node);
-		return -1;
-	}
-
-	/*
-	 * Get the pre-defined sound codec specific values from FDT.
-	 * All of these are expected to be correct otherwise sound
-	 * can not be played
-	 */
-	codectype = fdt_getprop(blob, node, "samsung,codec-type", NULL);
-	debug("device = %s\n", codectype);
-	if (!strcmp(codectype, "wm8994")) {
-		/* Check the codec type and initialise the same */
-		ret = wm8994_init(blob, pi2s_tx->id + 1,
-				  pi2s_tx->samplingrate,
-				  (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
-				  pi2s_tx->bitspersample, pi2s_tx->channels);
-	} else if (!strcmp(codectype, "max98095")) {
-		ret = max98095_init(blob, pi2s_tx->id + 1,
-				    pi2s_tx->samplingrate,
-				    (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
-				    pi2s_tx->bitspersample);
-	} else {
-		debug("%s: Unknown codec type %s\n", __func__, codectype);
-		return -1;
-	}
-
-	if (ret) {
-		debug("%s: Codec init failed\n", __func__);
-		return -1;
-	}
-
-	return 0;
-}
-
-int sound_init(const void *blob)
-{
-	int ret;
-	struct i2stx_info *pi2s_tx = &g_i2stx_pri;
-
-	/* Get the I2S Values */
-	if (get_sound_i2s_values(pi2s_tx, blob) < 0) {
-		debug(" FDT I2S values failed\n");
-		return -1;
-	}
-
-	if (codec_init(blob, pi2s_tx) < 0) {
-		debug(" Codec init failed\n");
-		return -1;
-	}
-
-	ret = i2s_tx_init(pi2s_tx);
-	if (ret) {
-		debug("%s: Failed to init i2c transmit: ret=%d\n", __func__,
-		      ret);
-		return ret;
-	}
-
-
-	return ret;
-}
-
-int sound_play(uint32_t msec, uint32_t frequency)
-{
-	unsigned int *data;
-	unsigned long data_size;
-	unsigned int ret = 0;
-
-	/*Buffer length computation */
-	data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels;
-	data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE);
-	data = malloc(data_size);
-
-	if (data == NULL) {
-		debug("%s: malloc failed\n", __func__);
-		return -1;
-	}
-
-	sound_create_square_wave(g_i2stx_pri.samplingrate,
-				 (unsigned short *)data,
-				 data_size / sizeof(unsigned short),
-				 frequency);
-
-	while (msec >= 1000) {
-		ret = i2s_transfer_tx_data(&g_i2stx_pri, data,
-					   (data_size / sizeof(int)));
-		msec -= 1000;
-	}
-	if (msec) {
-		unsigned long size =
-			(data_size * msec) / (sizeof(int) * 1000);
-
-		ret = i2s_transfer_tx_data(&g_i2stx_pri, data, size);
-	}
-
-	free(data);
-
-	return ret;
-}
diff --git a/drivers/sound/sound-uclass.c b/drivers/sound/sound-uclass.c
new file mode 100644
index 0000000..2b83626
--- /dev/null
+++ b/drivers/sound/sound-uclass.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
+
+#define SOUND_BITS_IN_BYTE 8
+
+int sound_setup(struct udevice *dev)
+{
+	struct sound_ops *ops = sound_get_ops(dev);
+
+	if (!ops->setup)
+		return -ENOSYS;
+
+	return ops->setup(dev);
+}
+
+int sound_play(struct udevice *dev, void *data, uint data_size)
+{
+	struct sound_ops *ops = sound_get_ops(dev);
+
+	if (!ops->play)
+		return -ENOSYS;
+
+	return ops->play(dev, data, data_size);
+}
+
+int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct i2s_uc_priv *i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s);
+	unsigned short *data;
+	uint data_size;
+	int ret;
+
+	ret = sound_setup(dev);
+	if (ret && ret != -EALREADY)
+		return ret;
+
+	/* Buffer length computation */
+	data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels;
+	data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE);
+	data = malloc(data_size);
+	if (!data) {
+		debug("%s: malloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size,
+				 frequency_hz, i2s_uc_priv->channels);
+
+	while (msecs >= 1000) {
+		ret = sound_play(dev, data, data_size);
+		msecs -= 1000;
+	}
+	if (msecs) {
+		unsigned long size =
+			(data_size * msecs) / (sizeof(int) * 1000);
+
+		ret = sound_play(dev, data, size);
+	}
+
+	free(data);
+
+	return ret;
+}
+
+int sound_find_codec_i2s(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct ofnode_phandle_args args;
+	ofnode node;
+	int ret;
+
+	/* First the codec */
+	node = ofnode_find_subnode(dev_ofnode(dev), "codec");
+	if (!ofnode_valid(node)) {
+		debug("Failed to find /cpu subnode\n");
+		return -EINVAL;
+	}
+	ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+					     "#sound-dai-cells", 0, 0, &args);
+	if (ret) {
+		debug("Cannot find phandle: %d\n", ret);
+		return ret;
+	}
+	ret = uclass_get_device_by_ofnode(UCLASS_AUDIO_CODEC, args.node,
+					  &uc_priv->codec);
+	if (ret) {
+		debug("Cannot find codec: %d\n", ret);
+		return ret;
+	}
+
+	/* Now the i2s */
+	node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
+	if (!ofnode_valid(node)) {
+		debug("Failed to find /cpu subnode\n");
+		return -EINVAL;
+	}
+	ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+					     "#sound-dai-cells", 0, 0, &args);
+	if (ret) {
+		debug("Cannot find phandle: %d\n", ret);
+		return ret;
+	}
+	ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+	if (ret) {
+		debug("Cannot find i2s: %d\n", ret);
+		return ret;
+	}
+	debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+	      uc_priv->codec->name, uc_priv->i2s->name);
+
+	return 0;
+}
+
+UCLASS_DRIVER(sound) = {
+	.id		= UCLASS_SOUND,
+	.name		= "sound",
+	.per_device_auto_alloc_size	= sizeof(struct sound_uc_priv),
+};
diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c
index 4f0ad0d..dd3f9db 100644
--- a/drivers/sound/sound.c
+++ b/drivers/sound/sound.c
@@ -8,7 +8,7 @@
 #include <sound.h>
 
 void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
-			      uint freq)
+			      uint freq, uint channels)
 {
 	const unsigned short amplitude = 16000; /* between 1 and 32767 */
 	const int period = freq ? sample_rate / freq : 0;
@@ -21,14 +21,17 @@
 		size--;
 
 	while (size) {
-		int i;
+		int i, j;
+
 		for (i = 0; size && i < half; i++) {
 			size -= 2;
-			*data++ = amplitude;
+			for (j = 0; j < channels; j++)
+				*data++ = amplitude;
 		}
 		for (i = 0; size && i < period - half; i++) {
 			size -= 2;
-			*data++ = -amplitude;
+			for (j = 0; j < channels; j++)
+				*data++ = -amplitude;
 		}
 	}
 }
diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c
index aaaa324..b290c4e 100644
--- a/drivers/sound/wm8994.c
+++ b/drivers/sound/wm8994.c
@@ -4,15 +4,17 @@
  * R. Chandrasekar <rcsekar@samsung.com>
  */
 #include <common.h>
-#include <asm/arch/clk.h>
-#include <asm/arch/cpu.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
+#include <audio_codec.h>
+#include <dm.h>
 #include <div64.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <i2s.h>
 #include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
 #include <asm/arch/sound.h>
 #include "wm8994.h"
 #include "wm8994_registers.h"
@@ -38,6 +40,7 @@
 	int mclk[WM8994_MAX_AIF];	/* master clock frequency in Hz */
 	int aifclk[WM8994_MAX_AIF];	/* audio interface clock in Hz   */
 	struct wm8994_fll_config fll[2]; /* fll config to configure fll */
+	struct udevice *dev;
 };
 
 /* wm 8994 supported sampling rate values */
@@ -60,29 +63,17 @@
 	640, 880, 960, 1280, 1760, 1920
 };
 
-static struct wm8994_priv g_wm8994_info;
-static unsigned char g_wm8994_i2c_dev_addr;
-static struct sound_codec_info g_codec_info;
-
-/*
- * Initialise I2C for wm 8994
- *
- * @param bus no	i2c bus number in which wm8994 is connected
- */
-static void wm8994_i2c_init(int bus_no)
-{
-	i2c_set_bus_num(bus_no);
-}
-
 /*
  * Writes value to a device register through i2c
  *
+ * @param priv	Private data for driver
  * @param reg	reg number to be write
  * @param data	data to be writen to the above registor
  *
  * @return	int value 1 for change, 0 for no change or negative error code.
  */
-static int wm8994_i2c_write(unsigned int reg, unsigned short data)
+static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg,
+			    unsigned short data)
 {
 	unsigned char val[2];
 
@@ -90,23 +81,25 @@
 	val[1] = (unsigned char)(data & 0xff);
 	debug("Write Addr : 0x%04X, Data :  0x%04X\n", reg, data);
 
-	return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+	return dm_i2c_write(priv->dev, reg, val, 2);
 }
 
 /*
  * Read a value from a device register through i2c
  *
+ * @param priv	Private data for driver
  * @param reg	reg number to be read
  * @param data	address of read data to be stored
  *
  * @return	int value 0 for success, -1 in case of error.
  */
-static unsigned int  wm8994_i2c_read(unsigned int reg , unsigned short *data)
+static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg,
+				    unsigned short *data)
 {
 	unsigned char val[2];
 	int ret;
 
-	ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+	ret = dm_i2c_read(priv->dev, reg, val, 1);
 	if (ret != 0) {
 		debug("%s: Error while reading register %#04x\n",
 		      __func__, reg);
@@ -123,6 +116,7 @@
 /*
  * update device register bits through i2c
  *
+ * @param priv	Private data for driver
  * @param reg	codec register
  * @param mask	register mask
  * @param value	new value
@@ -130,18 +124,18 @@
  * @return int value 1 if change in the register value,
  * 0 for no change or negative error code.
  */
-static int wm8994_update_bits(unsigned int reg, unsigned short mask,
-						unsigned short value)
+static int wm8994_bic_or(struct wm8994_priv *priv, unsigned int reg,
+			 unsigned short mask, unsigned short value)
 {
 	int change , ret = 0;
 	unsigned short old, new;
 
-	if (wm8994_i2c_read(reg, &old) != 0)
+	if (wm8994_i2c_read(priv, reg, &old) != 0)
 		return -1;
 	new = (old & ~mask) | (value & mask);
 	change  = (old != new) ? 1 : 0;
 	if (change)
-		ret = wm8994_i2c_write(reg, new);
+		ret = wm8994_i2c_write(priv, reg, new);
 	if (ret < 0)
 		return ret;
 
@@ -151,12 +145,13 @@
 /*
  * Sets i2s set format
  *
+ * @param priv		wm8994 information
  * @param aif_id	Interface ID
  * @param fmt		i2S format
  *
  * @return -1 for error and 0  Success.
  */
-int wm8994_set_fmt(int aif_id, unsigned int fmt)
+static int wm8994_set_fmt(struct wm8994_priv *priv, int aif_id, uint fmt)
 {
 	int ms_reg;
 	int aif_reg;
@@ -254,12 +249,13 @@
 		return -1;
 	}
 
-	error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV |
-			WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif);
+	error = wm8994_bic_or(priv, aif_reg, WM8994_AIF1_BCLK_INV |
+			      WM8994_AIF1_LRCLK_INV_MASK |
+			       WM8994_AIF1_FMT_MASK, aif);
 
-	error |= wm8994_update_bits(ms_reg, WM8994_AIF1_MSTR_MASK, ms);
-	error |= wm8994_update_bits(aif_clk, WM8994_AIF1CLK_ENA_MASK,
-						WM8994_AIF1CLK_ENA);
+	error |= wm8994_bic_or(priv, ms_reg, WM8994_AIF1_MSTR_MASK, ms);
+	error |= wm8994_bic_or(priv, aif_clk, WM8994_AIF1CLK_ENA_MASK,
+			       WM8994_AIF1CLK_ENA);
 	if (error < 0) {
 		debug("%s: codec register access error\n", __func__);
 		return -1;
@@ -271,7 +267,7 @@
 /*
  * Sets hw params FOR WM8994
  *
- * @param wm8994		wm8994 information pointer
+ * @param priv			wm8994 information pointer
  * @param aif_id		Audio interface ID
  * @param sampling_rate		Sampling rate
  * @param bits_per_sample	Bits per sample
@@ -279,9 +275,9 @@
  *
  * @return -1 for error  and 0  Success.
  */
-static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
-		unsigned int sampling_rate, unsigned int bits_per_sample,
-		unsigned int channels)
+static int wm8994_hw_params(struct wm8994_priv *priv, int aif_id,
+			    uint sampling_rate, uint bits_per_sample,
+			    uint channels)
 {
 	int aif1_reg;
 	int aif2_reg;
@@ -349,12 +345,10 @@
 
 	/* AIFCLK/fs ratio; look for a close match in either direction */
 	best = 0;
-	best_val = abs((fs_ratios[0] * sampling_rate)
-						- wm8994->aifclk[id]);
+	best_val = abs((fs_ratios[0] * sampling_rate) - priv->aifclk[id]);
 
 	for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
-		cur_val = abs((fs_ratios[i] * sampling_rate)
-					- wm8994->aifclk[id]);
+		cur_val = abs(fs_ratios[i] * sampling_rate - priv->aifclk[id]);
 		if (cur_val >= best_val)
 			continue;
 		best = i;
@@ -371,7 +365,7 @@
 	 */
 	best = 0;
 	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
-		cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
+		cur_val = (priv->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
 		if (cur_val < 0) /* BCLK table is sorted */
 			break;
 		best = i;
@@ -383,10 +377,10 @@
 		return -1;
 	}
 
-	bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
+	bclk_rate = priv->aifclk[id] * 10 / bclk_divs[best];
 	bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
 
-	if (wm8994_i2c_read(aif1_reg, &reg_data) != 0) {
+	if (wm8994_i2c_read(priv, aif1_reg, &reg_data) != 0) {
 		debug("%s: AIF1 register read Failed\n", __func__);
 		return -1;
 	}
@@ -394,16 +388,17 @@
 	if ((channels == 1) && ((reg_data & 0x18) == 0x18))
 		aif2 |= WM8994_AIF1_MONO;
 
-	if (wm8994->aifclk[id] == 0) {
+	if (priv->aifclk[id] == 0) {
 		debug("%s:Audio interface clock not set\n", __func__);
 		return -1;
 	}
 
-	ret = wm8994_update_bits(aif1_reg, WM8994_AIF1_WL_MASK, aif1);
-	ret |= wm8994_update_bits(aif2_reg, WM8994_AIF1_MONO, aif2);
-	ret |= wm8994_update_bits(bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
-	ret |= wm8994_update_bits(rate_reg, WM8994_AIF1_SR_MASK |
-				WM8994_AIF1CLK_RATE_MASK, rate_val);
+	ret = wm8994_bic_or(priv, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+	ret |= wm8994_bic_or(priv, aif2_reg, WM8994_AIF1_MONO, aif2);
+	ret |= wm8994_bic_or(priv, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK,
+				  bclk);
+	ret |= wm8994_bic_or(priv, rate_reg, WM8994_AIF1_SR_MASK |
+				  WM8994_AIF1CLK_RATE_MASK, rate_val);
 
 	debug("rate vale = %x , bclk val= %x\n", rate_val, bclk);
 
@@ -418,12 +413,12 @@
 /*
  * Configures Audio interface Clock
  *
- * @param wm8994	wm8994 information pointer
+ * @param priv		wm8994 information pointer
  * @param aif		Audio Interface ID
  *
  * @return -1 for error  and 0  Success.
  */
-static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
+static int configure_aif_clock(struct wm8994_priv *priv, int aif)
 {
 	int rate;
 	int reg1 = 0;
@@ -436,30 +431,30 @@
 	else
 		offset = 0;
 
-	switch (wm8994->sysclk[aif-1]) {
+	switch (priv->sysclk[aif - 1]) {
 	case WM8994_SYSCLK_MCLK1:
 		reg1 |= SEL_MCLK1;
-		rate = wm8994->mclk[0];
+		rate = priv->mclk[0];
 		break;
 
 	case WM8994_SYSCLK_MCLK2:
 		reg1 |= SEL_MCLK2;
-		rate = wm8994->mclk[1];
+		rate = priv->mclk[1];
 		break;
 
 	case WM8994_SYSCLK_FLL1:
 		reg1 |= SEL_FLL1;
-		rate = wm8994->fll[0].out;
+		rate = priv->fll[0].out;
 		break;
 
 	case WM8994_SYSCLK_FLL2:
 		reg1 |= SEL_FLL2;
-		rate = wm8994->fll[1].out;
+		rate = priv->fll[1].out;
 		break;
 
 	default:
 		debug("%s: Invalid input clock selection [%d]\n",
-		      __func__, wm8994->sysclk[aif-1]);
+		      __func__, priv->sysclk[aif - 1]);
 		return -1;
 	}
 
@@ -469,18 +464,18 @@
 		reg1 |= WM8994_AIF1CLK_DIV;
 	}
 
-	wm8994->aifclk[aif-1] = rate;
+	priv->aifclk[aif - 1] = rate;
 
-	ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_1 + offset,
-				WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
-				reg1);
+	ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_1 + offset,
+			    WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
+			    reg1);
 
 	if (aif == WM8994_AIF1)
-		ret |= wm8994_update_bits(WM8994_CLOCKING_1,
+		ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
 			WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK,
 			WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
 	else if (aif == WM8994_AIF2)
-		ret |= wm8994_update_bits(WM8994_CLOCKING_1,
+		ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
 			WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |
 			WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |
 			WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
@@ -496,33 +491,33 @@
 /*
  * Configures Audio interface  for the given frequency
  *
- * @param wm8994	wm8994 information
+ * @param priv		wm8994 information
  * @param aif_id	Audio Interface
  * @param clk_id	Input Clock ID
  * @param freq		Sampling frequency in Hz
  *
  * @return -1 for error and 0 success.
  */
-static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
-				int clk_id, unsigned int freq)
+static int wm8994_set_sysclk(struct wm8994_priv *priv, int aif_id, int clk_id,
+			     unsigned int freq)
 {
 	int i;
 	int ret = 0;
 
-	wm8994->sysclk[aif_id - 1] = clk_id;
+	priv->sysclk[aif_id - 1] = clk_id;
 
 	switch (clk_id) {
 	case WM8994_SYSCLK_MCLK1:
-		wm8994->mclk[0] = freq;
+		priv->mclk[0] = freq;
 		if (aif_id == 2) {
-			ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 ,
-			WM8994_AIF2DAC_DIV_MASK , 0);
+			ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_2,
+					    WM8994_AIF2DAC_DIV_MASK, 0);
 		}
 		break;
 
 	case WM8994_SYSCLK_MCLK2:
 		/* TODO: Set GPIO AF */
-		wm8994->mclk[1] = freq;
+		priv->mclk[1] = freq;
 		break;
 
 	case WM8994_SYSCLK_FLL1:
@@ -543,13 +538,14 @@
 				      __func__);
 				return -1;
 			}
-			ret = wm8994_update_bits(WM8994_CLOCKING_2,
+			ret = wm8994_bic_or(priv, WM8994_CLOCKING_2,
 					    WM8994_OPCLK_DIV_MASK, i);
-			ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
-					    WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
+			ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
+					     WM8994_OPCLK_ENA,
+					     WM8994_OPCLK_ENA);
 		} else {
-			ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
-					    WM8994_OPCLK_ENA, 0);
+			ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
+					     WM8994_OPCLK_ENA, 0);
 		}
 
 	default:
@@ -558,7 +554,7 @@
 		return -1;
 	}
 
-	ret |= configure_aif_clock(wm8994, aif_id);
+	ret |= configure_aif_clock(priv, aif_id);
 
 	if (ret < 0) {
 		debug("%s: codec register access error\n", __func__);
@@ -571,37 +567,38 @@
 /*
  * Initializes Volume for AIF2 to HP path
  *
+ * @param priv		wm8994 information
  * @returns -1 for error  and 0 Success.
  *
  */
-static int wm8994_init_volume_aif2_dac1(void)
+static int wm8994_init_volume_aif2_dac1(struct wm8994_priv *priv)
 {
 	int ret;
 
 	/* Unmute AIF2DAC */
-	ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1,
-			WM8994_AIF2DAC_MUTE_MASK, 0);
+	ret = wm8994_bic_or(priv, WM8994_AIF2_DAC_FILTERS_1,
+			    WM8994_AIF2DAC_MUTE_MASK, 0);
 
 
-	ret |= wm8994_update_bits(WM8994_AIF2_DAC_LEFT_VOLUME,
-			WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
-			WM8994_AIF2DAC_VU | 0xff);
+	ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_LEFT_VOLUME,
+			     WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
+			     WM8994_AIF2DAC_VU | 0xff);
 
-	ret |= wm8994_update_bits(WM8994_AIF2_DAC_RIGHT_VOLUME,
-			WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
-			WM8994_AIF2DAC_VU | 0xff);
+	ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_RIGHT_VOLUME,
+			     WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
+			     WM8994_AIF2DAC_VU | 0xff);
 
 
-	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
-			WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
+			     WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 
-	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
-			WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
+			     WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 	/* Head Phone Volume */
-	ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
-	ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
 
 	if (ret < 0) {
 		debug("%s: codec register access error\n", __func__);
@@ -614,26 +611,27 @@
 /*
  * Initializes Volume for AIF1 to HP path
  *
+ * @param priv		wm8994 information
  * @returns -1 for error  and 0 Success.
  *
  */
-static int wm8994_init_volume_aif1_dac1(void)
+static int wm8994_init_volume_aif1_dac1(struct wm8994_priv *priv)
 {
 	int ret = 0;
 
 	/* Unmute AIF1DAC */
-	ret |= wm8994_i2c_write(WM8994_AIF1_DAC_FILTERS_1, 0x0000);
+	ret |= wm8994_i2c_write(priv, WM8994_AIF1_DAC_FILTERS_1, 0x0000);
 
-	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
-			WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
+			     WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 
-	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
-			WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
+			     WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 	/* Head Phone Volume */
-	ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
-	ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
 
 	if (ret < 0) {
 		debug("%s: codec register access error\n", __func__);
@@ -646,93 +644,99 @@
 /*
  * Intialise wm8994 codec device
  *
- * @param wm8994	wm8994 information
+ * @param priv		wm8994 information
  *
  * @returns -1 for error  and 0 Success.
  */
-static int wm8994_device_init(struct wm8994_priv *wm8994,
-			      enum en_audio_interface aif_id)
+static int wm8994_device_init(struct wm8994_priv *priv)
 {
 	const char *devname;
 	unsigned short reg_data;
 	int ret;
 
-	wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */
+	wm8994_i2c_write(priv, WM8994_SOFTWARE_RESET, WM8994_SW_RESET);
 
-	ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, &reg_data);
+	ret = wm8994_i2c_read(priv, WM8994_SOFTWARE_RESET, &reg_data);
 	if (ret < 0) {
 		debug("Failed to read ID register\n");
-		goto err;
+		return ret;
 	}
 
 	if (reg_data == WM8994_ID) {
 		devname = "WM8994";
-		debug("Device registered as type %d\n", wm8994->type);
-		wm8994->type = WM8994;
+		debug("Device registered as type %d\n", priv->type);
+		priv->type = WM8994;
 	} else {
 		debug("Device is not a WM8994, ID is %x\n", ret);
-		ret = -1;
-		goto err;
+		return -ENXIO;
 	}
 
-	ret = wm8994_i2c_read(WM8994_CHIP_REVISION, &reg_data);
+	ret = wm8994_i2c_read(priv, WM8994_CHIP_REVISION, &reg_data);
 	if (ret < 0) {
 		debug("Failed to read revision register: %d\n", ret);
-		goto err;
+		return ret;
 	}
-	wm8994->revision = reg_data;
-	debug("%s revision %c\n", devname, 'A' + wm8994->revision);
+	priv->revision = reg_data;
+	debug("%s revision %c\n", devname, 'A' + priv->revision);
+
+	return 0;
+}
+
+static int wm8994_setup_interface(struct wm8994_priv *priv,
+				  enum en_audio_interface aif_id)
+{
+	int ret;
 
 	/* VMID Selection */
-	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
-			WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
+	ret = wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
+			    WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
 
 	/* Charge Pump Enable */
-	ret |= wm8994_update_bits(WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
-					WM8994_CP_ENA);
+	ret |= wm8994_bic_or(priv, WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
+			     WM8994_CP_ENA);
 
 	/* Head Phone Power Enable */
-	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
-			WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
+	ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
+			     WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
 
-	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
-				WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
+	ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
+			     WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
 
 	if (aif_id == WM8994_AIF1) {
-		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_2,
+		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_2,
 					WM8994_TSHUT_ENA | WM8994_MIXINL_ENA |
 					WM8994_MIXINR_ENA | WM8994_IN2L_ENA |
 					WM8994_IN2R_ENA);
 
-		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_4,
+		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_4,
 					WM8994_ADCL_ENA | WM8994_ADCR_ENA |
 					WM8994_AIF1ADC1R_ENA |
 					WM8994_AIF1ADC1L_ENA);
 
 		/* Power enable for AIF1 and DAC1 */
-		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_5,
+		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_5,
 					WM8994_AIF1DACL_ENA |
 					WM8994_AIF1DACR_ENA |
 					WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
 	} else if (aif_id == WM8994_AIF2) {
 		/* Power enable for AIF2 and DAC1 */
-		ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_5,
+		ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_5,
 			WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK |
 			WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK,
 			WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
 			WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
 	}
 	/* Head Phone Initialisation */
-	ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
+	ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
 		WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK,
 		WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY);
 
-	ret |= wm8994_update_bits(WM8994_DC_SERVO_1,
+	ret |= wm8994_bic_or(priv, WM8994_DC_SERVO_1,
 			WM8994_DCS_ENA_CHAN_0_MASK |
 			WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 |
 			WM8994_DCS_ENA_CHAN_1);
 
-	ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
+	ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
 			WM8994_HPOUT1L_DLY_MASK |
 			WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK |
 			WM8994_HPOUT1R_OUTP_MASK |
@@ -743,172 +747,130 @@
 			WM8994_HPOUT1R_RMV_SHORT);
 
 	/* MIXER Config DAC1 to HP */
-	ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_1,
-			WM8994_DAC1L_TO_HPOUT1L_MASK, WM8994_DAC1L_TO_HPOUT1L);
+	ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_1,
+			     WM8994_DAC1L_TO_HPOUT1L_MASK,
+			     WM8994_DAC1L_TO_HPOUT1L);
 
-	ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_2,
-			WM8994_DAC1R_TO_HPOUT1R_MASK, WM8994_DAC1R_TO_HPOUT1R);
+	ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_2,
+			     WM8994_DAC1R_TO_HPOUT1R_MASK,
+			     WM8994_DAC1R_TO_HPOUT1R);
 
 	if (aif_id == WM8994_AIF1) {
 		/* Routing AIF1 to DAC1 */
-		ret |= wm8994_i2c_write(WM8994_DAC1_LEFT_MIXER_ROUTING,
-				WM8994_AIF1DAC1L_TO_DAC1L);
+		ret |= wm8994_i2c_write(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
+					WM8994_AIF1DAC1L_TO_DAC1L);
 
-		ret |= wm8994_i2c_write(WM8994_DAC1_RIGHT_MIXER_ROUTING,
+		ret |= wm8994_i2c_write(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
 					WM8994_AIF1DAC1R_TO_DAC1R);
 
 		/* GPIO Settings for AIF1 */
-		ret |=  wm8994_i2c_write(WM8994_GPIO_1, WM8994_GPIO_DIR_OUTPUT
-					 | WM8994_GPIO_FUNCTION_I2S_CLK
-					 | WM8994_GPIO_INPUT_DEBOUNCE);
+		ret |=  wm8994_i2c_write(priv, WM8994_GPIO_1,
+					 WM8994_GPIO_DIR_OUTPUT |
+					 WM8994_GPIO_FUNCTION_I2S_CLK |
+					 WM8994_GPIO_INPUT_DEBOUNCE);
 
-		ret |= wm8994_init_volume_aif1_dac1();
+		ret |= wm8994_init_volume_aif1_dac1(priv);
 	} else if (aif_id == WM8994_AIF2) {
 		/* Routing AIF2 to DAC1 */
-		ret |= wm8994_update_bits(WM8994_DAC1_LEFT_MIXER_ROUTING,
-				WM8994_AIF2DACL_TO_DAC1L_MASK,
-				WM8994_AIF2DACL_TO_DAC1L);
+		ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
+				     WM8994_AIF2DACL_TO_DAC1L_MASK,
+				     WM8994_AIF2DACL_TO_DAC1L);
 
-		ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING,
-				WM8994_AIF2DACR_TO_DAC1R_MASK,
-				WM8994_AIF2DACR_TO_DAC1R);
+		ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
+				     WM8994_AIF2DACR_TO_DAC1R_MASK,
+				     WM8994_AIF2DACR_TO_DAC1R);
 
 		/* GPIO Settings for AIF2 */
 		/* B CLK */
-		ret |= wm8994_update_bits(WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
-					WM8994_GPIO_FUNCTION_MASK ,
-					WM8994_GPIO_DIR_OUTPUT);
+		ret |= wm8994_bic_or(priv, WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
+				     WM8994_GPIO_FUNCTION_MASK,
+				     WM8994_GPIO_DIR_OUTPUT);
 
 		/* LR CLK */
-		ret |= wm8994_update_bits(WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
-					WM8994_GPIO_FUNCTION_MASK,
-					WM8994_GPIO_DIR_OUTPUT);
+		ret |= wm8994_bic_or(priv, WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
+				     WM8994_GPIO_FUNCTION_MASK,
+				     WM8994_GPIO_DIR_OUTPUT);
 
 		/* DATA */
-		ret |= wm8994_update_bits(WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
-					WM8994_GPIO_FUNCTION_MASK,
-					WM8994_GPIO_DIR_OUTPUT);
+		ret |= wm8994_bic_or(priv, WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
+				     WM8994_GPIO_FUNCTION_MASK,
+				     WM8994_GPIO_DIR_OUTPUT);
 
-		ret |= wm8994_init_volume_aif2_dac1();
+		ret |= wm8994_init_volume_aif2_dac1(priv);
 	}
 
 	if (ret < 0)
 		goto err;
 
-	debug("%s: Codec chip init ok\n", __func__);
+	debug("%s: Codec chip setup ok\n", __func__);
 	return 0;
 err:
-	debug("%s: Codec chip init error\n", __func__);
+	debug("%s: Codec chip setup error\n", __func__);
 	return -1;
 }
 
-/*
- * Gets fdt values for wm8994 config parameters
- *
- * @param pcodec_info	codec information structure
- * @param blob		FDT blob
- * @return		int value, 0 for success
- */
-static int get_codec_values(struct sound_codec_info *pcodec_info,
-			const void *blob)
+static int _wm8994_init(struct wm8994_priv *priv,
+			enum en_audio_interface aif_id, int sampling_rate,
+			int mclk_freq, int bits_per_sample,
+			unsigned int channels)
 {
-	int error = 0;
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-	enum fdt_compat_id compat;
-	int node;
-	int parent;
-
-	/* Get the node from FDT for codec */
-	node = fdtdec_next_compatible(blob, 0, COMPAT_WOLFSON_WM8994_CODEC);
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for codec in device tree\n");
-		debug("node = %d\n", node);
-		return -1;
-	}
+	int ret;
 
-	parent = fdt_parent_offset(blob, node);
-	if (parent < 0) {
-		debug("%s: Cannot find node parent\n", __func__);
-		return -1;
+	ret = wm8994_setup_interface(priv, aif_id);
+	if (ret < 0) {
+		debug("%s: wm8994 codec chip init failed\n", __func__);
+		return ret;
 	}
 
-	compat = fdtdec_lookup(blob, parent);
-	switch (compat) {
-	case COMPAT_SAMSUNG_S3C2440_I2C:
-		pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
-		error |= pcodec_info->i2c_bus;
-		debug("i2c bus = %d\n", pcodec_info->i2c_bus);
-		pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
-							"reg", 0);
-		error |= pcodec_info->i2c_dev_addr;
-		debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
-		break;
-	default:
-		debug("%s: Unknown compat id %d\n", __func__, compat);
-		return -1;
+	ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq);
+	if (ret < 0) {
+		debug("%s: wm8994 codec set sys clock failed\n", __func__);
+		return ret;
 	}
-#else
-	pcodec_info->i2c_bus = AUDIO_I2C_BUS;
-	pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
-	debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
-#endif
 
-	pcodec_info->codec_type = CODEC_WM_8994;
+	ret = wm8994_hw_params(priv, aif_id, sampling_rate, bits_per_sample,
+			       channels);
 
-	if (error == -1) {
-		debug("fail to get wm8994 codec node properties\n");
-		return -1;
+	if (ret == 0) {
+		ret = wm8994_set_fmt(priv, aif_id, SND_SOC_DAIFMT_I2S |
+				     SND_SOC_DAIFMT_NB_NF |
+				     SND_SOC_DAIFMT_CBS_CFS);
 	}
 
-	return 0;
+	return ret;
 }
 
-/* WM8994 Device Initialisation */
-int wm8994_init(const void *blob, enum en_audio_interface aif_id,
-			int sampling_rate, int mclk_freq,
-			int bits_per_sample, unsigned int channels)
+static int wm8994_set_params(struct udevice *dev, int interface, int rate,
+			     int mclk_freq, int bits_per_sample, uint channels)
 {
-	int ret = 0;
-	struct sound_codec_info *pcodec_info = &g_codec_info;
+	struct wm8994_priv *priv = dev_get_priv(dev);
 
-	/* Get the codec Values */
-	if (get_codec_values(pcodec_info, blob) < 0) {
-		debug("FDT Codec values failed\n");
-		return -1;
-	}
-
-	/* shift the device address by 1 for 7 bit addressing */
-	g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr;
-	wm8994_i2c_init(pcodec_info->i2c_bus);
+	return _wm8994_init(priv, interface, rate, mclk_freq, bits_per_sample,
+			    channels);
+}
 
-	if (pcodec_info->codec_type == CODEC_WM_8994) {
-		g_wm8994_info.type = WM8994;
-	} else {
-		debug("%s: Codec id [%d] not defined\n", __func__,
-		      pcodec_info->codec_type);
-		return -1;
-	}
+static int wm8994_probe(struct udevice *dev)
+{
+	struct wm8994_priv *priv = dev_get_priv(dev);
 
-	ret = wm8994_device_init(&g_wm8994_info, aif_id);
-	if (ret < 0) {
-		debug("%s: wm8994 codec chip init failed\n", __func__);
-		return ret;
-	}
+	priv->dev = dev;
+	return wm8994_device_init(priv);
+}
 
-	ret =  wm8994_set_sysclk(&g_wm8994_info, aif_id, WM8994_SYSCLK_MCLK1,
-							mclk_freq);
-	if (ret < 0) {
-		debug("%s: wm8994 codec set sys clock failed\n", __func__);
-		return ret;
-	}
+static const struct audio_codec_ops wm8994_ops = {
+	.set_params	= wm8994_set_params,
+};
 
-	ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate,
-						bits_per_sample, channels);
+static const struct udevice_id wm8994_ids[] = {
+	{ .compatible = "wolfson,wm8994" },
+	{ }
+};
 
-	if (ret == 0) {
-		ret = wm8994_set_fmt(aif_id, SND_SOC_DAIFMT_I2S |
-						SND_SOC_DAIFMT_NB_NF |
-						SND_SOC_DAIFMT_CBS_CFS);
-	}
-	return ret;
-}
+U_BOOT_DRIVER(wm8994) = {
+	.name		= "wm8994",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= wm8994_ids,
+	.probe		= wm8994_probe,
+	.ops		= &wm8994_ops,
+	.priv_auto_alloc_size	= sizeof(struct wm8994_priv),
+};
diff --git a/drivers/sound/wm8994.h b/drivers/sound/wm8994.h
index ef2878f..e36e626 100644
--- a/drivers/sound/wm8994.h
+++ b/drivers/sound/wm8994.h
@@ -15,7 +15,7 @@
 
 /*  Avilable audi interface ports in wm8994 codec */
 enum en_audio_interface {
-	 WM8994_AIF1 = 1,
+	 WM8994_AIF1,
 	 WM8994_AIF2,
 	 WM8994_AIF3
 };
diff --git a/drivers/tee/optee/supplicant.c b/drivers/tee/optee/supplicant.c
index b1ea65b..c5726ec 100644
--- a/drivers/tee/optee/supplicant.c
+++ b/drivers/tee/optee/supplicant.c
@@ -82,8 +82,8 @@
 		cmd_shm_free(arg);
 		break;
 	case OPTEE_MSG_RPC_CMD_FS:
-		debug("OPTEE_MSG_RPC_CMD_FS not implemented\n");
-		arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
+		debug("REE FS storage isn't available\n");
+		arg->ret = TEE_ERROR_STORAGE_NOT_AVAILABLE;
 		break;
 	case OPTEE_MSG_RPC_CMD_RPMB:
 		optee_suppl_cmd_rpmb(dev, arg);
diff --git a/include/audio_codec.h b/include/audio_codec.h
new file mode 100644
index 0000000..2587099
--- /dev/null
+++ b/include/audio_codec.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __AUDIO_CODEC_H__
+#define __AUDIO_CODEC_H__
+
+/*
+ * An audio codec turns digital data into sound with various parameters to
+ * control its operation.
+ */
+
+/* Operations for sound */
+struct audio_codec_ops {
+	/**
+	 * set_params() - Set audio codec parameters
+	 *
+	 * @dev: Sound device
+	 * @inteface: Interface number to use on codec
+	 * @rate: Sampling rate in Hz
+	 * @mclk_freq: Codec clock frequency in Hz
+	 * @bits_per_sample: Must be 16 or 24
+	 * @channels: Number of channels to use (1=mono, 2=stereo)
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*set_params)(struct udevice *dev, int interface, int rate,
+			  int mclk_freq, int bits_per_sample, uint channels);
+};
+
+#define audio_codec_get_ops(dev) ((struct audio_codec_ops *)(dev)->driver->ops)
+
+/**
+ * audio_codec_set_params() - Set audio codec parameters
+ *
+ * @dev: Sound device
+ * @inteface: Interface number to use on codec
+ * @rate: Sampling rate in Hz
+ * @mclk_freq: Codec clock frequency in Hz
+ * @bits_per_sample: Must be 16 or 24
+ * @channels: Number of channels to use (1=mono, 2=stereo)
+ * @return 0 if OK, -ve on error
+ */
+int audio_codec_set_params(struct udevice *dev, int interface, int rate,
+			   int mclk_freq, int bits_per_sample, uint channels);
+
+#endif  /* __AUDIO_CODEC_H__ */
diff --git a/include/dm/read.h b/include/dm/read.h
index efcbee1..389e30e 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -65,6 +65,38 @@
 int dev_read_u32_default(struct udevice *dev, const char *propname, int def);
 
 /**
+ * dev_read_s32() - read a signed 32-bit integer from a device's DT property
+ *
+ * @dev:	device to read DT property from
+ * @propname:	name of the property to read from
+ * @outp:	place to put value (if found)
+ * @return 0 if OK, -ve on error
+ */
+int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp);
+
+/**
+ * dev_read_s32_default() - read a signed 32-bit int from a device's DT property
+ *
+ * @dev:	device to read DT property from
+ * @propname:	name of the property to read from
+ * @def:	default value to return if the property has no value
+ * @return property value, or @def if not found
+ */
+int dev_read_s32_default(struct udevice *dev, const char *propname, int def);
+
+/**
+ * dev_read_u32u() - read a 32-bit integer from a device's DT property
+ *
+ * This version uses a standard uint type.
+ *
+ * @dev:	device to read DT property from
+ * @propname:	name of the property to read from
+ * @outp:	place to put value (if found)
+ * @return 0 if OK, -ve on error
+ */
+int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp);
+
+/**
  * dev_read_string() - Read a string from a device's DT property
  *
  * @dev:	device to read DT property from
@@ -492,6 +524,32 @@
 	return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
 }
 
+static inline int dev_read_s32(struct udevice *dev,
+			       const char *propname, s32 *outp)
+{
+	return ofnode_read_s32(dev_ofnode(dev), propname, outp);
+}
+
+static inline int dev_read_s32_default(struct udevice *dev,
+				       const char *propname, int def)
+{
+	return ofnode_read_s32_default(dev_ofnode(dev), propname, def);
+}
+
+static inline int dev_read_u32u(struct udevice *dev,
+				const char *propname, uint *outp)
+{
+	u32 val;
+	int ret;
+
+	ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
+	if (ret)
+		return ret;
+	*outp = val;
+
+	return 0;
+}
+
 static inline const char *dev_read_string(struct udevice *dev,
 					  const char *propname)
 {
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index e960e48..f3bafb3 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -29,6 +29,7 @@
 	/* U-Boot uclasses start here - in alphabetical order */
 	UCLASS_ADC,		/* Analog-to-digital converter */
 	UCLASS_AHCI,		/* SATA disk controller */
+	UCLASS_AUDIO_CODEC,	/* Audio codec with control and data path */
 	UCLASS_AXI,		/* AXI bus */
 	UCLASS_BLK,		/* Block device */
 	UCLASS_BOARD,		/* Device information from hardware */
@@ -48,6 +49,7 @@
 	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
 	UCLASS_I2C_GENERIC,	/* Generic I2C device */
 	UCLASS_I2C_MUX,		/* I2C multiplexer */
+	UCLASS_I2S,		/* I2S bus */
 	UCLASS_IDE,		/* IDE device */
 	UCLASS_IRQ,		/* Interrupt controller */
 	UCLASS_KEYBOARD,	/* Keyboard input device */
@@ -82,6 +84,7 @@
 	UCLASS_SERIAL,		/* Serial UART */
 	UCLASS_SIMPLE_BUS,	/* Bus with child devices */
 	UCLASS_SMEM,		/* Shared memory interface */
+	UCLASS_SOUND,		/* Playing simple sounds */
 	UCLASS_SPI,		/* SPI bus */
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
diff --git a/include/i2s.h b/include/i2s.h
index e6d45ec..28f6184 100644
--- a/include/i2s.h
+++ b/include/i2s.h
@@ -76,7 +76,7 @@
 };
 
 /* This structure stores the i2s related information */
-struct i2stx_info {
+struct i2s_uc_priv {
 	unsigned int rfs;		/* LR clock frame size */
 	unsigned int bfs;		/* Bit slock frame size */
 	unsigned int audio_pll_clk;	/* Audio pll frequency in Hz */
@@ -87,17 +87,41 @@
 	unsigned int id;		/* I2S controller id */
 };
 
+/* Operations for i2s devices */
+struct i2s_ops {
+	/**
+	 * tx_data() - Transmit audio data
+	 *
+	 * @dev: I2C device
+	 * @data: Data buffer to play
+	 * @data_size: Size of data buffer in bytes
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*tx_data)(struct udevice *dev, void *data, uint data_size);
+};
+
+#define i2s_get_ops(dev)	((struct i2s_ops *)(dev)->driver->ops)
+
+/**
+ * i2s_tx_data() - Transmit audio data
+ *
+ * @dev: I2C device
+ * @data: Data buffer to play
+ * @data_size: Size of data buffer in bytes
+ * @return 0 if OK, -ve on error
+ */
+int i2s_tx_data(struct udevice *dev, void *data, uint data_size);
+
 /*
  * Sends the given data through i2s tx
  *
  * @param pi2s_tx	pointer of i2s transmitter parameter structure.
  * @param data		address of the data buffer
- * @param data_size	array size of the int buffer (total size / size of int)
- *
+ * @param data_size	size of the data (in bytes)
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data,
-				unsigned long data_size);
+int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
+			 uint data_size);
 
 /*
  * Initialise i2s transmiter
@@ -106,6 +130,6 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_tx_init(struct i2stx_info *pi2s_tx);
+int i2s_tx_init(struct i2s_uc_priv *pi2s_tx);
 
 #endif /* __I2S_H__ */
diff --git a/include/sound.h b/include/sound.h
index 77bfe6a..b7959cc 100644
--- a/include/sound.h
+++ b/include/sound.h
@@ -8,14 +8,6 @@
 #define __SOUND_H__
 
 /* sound codec enum */
-enum en_sound_codec {
-	CODEC_WM_8994,
-	CODEC_WM_8995,
-	CODEC_MAX_98095,
-	CODEC_MAX
-};
-
-/* sound codec enum */
 enum sound_compat {
 	AUDIO_COMPAT_SPI,
 	AUDIO_COMPAT_I2C,
@@ -25,33 +17,81 @@
 struct sound_codec_info {
 	int i2c_bus;
 	int i2c_dev_addr;
-	enum en_sound_codec codec_type;
 };
 
-/*
+/**
+ * struct sound_uc_priv - private uclass information about each sound device
+ *
+ * This is used to line the codec and i2s together
+ *
+ * @codec: Codec that is used for this sound device
+ * @i2s: I2S bus that is used for this sound device
+ * @setup_done: true if setup() has been called
+ */
+struct sound_uc_priv {
+	struct udevice *codec;
+	struct udevice *i2s;
+	int setup_done;
+};
+
+/**
  * Generates square wave sound data for 1 second
  *
- * @param sample_rate   Sample rate in Hz
- * @param data          data buffer pointer
- * @param size          size of the buffer
- * @param freq          frequency of the wave
+ * @sample_rate: Sample rate in Hz
+ * @data: data buffer pointer
+ * @size: size of the buffer in bytes
+ * @freq: frequency of the wave
+ * @channels: Number of channels to use
  */
 void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
-			      uint freq);
+			      uint freq, uint channels);
 
 /*
- * Initialises audio sub system
- * @param blob	Pointer of device tree node or NULL if none.
- * @return	int value 0 for success, -1 for error
+ * The sound uclass brings together a data transport (currently only I2C) and a
+ * codec (currently connected over I2C).
  */
-int sound_init(const void *blob);
 
-/*
- * plays the pcm data buffer in pcm_data.h through i2s1 to make the
- * sine wave sound
+/* Operations for sound */
+struct sound_ops {
+	/**
+	 * setup() - Set up to play a sound
+	 */
+	int (*setup)(struct udevice *dev);
+
+	/**
+	 * play() - Play a beep
+	 *
+	 * @dev: Sound device
+	 * @data: Data buffer to play
+	 * @data_size: Size of data buffer in bytes
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*play)(struct udevice *dev, void *data, uint data_size);
+};
+
+#define sound_get_ops(dev)	((struct sound_ops *)(dev)->driver->ops)
+
+/**
+ * setup() - Set up to play a sound
+ */
+int sound_setup(struct udevice *dev);
+
+/**
+ * play() - Play a beep
+ *
+ * @dev: Sound device
+ * @msecs: Duration of beep in milliseconds
+ * @frequency_hz: Frequency of the beep in Hertz
+ * @return 0 if OK, -ve on error
+ */
+int sound_beep(struct udevice *dev, int msecs, int frequency_hz);
+
+/**
+ * sound_find_codec_i2s() - Called by sound drivers to locate codec and i2s
  *
- * @return	int 0 for success, -1 for error
+ * This finds the audio codec and i2s devices and puts them in the uclass's
+ * private data for this device.
  */
-int sound_play(uint32_t msec, uint32_t frequency);
+int sound_find_codec_i2s(struct udevice *dev);
 
 #endif  /* __SOUND__H__ */
diff --git a/include/tee.h b/include/tee.h
index 98b1c9c..edd9f9b 100644
--- a/include/tee.h
+++ b/include/tee.h
@@ -34,6 +34,7 @@
  * struct tee_version_data::gen_caps
  */
 #define TEE_SUCCESS			0x00000000
+#define TEE_ERROR_STORAGE_NOT_AVAILABLE	0xf0100003
 #define TEE_ERROR_GENERIC		0xffff0000
 #define TEE_ERROR_BAD_PARAMETERS	0xffff0006
 #define TEE_ERROR_ITEM_NOT_FOUND	0xffff0008
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 1c48692..93028ed 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -662,7 +662,7 @@
 			return (-1);
 		}
 	} else {
-		size = totlen;
+		size = totlen + 1;
 	}
 
 	/* Check if the user provided a buffer */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 2c9081e..7dc80be 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -2,7 +2,6 @@
 #
 # Copyright (c) 2013 Google, Inc
 
-obj-$(CONFIG_CMD_DM) += cmd_dm.o
 obj-$(CONFIG_UT_DM) += bus.o
 obj-$(CONFIG_UT_DM) += test-driver.o
 obj-$(CONFIG_UT_DM) += test-fdt.o
@@ -13,6 +12,7 @@
 # subsystem you must add sandbox tests here.
 obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
+obj-$(CONFIG_SOUND) += audio.o
 obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BOARD) += board.o
 obj-$(CONFIG_CLK) += clk.o
@@ -21,6 +21,7 @@
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o
 obj-$(CONFIG_DM_I2C) += i2c.o
+obj-$(CONFIG_SOUND) += i2s.o
 obj-$(CONFIG_LED) += led.o
 obj-$(CONFIG_DM_MAILBOX) += mailbox.o
 obj-$(CONFIG_DM_MMC) += mmc.o
@@ -53,6 +54,7 @@
 obj-$(CONFIG_MISC) += misc.o
 obj-$(CONFIG_DM_SERIAL) += serial.o
 obj-$(CONFIG_CPU) += cpu.o
+obj-$(CONFIG_SOUND) += sound.o
 obj-$(CONFIG_TEE) += tee.o
 obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
 obj-$(CONFIG_DMA) += dma.o
diff --git a/test/dm/audio.c b/test/dm/audio.c
new file mode 100644
index 0000000..77c3a36
--- /dev/null
+++ b/test/dm/audio.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <asm/test.h>
+
+/* Basic test of the audio codec uclass */
+static int dm_test_audio(struct unit_test_state *uts)
+{
+	int interface, rate, mclk_freq, bits_per_sample;
+	struct udevice *dev;
+	uint channels;
+
+	/* check probe success */
+	ut_assertok(uclass_first_device_err(UCLASS_AUDIO_CODEC, &dev));
+	ut_assertok(audio_codec_set_params(dev, 1, 2, 3, 4, 5));
+	sandbox_get_codec_params(dev, &interface, &rate, &mclk_freq,
+				 &bits_per_sample, &channels);
+	ut_asserteq(1, interface);
+	ut_asserteq(2, rate);
+	ut_asserteq(3, mclk_freq);
+	ut_asserteq(4, bits_per_sample);
+	ut_asserteq(5, channels);
+
+	return 0;
+}
+DM_TEST(dm_test_audio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/i2s.c b/test/dm/i2s.c
new file mode 100644
index 0000000..49ebc35
--- /dev/null
+++ b/test/dm/i2s.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <asm/test.h>
+
+/* Basic test of the i2s codec uclass */
+static int dm_test_i2s(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	u8 data[3];
+
+	/* check probe success */
+	ut_assertok(uclass_first_device_err(UCLASS_I2S, &dev));
+	data[0] = 1;
+	data[1] = 4;
+	data[2] = 6;
+	ut_assertok(i2s_tx_data(dev, data, ARRAY_SIZE(data)));
+	ut_asserteq(11, sandbox_get_i2s_sum(dev));
+	ut_assertok(i2s_tx_data(dev, data, 1));
+	ut_asserteq(12, sandbox_get_i2s_sum(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_i2s, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/sound.c b/test/dm/sound.c
new file mode 100644
index 0000000..7d0b36e
--- /dev/null
+++ b/test/dm/sound.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <sound.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <asm/test.h>
+
+/* Basic test of the sound codec uclass */
+static int dm_test_sound(struct unit_test_state *uts)
+{
+	struct sound_uc_priv *uc_priv;
+	struct udevice *dev;
+
+	/* check probe success */
+	ut_assertok(uclass_first_device_err(UCLASS_SOUND, &dev));
+	uc_priv = dev_get_uclass_priv(dev);
+	ut_asserteq_str("audio-codec", uc_priv->codec->name);
+	ut_asserteq_str("i2s", uc_priv->i2s->name);
+	ut_asserteq(0, sandbox_get_setup_called(dev));
+
+	ut_assertok(sound_beep(dev, 1, 100));
+	ut_asserteq(4560, sandbox_get_sound_sum(dev));
+	ut_assertok(sound_beep(dev, 1, 100));
+	ut_asserteq(9120, sandbox_get_sound_sum(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_sound, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 96d2528..984b80c 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -736,3 +736,38 @@
 	return 0;
 }
 DM_TEST(dm_test_first_child, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test integer functions in dm_read_...() */
+static int dm_test_read_int(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	u32 val32;
+	s32 sval;
+	uint val;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(dev_read_u32(dev, "int-value", &val32));
+	ut_asserteq(1234, val32);
+
+	ut_asserteq(-EINVAL, dev_read_u32(dev, "missing", &val32));
+	ut_asserteq(6, dev_read_u32_default(dev, "missing", 6));
+
+	ut_asserteq(1234, dev_read_u32_default(dev, "int-value", 6));
+	ut_asserteq(1234, val32);
+
+	ut_asserteq(-EINVAL, dev_read_s32(dev, "missing", &sval));
+	ut_asserteq(6, dev_read_s32_default(dev, "missing", 6));
+
+	ut_asserteq(-1234, dev_read_s32_default(dev, "uint-value", 6));
+	ut_assertok(dev_read_s32(dev, "uint-value", &sval));
+	ut_asserteq(-1234, sval);
+
+	val = 0;
+	ut_asserteq(-EINVAL, dev_read_u32u(dev, "missing", &val));
+	ut_assertok(dev_read_u32u(dev, "uint-value", &val));
+	ut_asserteq(-1234, val);
+
+	return 0;
+}
+DM_TEST(dm_test_read_int, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/tools/Makefile b/tools/Makefile
index c26b631..2c4d91f 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -126,7 +126,7 @@
 fit_check_sign-objs   := $(dumpimage-mkimage-objs) fit_check_sign.o
 file2include-objs := file2include.o
 
-ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)
+ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),)
 # Add CONFIG_MXS into host CFLAGS, so we can check whether or not register
 # the mxsimage support within tools/mxsimage.c .
 HOSTCFLAGS_mxsimage.o += -DCONFIG_MXS
diff --git a/tools/mtk_image.c b/tools/mtk_image.c
index 2706d2d..2ca5194 100644
--- a/tools/mtk_image.c
+++ b/tools/mtk_image.c
@@ -322,7 +322,7 @@
 				lk = val;
 
 			if (!strcmp(key, "lkname"))
-				strncpy(lk_name, val, sizeof(lk_name));
+				snprintf(lk_name, sizeof(lk_name), "%s", val);
 		}
 
 		if (next)
@@ -656,7 +656,7 @@
 		bootname = SDMMC_BOOT_NAME;
 
 	/* Generic device header */
-	strncpy(hdr->boot.name, bootname, sizeof(hdr->boot.name));
+	snprintf(hdr->boot.name, sizeof(hdr->boot.name), "%s", bootname);
 	hdr->boot.version = cpu_to_le32(1);
 	hdr->boot.size = cpu_to_le32(sizeof(hdr->boot));