Merge branch 'master' of git://git.denx.de/u-boot-video
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c
index 154d674..764c661 100644
--- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c
+++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c
@@ -5,9 +5,12 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 #include <common.h>
+#include <fdtdec.h>
 #include <asm/io.h>
 #include <asm/arch/clk.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /* Default is s5pc100 */
 unsigned int s5p_cpu_id = 0xC100;
 /* Default is EVT1 */
@@ -30,7 +33,16 @@
 #ifdef CONFIG_DISPLAY_CPUINFO
 int print_cpuinfo(void)
 {
-	printf("CPU:   %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
+	const char *cpu_model;
+	int len;
+
+	/* For SoC with no real CPU ID in naming convention. */
+	cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
+	if (cpu_model)
+		printf("CPU:   %.*s @ ", len, cpu_model);
+	else
+		printf("CPU:   %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
+
 	print_freq(get_arm_clk(), "\n");
 
 	return 0;
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts
index d0a8621..690c747 100644
--- a/arch/arm/dts/exynos5422-odroidxu3.dts
+++ b/arch/arm/dts/exynos5422-odroidxu3.dts
@@ -31,6 +31,18 @@
 			0xb0000000 0xea00000>;
 	};
 
+	adc@12D10000 {
+		u-boot,dm-pre-reloc;
+		status = "okay";
+	};
+
+	i2c@12CA0000 {
+		s2mps11_pmic@66 {
+			compatible = "samsung,s2mps11-pmic";
+			reg = <0x66>;
+		};
+	};
+
 	ehci@12110000 {
 		samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
 	};
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi
index bd3619d..daa6a33 100644
--- a/arch/arm/dts/exynos54xx.dtsi
+++ b/arch/arm/dts/exynos54xx.dtsi
@@ -42,6 +42,13 @@
 		xhci1 = "/xhci@12400000";
 	};
 
+	adc@12D10000 {
+		compatible = "samsung,exynos-adc-v2";
+		reg = <0x12D10000 0x100>;
+		interrupts = <0 106 0>;
+		status = "disabled";
+	};
+
 	i2c@12CA0000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts
index 1d7ff23..76826dc 100644
--- a/arch/arm/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/dts/exynos5800-peach-pi.dts
@@ -12,6 +12,7 @@
 
 / {
 	model = "Samsung/Google Peach Pi board based on Exynos5800";
+	cpu-model = "Exynos5800";
 
 	compatible = "google,pit-rev#", "google,pit",
 		"google,peach", "samsung,exynos5800", "samsung,exynos5";
diff --git a/arch/arm/dts/socfpga_cyclone5_socdk.dts b/arch/arm/dts/socfpga_cyclone5_socdk.dts
index 5465609..9eb5a22 100644
--- a/arch/arm/dts/socfpga_cyclone5_socdk.dts
+++ b/arch/arm/dts/socfpga_cyclone5_socdk.dts
@@ -89,7 +89,7 @@
 		#size-cells = <1>;
 		compatible = "n25q00";
 		reg = <0>;      /* chip select */
-		spi-max-frequency = <50000000>;
+		spi-max-frequency = <100000000>;
 		m25p,fast-read;
 		page-size = <256>;
 		block-size = <16>; /* 2^16, 64KB */
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
index 18eadf5..3d31f9d 100644
--- a/arch/arm/mach-exynos/clock.c
+++ b/arch/arm/mach-exynos/clock.c
@@ -159,8 +159,8 @@
 			div = PLL_DIV_1024;
 		else if (proid_is_exynos4412())
 			div = PLL_DIV_65535;
-		else if (proid_is_exynos5250() || proid_is_exynos5420()
-			 || proid_is_exynos5800())
+		else if (proid_is_exynos5250() || proid_is_exynos5420() ||
+			 proid_is_exynos5422())
 			div = PLL_DIV_65536;
 		else
 			return 0;
@@ -346,7 +346,7 @@
 	int i;
 	struct clk_bit_info *info;
 
-	if (proid_is_exynos5420() || proid_is_exynos5800())
+	if (proid_is_exynos5420() || proid_is_exynos5422())
 		info = exynos542x_bit_info;
 	else
 		info = exynos5_bit_info;
@@ -558,7 +558,7 @@
 unsigned long clock_get_periph_rate(int peripheral)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			return exynos542x_get_periph_rate(peripheral);
 		return exynos5_get_periph_rate(peripheral);
 	} else {
@@ -1576,7 +1576,7 @@
 unsigned long get_pll_clk(int pllreg)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			return exynos542x_get_pll_clk(pllreg);
 		return exynos5_get_pll_clk(pllreg);
 	} else if (cpu_is_exynos4()) {
@@ -1692,7 +1692,7 @@
 		div -= 1;
 
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			exynos5420_set_mmc_clk(dev_index, div);
 		else
 			exynos5_set_mmc_clk(dev_index, div);
@@ -1708,7 +1708,7 @@
 	} else if (cpu_is_exynos5()) {
 		if (proid_is_exynos5420())
 			return exynos5420_get_lcd_clk();
-		else if (proid_is_exynos5800())
+		else if (proid_is_exynos5422())
 			return exynos5800_get_lcd_clk();
 		else
 			return exynos5_get_lcd_clk();
@@ -1740,7 +1740,7 @@
 int set_spi_clk(int periph_id, unsigned int rate)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			return exynos5420_set_spi_clk(periph_id, rate);
 		return exynos5_set_spi_clk(periph_id, rate);
 	}
diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c
index 0200fd1..1b7498d 100644
--- a/arch/arm/mach-exynos/clock_init_exynos5.c
+++ b/arch/arm/mach-exynos/clock_init_exynos5.c
@@ -971,7 +971,7 @@
 
 void system_clock_init(void)
 {
-	if (proid_is_exynos5420() || proid_is_exynos5800())
+	if (proid_is_exynos5420() || proid_is_exynos5422())
 		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 67aac2d..2829fb2 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_exynos5800()) {
+	if (proid_is_exynos5420() || proid_is_exynos5422()) {
 		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_exynos5800()) {
+	if (proid_is_exynos5420() || proid_is_exynos5422()) {
 		mrc_l2_aux_ctlr(val);
 		val |= CACHE_ENABLE_FORCE_L2_LOGIC |
 			CACHE_DISABLE_CLEAN_EVICT;
diff --git a/arch/arm/mach-exynos/dmc_init_ddr3.c b/arch/arm/mach-exynos/dmc_init_ddr3.c
index 7c0b12a..25a9df9 100644
--- a/arch/arm/mach-exynos/dmc_init_ddr3.c
+++ b/arch/arm/mach-exynos/dmc_init_ddr3.c
@@ -20,8 +20,8 @@
 #define TIMEOUT_US		10000
 #define NUM_BYTE_LANES		4
 #define DEFAULT_DQS		8
-#define DEFAULT_DQS_X4		(DEFAULT_DQS << 24) || (DEFAULT_DQS << 16) \
-				|| (DEFAULT_DQS << 8) || (DEFAULT_DQS << 0)
+#define DEFAULT_DQS_X4		((DEFAULT_DQS << 24) || (DEFAULT_DQS << 16) \
+				|| (DEFAULT_DQS << 8) || (DEFAULT_DQS << 0))
 
 #ifdef CONFIG_EXYNOS5250
 static void reset_phy_ctrl(void)
@@ -856,10 +856,10 @@
 	 */
 	val = readl(&drex0->concontrol);
 	val |= CONCONTROL_UPDATE_MODE;
-	writel(val , &drex0->concontrol);
+	writel(val, &drex0->concontrol);
 	val = readl(&drex1->concontrol);
 	val |= CONCONTROL_UPDATE_MODE;
-	writel(val , &drex1->concontrol);
+	writel(val, &drex1->concontrol);
 
 	return 0;
 }
diff --git a/arch/arm/mach-exynos/include/mach/adc.h b/arch/arm/mach-exynos/include/mach/adc.h
index a0e26d7..9af51ab 100644
--- a/arch/arm/mach-exynos/include/mach/adc.h
+++ b/arch/arm/mach-exynos/include/mach/adc.h
@@ -9,6 +9,39 @@
 #ifndef __ASM_ARM_ARCH_ADC_H_
 #define __ASM_ARM_ARCH_ADC_H_
 
+#define ADC_V2_CON1_SOFT_RESET		(0x2 << 1)
+#define ADC_V2_CON1_STC_EN		0x1
+
+#define ADC_V2_CON2_OSEL(x)		(((x) & 0x1) << 10)
+#define OSEL_2S				0x0
+#define OSEL_BINARY			0x1
+#define ADC_V2_CON2_ESEL(x)		(((x) & 0x1) << 9)
+#define ESEL_ADC_EVAL_TIME_40CLK	0x0
+#define ESEL_ADC_EVAL_TIME_20CLK	0x1
+#define ADC_V2_CON2_HIGHF(x)		(((x) & 0x1) << 8)
+#define HIGHF_CONV_RATE_30KSPS		0x0
+#define HIGHF_CONV_RATE_600KSPS		0x1
+#define ADC_V2_CON2_C_TIME(x)		(((x) & 0x7) << 4)
+#define ADC_V2_CON2_CHAN_SEL_MASK	0xf
+#define ADC_V2_CON2_CHAN_SEL(x)		((x) & ADC_V2_CON2_CHAN_SEL_MASK)
+
+#define ADC_V2_GET_STATUS_FLAG(x)	(((x) >> 2) & 0x1)
+#define FLAG_CONV_END			0x1
+
+#define ADC_V2_INT_DISABLE		0x0
+#define ADC_V2_INT_ENABLE		0x1
+#define INT_NOT_GENERATED		0x0
+#define INT_GENERATED			0x1
+
+#define ADC_V2_VERSION			0x80000008
+
+#define ADC_V2_MAX_CHANNEL		9
+
+/* For default 8 time convertion with sample rate 600 kSPS - 15us timeout */
+#define ADC_V2_CONV_TIMEOUT_US		15
+
+#define ADC_V2_DAT_MASK			0xfff
+
 #ifndef __ASSEMBLY__
 struct s5p_adc {
 	unsigned int adccon;
@@ -21,6 +54,17 @@
 	unsigned int adcmux;
 	unsigned int adcclrintpndnup;
 };
+
+struct exynos_adc_v2 {
+	unsigned int con1;
+	unsigned int con2;
+	unsigned int status;
+	unsigned int dat;
+	unsigned int int_en;
+	unsigned int int_status;
+	unsigned int reserved[2];
+	unsigned int version;
+};
 #endif
 
 #endif /* __ASM_ARM_ARCH_ADC_H_ */
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h
index cb3d2cc..14a1692 100644
--- a/arch/arm/mach-exynos/include/mach/cpu.h
+++ b/arch/arm/mach-exynos/include/mach/cpu.h
@@ -237,7 +237,7 @@
 		 * Exynos5800 is a variant of Exynos5420
 		 * and has product id 0x5422
 		 */
-		s5p_cpu_id = 0x5800;
+		s5p_cpu_id = 0x5422;
 		break;
 	}
 }
@@ -267,7 +267,7 @@
 IS_EXYNOS_TYPE(exynos4412, 0x4412)
 IS_EXYNOS_TYPE(exynos5250, 0x5250)
 IS_EXYNOS_TYPE(exynos5420, 0x5420)
-IS_EXYNOS_TYPE(exynos5800, 0x5800)
+IS_EXYNOS_TYPE(exynos5422, 0x5422)
 
 #define SAMSUNG_BASE(device, base)				\
 static inline unsigned int __attribute__((no_instrument_function)) \
@@ -278,7 +278,7 @@
 			return EXYNOS4X12_##base;		\
 		return EXYNOS4_##base;				\
 	} else if (cpu_is_exynos5()) {				\
-		if (proid_is_exynos5420() || proid_is_exynos5800())	\
+		if (proid_is_exynos5420() || proid_is_exynos5422())	\
 			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 9699954..7fc8e61 100644
--- a/arch/arm/mach-exynos/include/mach/gpio.h
+++ b/arch/arm/mach-exynos/include/mach/gpio.h
@@ -1398,7 +1398,7 @@
 static inline struct gpio_info *get_gpio_data(void)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			return exynos5420_gpio_data;
 		else
 			return exynos5_gpio_data;
@@ -1415,7 +1415,7 @@
 static inline unsigned int get_bank_num(void)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			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 179b294..12eb79c 100644
--- a/arch/arm/mach-exynos/pinmux.c
+++ b/arch/arm/mach-exynos/pinmux.c
@@ -737,10 +737,10 @@
 		return -1;
 	}
 	for (i = start; i < (start + 7); i++) {
+		gpio_set_pull(i, S5P_GPIO_PULL_NONE);
 		if (i == (start + 2))
 			continue;
 		gpio_cfg_pin(i,  func);
-		gpio_set_pull(i, S5P_GPIO_PULL_NONE);
 		gpio_set_drv(i, S5P_GPIO_DRV_4X);
 	}
 	if (flags & PINMUX_FLAG_8BIT_MODE) {
@@ -858,7 +858,7 @@
 int exynos_pinmux_config(int peripheral, int flags)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			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 1b12051..cd2d661 100644
--- a/arch/arm/mach-exynos/power.c
+++ b/arch/arm/mach-exynos/power.c
@@ -125,7 +125,7 @@
 void set_usbdrd_phy_ctrl(unsigned int enable)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5800())
+		if (proid_is_exynos5420() || proid_is_exynos5422())
 			exynos5420_set_usbdev_phy_ctrl(enable);
 		else
 			exynos5_set_usbdrd_phy_ctrl(enable);
diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager.h b/arch/arm/mach-socfpga/include/mach/reset_manager.h
index 8e59578..666a2ef 100644
--- a/arch/arm/mach-socfpga/include/mach/reset_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/reset_manager.h
@@ -69,9 +69,9 @@
 #define RSTMGR_UART0		RSTMGR_DEFINE(1, 16)
 #define RSTMGR_SPIM0		RSTMGR_DEFINE(1, 18)
 #define RSTMGR_SPIM1		RSTMGR_DEFINE(1, 19)
-#define RSTMGR_QSPI		RSTMGR_DEFINE(0, 5)
-#define RSTMGR_SDMMC		RSTMGR_DEFINE(0, 22)
-#define RSTMGR_DMA		RSTMGR_DEFINE(0, 28)
+#define RSTMGR_QSPI		RSTMGR_DEFINE(1, 5)
+#define RSTMGR_SDMMC		RSTMGR_DEFINE(1, 22)
+#define RSTMGR_DMA		RSTMGR_DEFINE(1, 28)
 #define RSTMGR_SDR		RSTMGR_DEFINE(1, 29)
 
 /* Create a human-readable reference to SoCFPGA reset. */
diff --git a/arch/sandbox/dts/sandbox_pmic.dtsi b/arch/sandbox/dts/sandbox_pmic.dtsi
index 44a26b1..ce261b9 100644
--- a/arch/sandbox/dts/sandbox_pmic.dtsi
+++ b/arch/sandbox/dts/sandbox_pmic.dtsi
@@ -55,7 +55,7 @@
 		regulator-always-on;
 	};
 
-	buck2 {
+	buck2: buck2 {
 		regulator-name = "SUPPLY_3.3V";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 730de8a..e2c4971 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -189,6 +189,12 @@
 		};
 	};
 
+	adc@0 {
+		compatible = "sandbox,adc";
+		vdd-supply = <&buck2>;
+		vss-microvolts = <0>;
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile
index 6cbd906..ef1a8f3 100644
--- a/board/samsung/common/Makefile
+++ b/board/samsung/common/Makefile
@@ -11,5 +11,8 @@
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_BOARD_COMMON)	+= board.o
-obj-$(CONFIG_EXYNOS5_DT)	+= exynos5-dt.o
+ifdef CONFIG_EXYNOS5_DT
+obj-y += exynos5-dt.o
+obj-$(CONFIG_BOARD_TYPES) += exynos5-dt-types.o
+endif
 endif
diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c
index d32c75d..1334c22 100644
--- a/board/samsung/common/board.c
+++ b/board/samsung/common/board.c
@@ -304,8 +304,8 @@
 	printf("Board: %s\n", board_info ? board_info : "unknown");
 #ifdef CONFIG_BOARD_TYPES
 	board_info = get_board_type();
-
-	printf("Model: %s\n", board_info ? board_info : "unknown");
+	if (board_info)
+		printf("Type:  %s\n", board_info);
 #endif
 	return 0;
 }
diff --git a/board/samsung/common/exynos5-dt-types.c b/board/samsung/common/exynos5-dt-types.c
new file mode 100644
index 0000000..48fd1f7
--- /dev/null
+++ b/board/samsung/common/exynos5-dt-types.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <adc.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/s2mps11.h>
+#include <samsung/exynos5-dt-types.h>
+#include <samsung/misc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id board_ids[] = {
+	{ .compatible = "samsung,odroidxu3", .data = EXYNOS5_BOARD_ODROID_XU3 },
+	{ .compatible = "samsung,exynos5", .data = EXYNOS5_BOARD_GENERIC },
+	{ },
+};
+
+/**
+ * Odroix XU3/4 board revisions:
+ * Rev   ADCmax  Board
+ * 0.1     0     XU3 0.1
+ * 0.2   410     XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231)
+ * 0.3  1408     XU4 0.1
+ * Use +10 % for ADC value tolerance.
+ */
+struct odroid_rev_info odroid_info[] = {
+	{ EXYNOS5_BOARD_ODROID_XU3_REV01, 1, 10, "xu3" },
+	{ EXYNOS5_BOARD_ODROID_XU3_REV02, 2, 410, "xu3" },
+	{ EXYNOS5_BOARD_ODROID_XU4_REV01, 1, 1408, "xu4" },
+	{ EXYNOS5_BOARD_ODROID_UNKNOWN, 0, 4095, "unknown" },
+};
+
+static unsigned int odroid_get_rev(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
+		if (odroid_info[i].board_type == gd->board_type)
+			return odroid_info[i].board_rev;
+	}
+
+	return 0;
+}
+
+static int odroid_get_board_type(void)
+{
+	unsigned int adcval;
+	int ret, i;
+
+	ret = adc_channel_single_shot("adc", CONFIG_ODROID_REV_AIN, &adcval);
+	if (ret)
+		goto rev_default;
+
+	for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
+		/* ADC tolerance: +20 % */
+		if (adcval < odroid_info[i].adc_val)
+			return odroid_info[i].board_type;
+	}
+
+rev_default:
+	return EXYNOS5_BOARD_ODROID_XU3;
+}
+
+/**
+ * odroid_get_type_str - returns pointer to one of the board type string.
+ * Board types: "xu3", "xu3-lite", "xu4". However the "xu3lite" can be
+ * detected only when the i2c controller is ready to use. Fortunately,
+ * XU3 and XU3L are compatible, and the information about board lite
+ * revision is needed before booting the linux, to set proper environment
+ * variable: $fdtfile.
+ */
+static const char *odroid_get_type_str(void)
+{
+	const char *type_xu3l = "xu3-lite";
+	struct udevice *dev, *chip;
+	int i, ret;
+
+	if (gd->board_type != EXYNOS5_BOARD_ODROID_XU3_REV02)
+		goto exit;
+
+	ret = pmic_get("s2mps11", &dev);
+	if (ret)
+		goto exit;
+
+	/* Enable LDO26: 3.0V */
+	ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL,
+			     S2MPS11_LDO26_ENABLE);
+	if (ret)
+		goto exit;
+
+	/* Check XU3Lite by probe INA231 I2C0:0x40 */
+	ret = uclass_get_device(UCLASS_I2C, 0, &dev);
+	if (ret)
+		goto exit;
+
+	ret = dm_i2c_probe(dev, 0x40, 0x0, &chip);
+	if (ret)
+		return type_xu3l;
+
+exit:
+	for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
+		if (odroid_info[i].board_type == gd->board_type)
+			return odroid_info[i].name;
+	}
+
+	return NULL;
+}
+
+bool board_is_odroidxu3(void)
+{
+	if (gd->board_type >= EXYNOS5_BOARD_ODROID_XU3 &&
+	    gd->board_type <= EXYNOS5_BOARD_ODROID_XU3_REV02)
+		return true;
+
+	return false;
+}
+
+bool board_is_odroidxu4(void)
+{
+	if (gd->board_type == EXYNOS5_BOARD_ODROID_XU4_REV01)
+		return true;
+
+	return false;
+}
+
+bool board_is_generic(void)
+{
+	if (gd->board_type == EXYNOS5_BOARD_GENERIC)
+		return true;
+
+	return false;
+}
+
+/**
+ * get_board_rev() - return detected board revision.
+ *
+ * @return:  return board revision number for XU3 or 0 for generic
+ */
+u32 get_board_rev(void)
+{
+	if (board_is_generic())
+		return 0;
+
+	return odroid_get_rev();
+}
+
+/**
+ * get_board_type() - returns board type string.
+ *
+ * @return:  return board type string for XU3 or empty string for generic
+ */
+const char *get_board_type(void)
+{
+	const char *generic = "";
+
+	if (board_is_generic())
+		return generic;
+
+	return odroid_get_type_str();
+}
+
+/**
+ * set_board_type() - set board type in gd->board_type.
+ * As default type set EXYNOS5_BOARD_GENERIC, if detect Odroid,
+ * then set its proper type.
+ */
+void set_board_type(void)
+{
+	const struct udevice_id *of_match = board_ids;
+	int ret;
+
+	gd->board_type = EXYNOS5_BOARD_GENERIC;
+
+	while (of_match->compatible) {
+		ret = fdt_node_check_compatible(gd->fdt_blob, 0,
+						of_match->compatible);
+		if (ret)
+			of_match++;
+
+		gd->board_type = of_match->data;
+		break;
+	}
+
+	/* If Odroid, then check its revision */
+	if (board_is_odroidxu3())
+		gd->board_type = odroid_get_board_type();
+}
diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c
index 4250f72..4d9e151 100644
--- a/board/samsung/common/exynos5-dt.c
+++ b/board/samsung/common/exynos5-dt.c
@@ -27,7 +27,10 @@
 #include <power/pmic.h>
 #include <power/max77686_pmic.h>
 #include <power/regulator.h>
+#include <power/s2mps11.h>
 #include <power/s5m8767.h>
+#include <samsung/exynos5-dt-types.h>
+#include <samsung/misc.h>
 #include <tmu.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -335,15 +338,24 @@
 #ifdef CONFIG_SET_DFU_ALT_INFO
 char *get_dfu_alt_system(char *interface, char *devstr)
 {
+	char *info = "Not supported!";
+
+	if (board_is_odroidxu4())
+		return info;
+
 	return getenv("dfu_alt_system");
 }
 
 char *get_dfu_alt_boot(char *interface, char *devstr)
 {
+	char *info = "Not supported!";
 	struct mmc *mmc;
 	char *alt_boot;
 	int dev_num;
 
+	if (board_is_odroidxu4())
+		return info;
+
 	dev_num = simple_strtoul(devstr, NULL, 10);
 
 	mmc = find_mmc_device(dev_num);
diff --git a/board/samsung/common/misc.c b/board/samsung/common/misc.c
index e0e2c48..da0d4db 100644
--- a/board/samsung/common/misc.c
+++ b/board/samsung/common/misc.c
@@ -85,6 +85,9 @@
 
 #ifdef CONFIG_BOARD_TYPES
 	bdtype = get_board_type();
+	if (!bdtype)
+		bdtype = "";
+
 	sprintf(info, "%s%s", bdname, bdtype);
 	setenv("boardname", info);
 #endif
@@ -256,9 +259,9 @@
 		cmd = find_cmd(mode_name[mode][1]);
 		if (cmd) {
 			printf("Enter: %s %s\n", mode_name[mode][0],
-						 mode_info[mode]);
+			       mode_info[mode]);
 			lcd_printf("\n\n\t%s %s\n", mode_name[mode][0],
-						    mode_info[mode]);
+				   mode_info[mode]);
 			lcd_puts("\n\tDo not turn off device before finish!\n");
 
 			cmd_result = run_command(mode_cmd[mode], 0);
@@ -315,8 +318,7 @@
 
 	for (i = 0; i <= BOOT_MODE_EXIT; i++)
 		lcd_printf("\t%s  %s - %s\n\n", selection[i],
-						mode_name[i][0],
-						mode_info[i]);
+			   mode_name[i][0], mode_info[i]);
 }
 
 static void download_menu(void)
diff --git a/board/samsung/odroid/odroid.c b/board/samsung/odroid/odroid.c
index 32155f1..36d493d5 100644
--- a/board/samsung/odroid/odroid.c
+++ b/board/samsung/odroid/odroid.c
@@ -33,13 +33,6 @@
 	ODROID_TYPES,
 };
 
-static const char *mmc_regulators[] = {
-	"VDDQ_EMMC_1.8V",
-	"VDDQ_EMMC_2.8V",
-	"TFLASH_2.8V",
-	NULL,
-};
-
 void set_board_type(void)
 {
 	/* Set GPA1 pin 1 to HI - enable XCL205 output */
@@ -428,6 +421,13 @@
 
 int exynos_power_init(void)
 {
+	const char *mmc_regulators[] = {
+		"VDDQ_EMMC_1.8V",
+		"VDDQ_EMMC_2.8V",
+		"TFLASH_2.8V",
+		NULL,
+	};
+
 	if (regulator_list_autoset(mmc_regulators, NULL, true))
 		error("Unable to init all mmc regulators");
 
@@ -450,7 +450,6 @@
 		return regulator_set_mode(dev, OPMODE_ON);
 	else
 		return regulator_set_mode(dev, OPMODE_LPM);
-
 }
 
 struct s3c_plat_otg_data s5pc210_otg_data = {
diff --git a/board/samsung/smdk2410/smdk2410.c b/board/samsung/smdk2410/smdk2410.c
index b75a0e3..6e678c7 100644
--- a/board/samsung/smdk2410/smdk2410.c
+++ b/board/samsung/smdk2410/smdk2410.c
@@ -18,11 +18,11 @@
 
 #define FCLK_SPEED 1
 
-#if FCLK_SPEED==0		/* Fout = 203MHz, Fin = 12MHz for Audio */
+#if (FCLK_SPEED == 0)		/* Fout = 203MHz, Fin = 12MHz for Audio */
 #define M_MDIV	0xC3
 #define M_PDIV	0x4
 #define M_SDIV	0x1
-#elif FCLK_SPEED==1		/* Fout = 202.8MHz */
+#elif (FCLK_SPEED == 1)		/* Fout = 202.8MHz */
 #define M_MDIV	0xA1
 #define M_PDIV	0x3
 #define M_SDIV	0x1
@@ -30,11 +30,11 @@
 
 #define USB_CLOCK 1
 
-#if USB_CLOCK==0
+#if (USB_CLOCK == 0)
 #define U_M_MDIV	0xA1
 #define U_M_PDIV	0x3
 #define U_M_SDIV	0x1
-#elif USB_CLOCK==1
+#elif (USB_CLOCK == 1)
 #define U_M_MDIV	0x48
 #define U_M_PDIV	0x3
 #define U_M_SDIV	0x2
@@ -44,7 +44,7 @@
 {
 	__asm__ volatile ("1:\n"
 	  "subs %0, %1, #1\n"
-	  "bne 1b":"=r" (loops):"0" (loops));
+	  "bne 1b" : "=r" (loops) : "0" (loops));
 }
 
 /*
diff --git a/board/samsung/smdkv310/smdkv310.c b/board/samsung/smdkv310/smdkv310.c
index cb7f9b0..fc0e8d2 100644
--- a/board/samsung/smdkv310/smdkv310.c
+++ b/board/samsung/smdkv310/smdkv310.c
@@ -55,16 +55,16 @@
 void dram_init_banksize(void)
 {
 	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
-	gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1, \
+	gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1,
 							PHYS_SDRAM_1_SIZE);
 	gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
-	gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2, \
+	gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2,
 							PHYS_SDRAM_2_SIZE);
 	gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
-	gd->bd->bi_dram[2].size = get_ram_size((long *)PHYS_SDRAM_3, \
+	gd->bd->bi_dram[2].size = get_ram_size((long *)PHYS_SDRAM_3,
 							PHYS_SDRAM_3_SIZE);
 	gd->bd->bi_dram[3].start = PHYS_SDRAM_4;
-	gd->bd->bi_dram[3].size = get_ram_size((long *)PHYS_SDRAM_4, \
+	gd->bd->bi_dram[3].size = get_ram_size((long *)PHYS_SDRAM_4,
 							PHYS_SDRAM_4_SIZE);
 }
 
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 0ccaeb4..4fa6538 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -1177,25 +1177,9 @@
 	struct usb_endpoint_descriptor *ep_desc;
 	unsigned int flags = 0;
 
-	int protocol = 0;
-	int subclass = 0;
-
 	/* let's examine the device now */
 	iface = &dev->config.if_desc[ifnum];
 
-#if 0
-	/* this is the place to patch some storage devices */
-	debug("iVendor %X iProduct %X\n", dev->descriptor.idVendor,
-			dev->descriptor.idProduct);
-
-	if ((dev->descriptor.idVendor) == 0x066b &&
-	    (dev->descriptor.idProduct) == 0x0103) {
-		debug("patched for E-USB\n");
-		protocol = US_PR_CB;
-		subclass = US_SC_UFI;	    /* an assumption */
-	}
-#endif
-
 	if (dev->descriptor.bDeviceClass != 0 ||
 			iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
 			iface->desc.bInterfaceSubClass < US_SC_MIN ||
@@ -1215,17 +1199,8 @@
 	ss->ifnum = ifnum;
 	ss->pusb_dev = dev;
 	ss->attention_done = 0;
-
-	/* If the device has subclass and protocol, then use that.  Otherwise,
-	 * take data from the specific interface.
-	 */
-	if (subclass) {
-		ss->subclass = subclass;
-		ss->protocol = protocol;
-	} else {
-		ss->subclass = iface->desc.bInterfaceSubClass;
-		ss->protocol = iface->desc.bInterfaceProtocol;
-	}
+	ss->subclass = iface->desc.bInterfaceSubClass;
+	ss->protocol = iface->desc.bInterfaceProtocol;
 
 	/* set the handler pointers based on the protocol */
 	debug("Transport: ");
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig
index 479af9e..4ab91fa 100644
--- a/configs/odroid-xu3_defconfig
+++ b/configs/odroid-xu3_defconfig
@@ -9,7 +9,12 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_DM_I2C_COMPAT=y
 CONFIG_DM_PMIC=y
+CONFIG_CMD_PMIC=y
+CONFIG_ERRNO_STR=y
 CONFIG_DM_REGULATOR=y
+CONFIG_PMIC_S2MPS11=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_VIDEO_BRIDGE=y
+CONFIG_ADC=y
+CONFIG_ADC_EXYNOS=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 67ae99b..94c8e68 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -65,3 +65,5 @@
 CONFIG_UT_ENV=y
 CONFIG_REMOTEPROC_SANDBOX=y
 CONFIG_CMD_REMOTEPROC=y
+CONFIG_ADC=y
+CONFIG_ADC_SANDBOX=y
diff --git a/doc/device-tree-bindings/adc/adc.txt b/doc/device-tree-bindings/adc/adc.txt
new file mode 100644
index 0000000..463de3c
--- /dev/null
+++ b/doc/device-tree-bindings/adc/adc.txt
@@ -0,0 +1,62 @@
+ADC device binding
+
+There are no mandatory properties for ADC. However, if Voltage info is required,
+then there are two options:
+- use microvolts constraint or
+- use regulator phandle to enable/read supply's Voltage
+
+Properties and constraints:
+*optional and always checked, Voltage polarity info:
+- vdd-polarity-negative:  positive reference Voltage has a negative polarity
+- vss-polarity-negative:  negative reference Voltage has a negative polarity
+
+Chose one option, for each supply (Vdd/Vss):
+
+*optional and always checked, supply Voltage constants:
+- vdd-supply:            phandle to Vdd regulator's node
+- vss-supply:            phandle to Vss regulator's node
+
+*optional and checked only if the above corresponding, doesn't exist:
+- vdd-microvolts:        positive reference Voltage value [uV]
+- vss-microvolts:        negative reference Voltage value [uV]
+
+Example with constant 'Vdd' value:
+adc@1000000 {
+	compatible = "some-adc";
+	reg = <0xaabb000 0x100>;
+	status = "enabled";
+	vdd-microvolts = <1800000>;
+};
+
+Example of supply phandle usage, for the ADC's VDD/VSS references as below:
+   _______         _______
+  |Sandbox|       |Sandbox|
+  : PMIC  :       :  ADC  :
+  .       .       .       .
+  |       | (Vdd) |   AIN0|-->
+  |  BUCK2|-------|VDDref |
+  | (3.3V)|      _|VSSref |
+  |_______|     | |_______|
+               _|_
+
+For the above PMIC, the node can be defined as follows:
+sandbox_pmic {
+	compatible = "sandbox,pmic";
+	...
+	buck2: buck2 {
+		regulator-name = "SUPPLY_3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+	...
+};
+
+For the above ADC, the node can be defined as follows:
+adc@0 {
+	compatible = "sandbox,adc";
+	vdd-supply = <&buck2>;
+	vss-microvolts = <0>;
+};
+
+The ADC uclass code, will enable the supply before start of the conversion,
+but it will not configure the regulator settings.
diff --git a/doc/device-tree-bindings/exynos/soc.txt b/doc/device-tree-bindings/exynos/soc.txt
new file mode 100644
index 0000000..9ba6f3b
--- /dev/null
+++ b/doc/device-tree-bindings/exynos/soc.txt
@@ -0,0 +1,21 @@
+Exynos SoC model
+
+The "cpu-model" property is a non-standard extension for the device tree root
+node. Since the cpu id of some Exynos variants does not correspond to product
+name, this property fills the gap.
+
+For almost all Exynos based boards in the kernel, the product name corresponds
+to the device tree file name. The same name is generated in U-Boot, so the new
+property allows doing it automatically.
+
+Required properties:
+ - cpu-model : Exynos product name
+
+Example:
+
+/ {
+	model = "Samsung/Google Peach Pi board based on Exynos5800";
+	cpu-model = "Exynos5800";
+
+	compatible = ...
+};
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt
new file mode 100644
index 0000000..422f14f
--- /dev/null
+++ b/doc/device-tree-bindings/pmic/s2mps11.txt
@@ -0,0 +1,17 @@
+SAMSUNG, S2MPS11 PMIC
+
+This file describes the binding info for the PMIC driver:
+- drivers/power/pmic/s2mps11.c
+
+Required properties:
+- compatible: "samsung,s2mps11-pmic"
+- reg = 0x66
+
+With those two properties, the pmic device can be used for read/write only.
+
+Example:
+
+s2mps11@66 {
+	compatible = "samsung,s2mps11-pmic";
+	reg = <0x66>;
+};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index ba88b5e..c481e93 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -4,6 +4,8 @@
 
 # types of drivers sorted in alphabetical order
 
+source "drivers/adc/Kconfig"
+
 source "drivers/block/Kconfig"
 
 source "drivers/clk/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 4f49bfd..ad29a4f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -35,6 +35,7 @@
 
 else
 
+obj-y += adc/
 obj-$(CONFIG_DM_DEMO) += demo/
 obj-$(CONFIG_BIOSEMU) += bios_emulator/
 obj-y += block/
diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig
new file mode 100644
index 0000000..e5335f7
--- /dev/null
+++ b/drivers/adc/Kconfig
@@ -0,0 +1,30 @@
+config ADC
+	bool "Enable ADC drivers using Driver Model"
+	help
+	  This enables ADC API for drivers, which allows driving ADC features
+	  by single and multi-channel methods for:
+	  - start/stop/get data for conversion of a single-channel selected by
+	    a number or multi-channels selected by a bitmask
+	  - get data mask (ADC resolution)
+	  ADC reference Voltage supply options:
+	  - methods for get Vdd/Vss reference Voltage values with polarity
+	  - support supply's phandle with auto-enable
+	  - supply polarity setting in fdt
+
+config ADC_EXYNOS
+	bool "Enable Exynos 54xx ADC driver"
+	help
+	  This enables basic driver for Exynos ADC compatible with Exynos54xx.
+	  It provides:
+	  - 10 analog input channels
+	  - 12-bit resolution
+	  - 600 KSPS of sample rate
+
+config ADC_SANDBOX
+	bool "Enable Sandbox ADC test driver"
+	help
+	  This enables driver for Sandbox ADC device emulation.
+	  It provides:
+	  - 4 analog input channels
+	  - 16-bit resolution
+	  - single and multi-channel conversion mode
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile
new file mode 100644
index 0000000..cebf26d
--- /dev/null
+++ b/drivers/adc/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2015 Samsung Electronics
+# Przemyslaw Marczak <p.marczak@samsung.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_ADC) += adc-uclass.o
+obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o
+obj-$(CONFIG_ADC_SANDBOX) += sandbox.o
diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c
new file mode 100644
index 0000000..9233fcd
--- /dev/null
+++ b/drivers/adc/adc-uclass.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <adc.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ADC_UCLASS_PLATDATA_SIZE	sizeof(struct adc_uclass_platdata)
+#define CHECK_NUMBER			true
+#define CHECK_MASK			(!CHECK_NUMBER)
+
+/* TODO: add support for timer uclass (for early calls) */
+#ifdef CONFIG_SANDBOX_ARCH
+#define sdelay(x)	udelay(x)
+#else
+extern void sdelay(unsigned long loops);
+#endif
+
+static int check_channel(struct udevice *dev, int value, bool number_or_mask,
+			 const char *caller_function)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	unsigned mask = number_or_mask ? (1 << value) : value;
+
+	/* For the real ADC hardware, some ADC channels can be inactive.
+	 * For example if device has 4 analog channels, and only channels
+	 * 1-st and 3-rd are valid, then channel mask is: 0b1010, so request
+	 * with mask 0b1110 should return an error.
+	*/
+	if ((uc_pdata->channel_mask >= mask) && (uc_pdata->channel_mask & mask))
+		return 0;
+
+	printf("Error in %s/%s().\nWrong channel selection for device: %s\n",
+	       __FILE__, caller_function, dev->name);
+
+	return -EINVAL;
+}
+
+static int adc_supply_enable(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	const char *supply_type;
+	int ret = 0;
+
+	if (uc_pdata->vdd_supply) {
+		supply_type = "vdd";
+		ret = regulator_set_enable(uc_pdata->vdd_supply, true);
+	}
+
+	if (!ret && uc_pdata->vss_supply) {
+		supply_type = "vss";
+		ret = regulator_set_enable(uc_pdata->vss_supply, true);
+	}
+
+	if (ret)
+		error("%s: can't enable %s-supply!", dev->name, supply_type);
+
+	return ret;
+}
+
+int adc_data_mask(struct udevice *dev, unsigned int *data_mask)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+
+	if (!uc_pdata)
+		return -ENOSYS;
+
+	*data_mask = uc_pdata->data_mask;
+	return 0;
+}
+
+int adc_stop(struct udevice *dev)
+{
+	const struct adc_ops *ops = dev_get_driver_ops(dev);
+
+	if (!ops->stop)
+		return -ENOSYS;
+
+	return ops->stop(dev);
+}
+
+int adc_start_channel(struct udevice *dev, int channel)
+{
+	const struct adc_ops *ops = dev_get_driver_ops(dev);
+	int ret;
+
+	if (!ops->start_channel)
+		return -ENOSYS;
+
+	ret = check_channel(dev, channel, CHECK_NUMBER, __func__);
+	if (ret)
+		return ret;
+
+	ret = adc_supply_enable(dev);
+	if (ret)
+		return ret;
+
+	return ops->start_channel(dev, channel);
+}
+
+int adc_start_channels(struct udevice *dev, unsigned int channel_mask)
+{
+	const struct adc_ops *ops = dev_get_driver_ops(dev);
+	int ret;
+
+	if (!ops->start_channels)
+		return -ENOSYS;
+
+	ret = check_channel(dev, channel_mask, CHECK_MASK, __func__);
+	if (ret)
+		return ret;
+
+	ret = adc_supply_enable(dev);
+	if (ret)
+		return ret;
+
+	return ops->start_channels(dev, channel_mask);
+}
+
+int adc_channel_data(struct udevice *dev, int channel, unsigned int *data)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	const struct adc_ops *ops = dev_get_driver_ops(dev);
+	unsigned int timeout_us = uc_pdata->data_timeout_us;
+	int ret;
+
+	if (!ops->channel_data)
+		return -ENOSYS;
+
+	ret = check_channel(dev, channel, CHECK_NUMBER, __func__);
+	if (ret)
+		return ret;
+
+	do {
+		ret = ops->channel_data(dev, channel, data);
+		if (!ret || ret != -EBUSY)
+			break;
+
+		/* TODO: use timer uclass (for early calls). */
+		sdelay(5);
+	} while (timeout_us--);
+
+	return ret;
+}
+
+int adc_channels_data(struct udevice *dev, unsigned int channel_mask,
+		      struct adc_channel *channels)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	unsigned int timeout_us = uc_pdata->multidata_timeout_us;
+	const struct adc_ops *ops = dev_get_driver_ops(dev);
+	int ret;
+
+	if (!ops->channels_data)
+		return -ENOSYS;
+
+	ret = check_channel(dev, channel_mask, CHECK_MASK, __func__);
+	if (ret)
+		return ret;
+
+	do {
+		ret = ops->channels_data(dev, channel_mask, channels);
+		if (!ret || ret != -EBUSY)
+			break;
+
+		/* TODO: use timer uclass (for early calls). */
+		sdelay(5);
+	} while (timeout_us--);
+
+	return ret;
+}
+
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
+	if (ret)
+		return ret;
+
+	ret = adc_start_channel(dev, channel);
+	if (ret)
+		return ret;
+
+	ret = adc_channel_data(dev, channel, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int _adc_channels_single_shot(struct udevice *dev,
+				     unsigned int channel_mask,
+				     struct adc_channel *channels)
+{
+	unsigned int data;
+	int channel, ret;
+
+	for (channel = 0; channel <= ADC_MAX_CHANNEL; channel++) {
+		/* Check channel bit. */
+		if (!((channel_mask >> channel) & 0x1))
+			continue;
+
+		ret = adc_start_channel(dev, channel);
+		if (ret)
+			return ret;
+
+		ret = adc_channel_data(dev, channel, &data);
+		if (ret)
+			return ret;
+
+		channels->id = channel;
+		channels->data = data;
+		channels++;
+	}
+
+	return 0;
+}
+
+int adc_channels_single_shot(const char *name, unsigned int channel_mask,
+			     struct adc_channel *channels)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
+	if (ret)
+		return ret;
+
+	ret = adc_start_channels(dev, channel_mask);
+	if (ret)
+		goto try_manual;
+
+	ret = adc_channels_data(dev, channel_mask, channels);
+	if (ret)
+		return ret;
+
+	return 0;
+
+try_manual:
+	if (ret != -ENOSYS)
+		return ret;
+
+	return _adc_channels_single_shot(dev, channel_mask, channels);
+}
+
+static int adc_vdd_platdata_update(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	int ret;
+
+	/* Warning!
+	 * This function can't return supply device before its bind.
+	 * Please pay attention to proper fdt scan sequence. If ADC device
+	 * will bind before its supply regulator device, then the below 'get'
+	 * will return an error.
+	 */
+	ret = device_get_supply_regulator(dev, "vdd-supply",
+					  &uc_pdata->vdd_supply);
+	if (ret)
+		return ret;
+
+	ret = regulator_get_value(uc_pdata->vdd_supply);
+	if (ret < 0)
+		return ret;
+
+	uc_pdata->vdd_microvolts = ret;
+
+	return 0;
+}
+
+static int adc_vss_platdata_update(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	int ret;
+
+	ret = device_get_supply_regulator(dev, "vss-supply",
+					  &uc_pdata->vss_supply);
+	if (ret)
+		return ret;
+
+	ret = regulator_get_value(uc_pdata->vss_supply);
+	if (ret < 0)
+		return ret;
+
+	uc_pdata->vss_microvolts = ret;
+
+	return 0;
+}
+
+int adc_vdd_value(struct udevice *dev, int *uV)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	int ret, value_sign = uc_pdata->vdd_polarity_negative ? -1 : 1;
+
+	if (!uc_pdata->vdd_supply)
+		goto nodev;
+
+	/* Update the regulator Value. */
+	ret = adc_vdd_platdata_update(dev);
+	if (ret)
+		return ret;
+nodev:
+	if (uc_pdata->vdd_microvolts == -ENODATA)
+		return -ENODATA;
+
+	*uV = uc_pdata->vdd_microvolts * value_sign;
+
+	return 0;
+}
+
+int adc_vss_value(struct udevice *dev, int *uV)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	int ret, value_sign = uc_pdata->vss_polarity_negative ? -1 : 1;
+
+	if (!uc_pdata->vss_supply)
+		goto nodev;
+
+	/* Update the regulator Value. */
+	ret = adc_vss_platdata_update(dev);
+	if (ret)
+		return ret;
+nodev:
+	if (uc_pdata->vss_microvolts == -ENODATA)
+		return -ENODATA;
+
+	*uV = uc_pdata->vss_microvolts * value_sign;
+
+	return 0;
+}
+
+static int adc_vdd_platdata_set(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	int ret, offset = dev->of_offset;
+	const void *fdt = gd->fdt_blob;
+	char *prop;
+
+	prop = "vdd-polarity-negative";
+	uc_pdata->vdd_polarity_negative = fdtdec_get_bool(fdt, offset, prop);
+
+	ret = adc_vdd_platdata_update(dev);
+	if (ret != -ENOENT)
+		return ret;
+
+	/* No vdd-supply phandle. */
+	prop  = "vdd-microvolts";
+	uc_pdata->vdd_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA);
+
+	return 0;
+}
+
+static int adc_vss_platdata_set(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	int ret, offset = dev->of_offset;
+	const void *fdt = gd->fdt_blob;
+	char *prop;
+
+	prop = "vss-polarity-negative";
+	uc_pdata->vss_polarity_negative = fdtdec_get_bool(fdt, offset, prop);
+
+	ret = adc_vss_platdata_update(dev);
+	if (ret != -ENOENT)
+		return ret;
+
+	/* No vss-supply phandle. */
+	prop = "vss-microvolts";
+	uc_pdata->vss_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA);
+
+	return 0;
+}
+
+static int adc_pre_probe(struct udevice *dev)
+{
+	int ret;
+
+	/* Set ADC VDD platdata: polarity, uV, regulator (phandle). */
+	ret = adc_vdd_platdata_set(dev);
+	if (ret)
+		error("%s: Can't update Vdd. Error: %d", dev->name, ret);
+
+	/* Set ADC VSS platdata: polarity, uV, regulator (phandle). */
+	ret = adc_vss_platdata_set(dev);
+	if (ret)
+		error("%s: Can't update Vss. Error: %d", dev->name, ret);
+
+	return 0;
+}
+
+UCLASS_DRIVER(adc) = {
+	.id	= UCLASS_ADC,
+	.name	= "adc",
+	.pre_probe =  adc_pre_probe,
+	.per_device_platdata_auto_alloc_size = ADC_UCLASS_PLATDATA_SIZE,
+};
diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c
new file mode 100644
index 0000000..534e68d
--- /dev/null
+++ b/drivers/adc/exynos-adc.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <adc.h>
+#include <asm/arch/adc.h>
+
+struct exynos_adc_priv {
+	int active_channel;
+	struct exynos_adc_v2 *regs;
+};
+
+int exynos_adc_channel_data(struct udevice *dev, int channel,
+			    unsigned int *data)
+{
+	struct exynos_adc_priv *priv = dev_get_priv(dev);
+	struct exynos_adc_v2 *regs = priv->regs;
+
+	if (channel != priv->active_channel) {
+		error("Requested channel is not active!");
+		return -EINVAL;
+	}
+
+	if (ADC_V2_GET_STATUS_FLAG(readl(&regs->status)) != FLAG_CONV_END)
+		return -EBUSY;
+
+	*data = readl(&regs->dat) & ADC_V2_DAT_MASK;
+
+	return 0;
+}
+
+int exynos_adc_start_channel(struct udevice *dev, int channel)
+{
+	struct exynos_adc_priv *priv = dev_get_priv(dev);
+	struct exynos_adc_v2 *regs = priv->regs;
+	unsigned int cfg;
+
+	/* Choose channel */
+	cfg = readl(&regs->con2);
+	cfg &= ~ADC_V2_CON2_CHAN_SEL_MASK;
+	cfg |= ADC_V2_CON2_CHAN_SEL(channel);
+	writel(cfg, &regs->con2);
+
+	/* Start conversion */
+	cfg = readl(&regs->con1);
+	writel(cfg | ADC_V2_CON1_STC_EN, &regs->con1);
+
+	priv->active_channel = channel;
+
+	return 0;
+}
+
+int exynos_adc_stop(struct udevice *dev)
+{
+	struct exynos_adc_priv *priv = dev_get_priv(dev);
+	struct exynos_adc_v2 *regs = priv->regs;
+	unsigned int cfg;
+
+	/* Stop conversion */
+	cfg = readl(&regs->con1);
+	cfg |= ~ADC_V2_CON1_STC_EN;
+
+	writel(cfg, &regs->con1);
+
+	priv->active_channel = -1;
+
+	return 0;
+}
+
+int exynos_adc_probe(struct udevice *dev)
+{
+	struct exynos_adc_priv *priv = dev_get_priv(dev);
+	struct exynos_adc_v2 *regs = priv->regs;
+	unsigned int cfg;
+
+	/* Check HW version */
+	if (readl(&regs->version) != ADC_V2_VERSION) {
+		error("This driver supports only ADC v2!");
+		return -ENXIO;
+	}
+
+	/* ADC Reset */
+	writel(ADC_V2_CON1_SOFT_RESET, &regs->con1);
+
+	/* Disable INT - will read status only */
+	writel(0x0, &regs->int_en);
+
+	/* CON2 - set conversion parameters */
+	cfg = ADC_V2_CON2_C_TIME(3); /* Conversion times: (1 << 3) = 8 */
+	cfg |= ADC_V2_CON2_OSEL(OSEL_BINARY);
+	cfg |= ADC_V2_CON2_ESEL(ESEL_ADC_EVAL_TIME_20CLK);
+	cfg |= ADC_V2_CON2_HIGHF(HIGHF_CONV_RATE_600KSPS);
+	writel(cfg, &regs->con2);
+
+	priv->active_channel = -1;
+
+	return 0;
+}
+
+int exynos_adc_ofdata_to_platdata(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	struct exynos_adc_priv *priv = dev_get_priv(dev);
+
+	priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev);
+	if (priv->regs == (struct exynos_adc_v2 *)FDT_ADDR_T_NONE) {
+		error("Dev: %s - can't get address!", dev->name);
+		return -ENODATA;
+	}
+
+	uc_pdata->data_mask = ADC_V2_DAT_MASK;
+	uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
+	uc_pdata->data_timeout_us = ADC_V2_CONV_TIMEOUT_US;
+
+	/* Mask available channel bits: [0:9] */
+	uc_pdata->channel_mask = (2 << ADC_V2_MAX_CHANNEL) - 1;
+
+	return 0;
+}
+
+static const struct adc_ops exynos_adc_ops = {
+	.start_channel = exynos_adc_start_channel,
+	.channel_data = exynos_adc_channel_data,
+	.stop = exynos_adc_stop,
+};
+
+static const struct udevice_id exynos_adc_ids[] = {
+	{ .compatible = "samsung,exynos-adc-v2" },
+	{ }
+};
+
+U_BOOT_DRIVER(exynos_adc) = {
+	.name		= "exynos-adc",
+	.id		= UCLASS_ADC,
+	.of_match	= exynos_adc_ids,
+	.ops		= &exynos_adc_ops,
+	.probe		= exynos_adc_probe,
+	.ofdata_to_platdata = exynos_adc_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct exynos_adc_priv),
+};
diff --git a/drivers/adc/sandbox.c b/drivers/adc/sandbox.c
new file mode 100644
index 0000000..3718922
--- /dev/null
+++ b/drivers/adc/sandbox.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <adc.h>
+#include <sandbox-adc.h>
+
+/**
+ * struct sandbox_adc_priv - sandbox ADC device's operation status and data
+ *
+ * @conversion_status - conversion status: ACTIVE (started) / INACTIVE (stopped)
+ * @conversion_mode   - conversion mode: single or multi-channel
+ * @active_channel    - active channel number, valid for single channel mode
+ * data[]             - channels data
+ */
+struct sandbox_adc_priv {
+	int conversion_status;
+	int conversion_mode;
+	int active_channel_mask;
+	unsigned int data[4];
+};
+
+int sandbox_adc_start_channel(struct udevice *dev, int channel)
+{
+	struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+	/* Set single-channel mode */
+	priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL;
+	/* Select channel */
+	priv->active_channel_mask = 1 << channel;
+	/* Start conversion */
+	priv->conversion_status = SANDBOX_ADC_ACTIVE;
+
+	return 0;
+}
+
+int sandbox_adc_start_channels(struct udevice *dev, unsigned int channel_mask)
+{
+	struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+	/* Set single-channel mode */
+	priv->conversion_mode = SANDBOX_ADC_MODE_MULTI_CHANNEL;
+	/* Select channel */
+	priv->active_channel_mask = channel_mask;
+	/* Start conversion */
+	priv->conversion_status = SANDBOX_ADC_ACTIVE;
+
+	return 0;
+}
+
+int sandbox_adc_channel_data(struct udevice *dev, int channel,
+			     unsigned int *data)
+{
+	struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+	/* For single-channel conversion mode, check if channel was selected */
+	if ((priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) &&
+	    !(priv->active_channel_mask & (1 << channel))) {
+		error("Request for an inactive channel!");
+		return -EINVAL;
+	}
+
+	/* The conversion must be started before reading the data */
+	if (priv->conversion_status == SANDBOX_ADC_INACTIVE)
+		return -EIO;
+
+	*data = priv->data[channel];
+
+	return 0;
+}
+
+int sandbox_adc_channels_data(struct udevice *dev, unsigned int channel_mask,
+			      struct adc_channel *channels)
+{
+	struct sandbox_adc_priv *priv = dev_get_priv(dev);
+	int i;
+
+	/* Return error for single-channel conversion mode */
+	if (priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) {
+		error("ADC in single-channel mode!");
+		return -EPERM;
+	}
+	/* Check channel selection */
+	if (!(priv->active_channel_mask & channel_mask)) {
+		error("Request for an inactive channel!");
+		return -EINVAL;
+	}
+	/* The conversion must be started before reading the data */
+	if (priv->conversion_status == SANDBOX_ADC_INACTIVE)
+		return -EIO;
+
+	for (i = 0; i < SANDBOX_ADC_CHANNELS; i++) {
+		if (!((channel_mask >> i) & 0x1))
+			continue;
+
+		channels->data = priv->data[i];
+		channels->id = i;
+		channels++;
+	}
+
+	return 0;
+}
+
+int sandbox_adc_stop(struct udevice *dev)
+{
+	struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+	/* Start conversion */
+	priv->conversion_status = SANDBOX_ADC_INACTIVE;
+
+	return 0;
+}
+
+int sandbox_adc_probe(struct udevice *dev)
+{
+	struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+	/* Stop conversion */
+	priv->conversion_status = SANDBOX_ADC_INACTIVE;
+	/* Set single-channel mode */
+	priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL;
+	/* Deselect all channels */
+	priv->active_channel_mask = 0;
+
+	/* Set sandbox test data */
+	priv->data[0] = SANDBOX_ADC_CHANNEL0_DATA;
+	priv->data[1] = SANDBOX_ADC_CHANNEL1_DATA;
+	priv->data[2] = SANDBOX_ADC_CHANNEL2_DATA;
+	priv->data[3] = SANDBOX_ADC_CHANNEL3_DATA;
+
+	return 0;
+}
+
+int sandbox_adc_ofdata_to_platdata(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+
+	uc_pdata->data_mask = SANDBOX_ADC_DATA_MASK;
+	uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
+	uc_pdata->data_timeout_us = 0;
+
+	/* Mask available channel bits: [0:3] */
+	uc_pdata->channel_mask = (1 << SANDBOX_ADC_CHANNELS) - 1;
+
+	return 0;
+}
+
+static const struct adc_ops sandbox_adc_ops = {
+	.start_channel = sandbox_adc_start_channel,
+	.start_channels = sandbox_adc_start_channels,
+	.channel_data = sandbox_adc_channel_data,
+	.channels_data = sandbox_adc_channels_data,
+	.stop = sandbox_adc_stop,
+};
+
+static const struct udevice_id sandbox_adc_ids[] = {
+	{ .compatible = "sandbox,adc" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_adc) = {
+	.name		= "sandbox-adc",
+	.id		= UCLASS_ADC,
+	.of_match	= sandbox_adc_ids,
+	.ops		= &sandbox_adc_ops,
+	.probe		= sandbox_adc_probe,
+	.ofdata_to_platdata = sandbox_adc_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct sandbox_adc_priv),
+};
diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c
index 7646c6b..9702eee 100644
--- a/drivers/dfu/dfu_sf.c
+++ b/drivers/dfu/dfu_sf.c
@@ -115,8 +115,10 @@
 int dfu_fill_entity_sf(struct dfu_entity *dfu, char *devstr, char *s)
 {
 	char *st;
+	char *devstr_bkup = strdup(devstr);
 
-	dfu->data.sf.dev = parse_dev(devstr);
+	dfu->data.sf.dev = parse_dev(devstr_bkup);
+	free(devstr_bkup);
 	if (!dfu->data.sf.dev)
 		return -ENODEV;
 
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index 15ecfee..44353c7 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -106,6 +106,12 @@
 	flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
 	dev_id = host->index + PERIPH_ID_SDMMC0;
 
+	ret = exynos_pinmux_config(dev_id, flag);
+	if (ret) {
+		printf("external SD not configured\n");
+		return ret;
+	}
+
 	if (dm_gpio_is_valid(&host->pwr_gpio)) {
 		dm_gpio_set_value(&host->pwr_gpio, 1);
 		ret = exynos_pinmux_config(dev_id, flag);
@@ -121,12 +127,6 @@
 			debug("no SD card detected (%d)\n", ret);
 			return -ENODEV;
 		}
-
-		ret = exynos_pinmux_config(dev_id, flag);
-		if (ret) {
-			printf("external SD not configured\n");
-			return ret;
-		}
 	}
 
 	return s5p_sdhci_core_init(host);
@@ -193,7 +193,7 @@
 		}
 
 		ret = do_sdhci_init(host);
-		if (ret) {
+		if (ret && ret != -ENODEV) {
 			printf("%s: failed to initialize dev %d (%d)\n", __func__, i, ret);
 			failed++;
 		}
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 547fd1a..fb29843 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -33,6 +33,20 @@
 	This config enables implementation of driver-model pmic uclass features
 	for PMIC MAX77686. The driver implements read/write operations.
 
+config PMIC_S2MPS11
+	bool "Enable Driver Model for PMIC Samsung S2MPS11"
+	depends on DM_PMIC
+	---help---
+	The Samsung S2MPS11 PMIC provides:
+	 - 38 adjustable LDO regulators
+	 - 9 High-Efficiency Buck Converters
+	 - 1 BuckBoost Converter
+	 - RTC with two alarms
+	 - Backup battery charger
+	 - I2C Configuration Interface
+	This driver provides access to I/O interface only.
+	Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
+
 config DM_PMIC_SANDBOX
 	bool "Enable Driver Model for emulated Sandbox PMIC "
 	depends on DM_PMIC
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 00fde71..91e78f8 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
 obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o
 obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o
+obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
 obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
 obj-$(CONFIG_PMIC_ACT8846) += act8846.o
 obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c
new file mode 100644
index 0000000..9d83059
--- /dev/null
+++ b/drivers/power/pmic/s2mps11.c
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics
+ *  Przemyslaw Marczak  <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/s2mps11.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int s2mps11_reg_count(struct udevice *dev)
+{
+	return S2MPS11_REG_COUNT;
+}
+
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
+			 int len)
+{
+	int ret;
+
+	ret = dm_i2c_write(dev, reg, buff, len);
+	if (ret)
+		error("write error to device: %p register: %#x!", dev, reg);
+
+	return ret;
+}
+
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+	int ret;
+
+	ret = dm_i2c_read(dev, reg, buff, len);
+	if (ret)
+		error("read error from device: %p register: %#x!", dev, reg);
+
+	return ret;
+}
+
+static struct dm_pmic_ops s2mps11_ops = {
+	.reg_count = s2mps11_reg_count,
+	.read = s2mps11_read,
+	.write = s2mps11_write,
+};
+
+static const struct udevice_id s2mps11_ids[] = {
+	{ .compatible = "samsung,s2mps11-pmic" },
+	{ }
+};
+
+U_BOOT_DRIVER(pmic_s2mps11) = {
+	.name = "s2mps11_pmic",
+	.id = UCLASS_PMIC,
+	.of_match = s2mps11_ids,
+	.ops = &s2mps11_ops,
+};
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index a5170df..4241a4c 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -138,6 +138,13 @@
 	return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
 }
 
+int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
+				struct udevice **devp)
+{
+	return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+					    supply_name, devp);
+}
+
 int regulator_autoset(struct udevice *dev)
 {
 	struct dm_regulator_uclass_platdata *uc_pdata;
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 34a0f46..4f7fd52 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -37,9 +37,8 @@
 }
 
 /* Calibration sequence to determine the read data capture delay register */
-static int spi_calibration(struct udevice *bus)
+static int spi_calibration(struct udevice *bus, uint hz)
 {
-	struct cadence_spi_platdata *plat = bus->platdata;
 	struct cadence_spi_priv *priv = dev_get_priv(bus);
 	void *base = priv->regbase;
 	u8 opcode_rdid = 0x9F;
@@ -64,7 +63,7 @@
 	}
 
 	/* use back the intended clock and find low range */
-	cadence_spi_write_speed(bus, plat->max_hz);
+	cadence_spi_write_speed(bus, hz);
 	for (i = 0; i < CQSPI_READ_CAPTURE_MAX_DELAY; i++) {
 		/* Disable QSPI */
 		cadence_qspi_apb_controller_disable(base);
@@ -111,7 +110,7 @@
 	      (range_hi + range_lo) / 2, range_lo, range_hi);
 
 	/* just to ensure we do once only when speed or chip select change */
-	priv->qspi_calibrated_hz = plat->max_hz;
+	priv->qspi_calibrated_hz = hz;
 	priv->qspi_calibrated_cs = spi_chip_select(bus);
 
 	return 0;
@@ -123,17 +122,25 @@
 	struct cadence_spi_priv *priv = dev_get_priv(bus);
 	int err;
 
+	if (hz > plat->max_hz)
+		hz = plat->max_hz;
+
 	/* Disable QSPI */
 	cadence_qspi_apb_controller_disable(priv->regbase);
 
-	cadence_spi_write_speed(bus, hz);
-
-	/* Calibration required for different SCLK speed or chip select */
-	if (priv->qspi_calibrated_hz != plat->max_hz ||
+	/*
+	 * Calibration required for different current SCLK speed, requested
+	 * SCLK speed or chip select
+	 */
+	if (priv->previous_hz != hz ||
+	    priv->qspi_calibrated_hz != hz ||
 	    priv->qspi_calibrated_cs != spi_chip_select(bus)) {
-		err = spi_calibration(bus);
+		err = spi_calibration(bus, hz);
 		if (err)
 			return err;
+
+		/* prevent calibration run when same as previous request */
+		priv->previous_hz = hz;
 	}
 
 	/* Enable QSPI */
@@ -291,10 +298,6 @@
 	plat->regbase = (void *)data[0];
 	plat->ahbbase = (void *)data[2];
 
-	/* Use 500KHz as a suitable default */
-	plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
-				      500000);
-
 	/* All other paramters are embedded in the child node */
 	subnode = fdt_first_subnode(blob, node);
 	if (subnode < 0) {
@@ -302,6 +305,10 @@
 		return -ENODEV;
 	}
 
+	/* Use 500 KHz as a suitable default */
+	plat->max_hz = fdtdec_get_uint(blob, subnode, "spi-max-frequency",
+				       500000);
+
 	/* Read other parameters from DT */
 	plat->page_size = fdtdec_get_int(blob, subnode, "page-size", 256);
 	plat->block_size = fdtdec_get_int(blob, subnode, "block-size", 16);
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 98e57aa..2912e36 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -38,6 +38,7 @@
 	int		qspi_is_init;
 	unsigned int	qspi_calibrated_hz;
 	unsigned int	qspi_calibrated_cs;
+	unsigned int	previous_hz;
 };
 
 /* Functions call declaration */
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index ab3c94e..0ae3de5 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -281,7 +281,7 @@
 	return 0;
 
 err1:
-	dma_unmap_single((void *)dwc->scratch_addr, dwc->nr_scratch *
+	dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
 			 DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
 
 err0:
@@ -296,7 +296,7 @@
 	if (!dwc->nr_scratch)
 		return;
 
-	dma_unmap_single((void *)dwc->scratch_addr, dwc->nr_scratch *
+	dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
 			 DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
 	kfree(dwc->scratchbuf);
 }
@@ -629,7 +629,8 @@
 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
 	dwc->mem = mem;
 
-	dwc->regs	= (int *)(dwc3_dev->base + DWC3_GLOBALS_REGS_START);
+	dwc->regs = (void *)(uintptr_t)(dwc3_dev->base +
+					DWC3_GLOBALS_REGS_START);
 
 	/* default to highest possible threshold */
 	lpm_nyet_threshold = 0xff;
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index aba614f..12b133f 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -81,8 +81,8 @@
 		trb->ctrl |= (DWC3_TRB_CTRL_IOC
 				| DWC3_TRB_CTRL_LST);
 
-	dwc3_flush_cache((int)buf_dma, len);
-	dwc3_flush_cache((int)trb, sizeof(*trb));
+	dwc3_flush_cache((long)buf_dma, len);
+	dwc3_flush_cache((long)trb, sizeof(*trb));
 
 	if (chain)
 		return 0;
@@ -790,7 +790,7 @@
 	if (!r)
 		return;
 
-	dwc3_flush_cache((int)trb, sizeof(*trb));
+	dwc3_flush_cache((long)trb, sizeof(*trb));
 
 	status = DWC3_TRB_SIZE_TRBSTS(trb->size);
 	if (status == DWC3_TRBSTS_SETUP_PENDING) {
@@ -821,7 +821,7 @@
 			ur->actual += transferred;
 
 			trb++;
-			dwc3_flush_cache((int)trb, sizeof(*trb));
+			dwc3_flush_cache((long)trb, sizeof(*trb));
 			length = trb->size & DWC3_TRB_SIZE_MASK;
 
 			ep0->free_slot = 0;
@@ -831,7 +831,7 @@
 					maxp);
 		transferred = min_t(u32, ur->length - transferred,
 				    transfer_size - length);
-		dwc3_flush_cache((int)dwc->ep0_bounce, DWC3_EP0_BOUNCE_SIZE);
+		dwc3_flush_cache((long)dwc->ep0_bounce, DWC3_EP0_BOUNCE_SIZE);
 		memcpy(buf, dwc->ep0_bounce, transferred);
 	} else {
 		transferred = ur->length - length;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f3d649a..8ff949d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -244,7 +244,7 @@
 
 	list_del(&req->list);
 	req->trb = NULL;
-	dwc3_flush_cache((int)req->request.dma, req->request.length);
+	dwc3_flush_cache((long)req->request.dma, req->request.length);
 
 	if (req->request.status == -EINPROGRESS)
 		req->request.status = status;
@@ -771,8 +771,8 @@
 
 	trb->ctrl |= DWC3_TRB_CTRL_HWO;
 
-	dwc3_flush_cache((int)dma, length);
-	dwc3_flush_cache((int)trb, sizeof(*trb));
+	dwc3_flush_cache((long)dma, length);
+	dwc3_flush_cache((long)trb, sizeof(*trb));
 }
 
 /*
@@ -1769,7 +1769,7 @@
 	slot %= DWC3_TRB_NUM;
 	trb = &dep->trb_pool[slot];
 
-	dwc3_flush_cache((int)trb, sizeof(*trb));
+	dwc3_flush_cache((long)trb, sizeof(*trb));
 	__dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
 	dwc3_gadget_giveback(dep, req, status);
 
@@ -2670,7 +2670,7 @@
 
 		for (i = 0; i < dwc->num_event_buffers; i++) {
 			evt = dwc->ev_buffs[i];
-			dwc3_flush_cache((int)evt->buf, evt->length);
+			dwc3_flush_cache((long)evt->buf, evt->length);
 		}
 
 		dwc3_thread_interrupt(0, dwc);
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 5042a24..0d9fa22 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -23,7 +23,7 @@
 #define	CACHELINE_SIZE		CONFIG_SYS_CACHELINE_SIZE
 static inline u32 dwc3_readl(void __iomem *base, u32 offset)
 {
-	u32 offs = offset - DWC3_GLOBALS_REGS_START;
+	unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
 	u32 value;
 
 	/*
@@ -38,7 +38,7 @@
 
 static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
 {
-	u32 offs = offset - DWC3_GLOBALS_REGS_START;
+	unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
 
 	/*
 	 * We requested the mem region starting from the Globals address
diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c
index ff1481b..9ed0ce3 100644
--- a/drivers/usb/gadget/f_thor.c
+++ b/drivers/usb/gadget/f_thor.c
@@ -569,7 +569,7 @@
 
 	dev->in_req->length = len;
 
-	debug("%s: dev->in_req->length:%d to_cpy:%d\n", __func__,
+	debug("%s: dev->in_req->length:%d to_cpy:%zd\n", __func__,
 	      dev->in_req->length, sizeof(data));
 
 	status = usb_ep_queue(dev->in_ep, dev->in_req, 0);
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index 875e998..326757b 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -65,7 +65,7 @@
 	if (req->length == 0)
 		return;
 
-	dma_unmap_single((void *)req->dma, req->length,
+	dma_unmap_single((void *)(uintptr_t)req->dma, req->length,
 			 is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 }
 EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 9bde2b2..ccbfc02 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -2205,6 +2205,7 @@
 	if (!ohci->hcca)
 		return -ENOMEM;
 	memset(ohci->hcca, 0, sizeof(struct ohci_hcca));
+	flush_dcache_hcca(ohci->hcca);
 
 	if (hc_reset(ohci) < 0)
 		return -EIO;
diff --git a/include/adc.h b/include/adc.h
new file mode 100644
index 0000000..4b14017
--- /dev/null
+++ b/include/adc.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _ADC_H_
+#define _ADC_H_
+
+/* ADC_CHANNEL() - ADC channel bit mask, to select only required channels */
+#define ADC_CHANNEL(x)		(1 << x)
+
+/* The last possible selected channel with 32-bit mask */
+#define ADC_MAX_CHANNEL		31
+
+/**
+ * adc_data_format: define the ADC output data format, can be useful when
+ * the device's input Voltage range is bipolar.
+ * - ADC_DATA_FORMAT_BIN - binary offset
+ * - ADC_DATA_FORMAT_2S  - two's complement
+ *
+ * Note: Device's driver should fill the 'data_format' field of its uclass's
+ * platform data using one of the above data format types.
+ */
+enum adc_data_format {
+	ADC_DATA_FORMAT_BIN,
+	ADC_DATA_FORMAT_2S,
+};
+
+/**
+ * struct adc_channel - structure to hold channel conversion data.
+ * Useful to keep the result of a multi-channel conversion output.
+ *
+ * @id   - channel id
+ * @data - channel conversion data
+ */
+struct adc_channel {
+	int id;
+	unsigned int data;
+};
+
+/**
+ * struct adc_uclass_platdata - basic ADC info
+ *
+ * Note: The positive/negative reference Voltage is only a name and it doesn't
+ * provide an information about the value polarity. It is possible, for both
+ * values to be a negative or positive. For this purpose the uclass's platform
+ * data provides a bool fields: 'vdd/vss_supply_is_negative'. This is useful,
+ * since the regulator API returns only a positive Voltage values.
+ *
+ * To get the reference Voltage values with polarity, use functions:
+ * - adc_vdd_value()
+ * - adc_vss_value()
+ * Those are useful for some cases of ADC's references, e.g.:
+ * * Vdd: +3.3V; Vss: -3.3V -> 6.6 Vdiff
+ * * Vdd: +3.3V; Vss: +0.3V -> 3.0 Vdiff
+ * * Vdd: +3.3V; Vss:  0.0V -> 3.3 Vdiff
+ * The last one is usually standard and doesn't require the fdt polarity info.
+ *
+ * For more informations read binding info:
+ * - doc/device-tree-bindings/adc/adc.txt
+ *
+ * @data_mask              - conversion output data mask
+ * @data_timeout_us        - single channel conversion timeout
+ * @multidata_timeout_us   - multi channel conversion timeout
+ * @channel_mask           - bit mask of available channels [0:31]
+ * @vdd_supply             - positive reference Voltage supply (regulator)
+ * @vss_supply             - negative reference Voltage supply (regulator)
+ * @vdd_polarity_negative  - positive reference Voltage has negative polarity
+ * @vss_polarity_negative  - negative reference Voltage has negative polarity
+ * @vdd_microvolts         - positive reference Voltage value
+ * @vss_microvolts         - negative reference Voltage value
+ */
+struct adc_uclass_platdata {
+	int data_format;
+	unsigned int data_mask;
+	unsigned int data_timeout_us;
+	unsigned int multidata_timeout_us;
+	unsigned int channel_mask;
+	struct udevice *vdd_supply;
+	struct udevice *vss_supply;
+	bool vdd_polarity_negative;
+	bool vss_polarity_negative;
+	int vdd_microvolts;
+	int vss_microvolts;
+};
+
+/**
+ * struct adc_ops - ADC device operations for single/multi-channel operation.
+ */
+struct adc_ops {
+	/**
+	 * start_channel() - start conversion with its default parameters
+	 *                   for the given channel number.
+	 *
+	 * @dev:          ADC device to init
+	 * @channel:      analog channel number
+	 * @return:       0 if OK, -ve on error
+	 */
+	int (*start_channel)(struct udevice *dev, int channel);
+
+	/**
+	 * start_channels() - start conversion with its default parameters
+	 *                    for the channel numbers selected by the bit mask.
+	 *
+	 * This is optional, useful when the hardware supports multichannel
+	 * conversion by the single software trigger.
+	 *
+	 * @dev:          ADC device to init
+	 * @channel_mask: bit mask of selected analog channels
+	 * @return:       0 if OK, -ve on error
+	 */
+	int (*start_channels)(struct udevice *dev, unsigned int channel_mask);
+
+	/**
+	 * channel_data() - get conversion output data for the given channel.
+	 *
+	 * Note: The implementation of this function should only check, that
+	 * the conversion data is available at the call time. If the hardware
+	 * requires some delay to get the data, then this function should
+	 * return with -EBUSY value. The ADC API will call it in a loop,
+	 * until the data is available or the timeout expires. The maximum
+	 * timeout for this operation is defined by the field 'data_timeout_us'
+	 * in ADC uclasses platform data structure.
+	 *
+	 * @dev:          ADC device to trigger
+	 * @channel:      selected analog channel number
+	 * @data:         returned pointer to selected channel's output data
+	 * @return:       0 if OK, -EBUSY if busy, and other negative on error
+	 */
+	int (*channel_data)(struct udevice *dev, int channel,
+			    unsigned int *data);
+
+	/**
+	 * channels_data() - get conversion data for the selected channels.
+	 *
+	 * This is optional, useful when multichannel conversion is supported
+	 * by the hardware, by the single software trigger.
+	 *
+	 * For the proper implementation, please look at the 'Note' for the
+	 * above method. The only difference is in used timeout value, which
+	 * is defined by field 'multidata_timeout_us'.
+	 *
+	 * @dev:          ADC device to trigger
+	 * @channel_mask: bit mask of selected analog channels
+	 * @channels:     returned pointer to array of output data for channels
+	 *                selected by the given mask
+	 * @return:       0 if OK, -ve on error
+	 */
+	int (*channels_data)(struct udevice *dev, unsigned int channel_mask,
+			     struct adc_channel *channels);
+
+	/**
+	 * stop() - stop conversion of the given ADC device
+	 *
+	 * @dev:          ADC device to stop
+	 * @return:       0 if OK, -ve on error
+	 */
+	int (*stop)(struct udevice *dev);
+};
+
+/**
+ * adc_start_channel() - start conversion for given device/channel and exit.
+ *
+ * @dev:     ADC device
+ * @channel: analog channel number
+ * @return:  0 if OK, -ve on error
+ */
+int adc_start_channel(struct udevice *dev, int channel);
+
+/**
+ * adc_start_channels() - start conversion for given device/channels and exit.
+ *
+ * Note:
+ * To use this function, device must implement method: start_channels().
+ *
+ * @dev:          ADC device to start
+ * @channel_mask: channel selection - a bit mask
+ * @channel_mask: bit mask of analog channels
+ * @return:       0 if OK, -ve on error
+ */
+int adc_start_channels(struct udevice *dev, unsigned int channel_mask);
+
+/**
+ * adc_channel_data() - get conversion data for the given device channel number.
+ *
+ * @dev:     ADC device to read
+ * @channel: analog channel number
+ * @data:    pointer to returned channel's data
+ * @return:  0 if OK, -ve on error
+ */
+int adc_channel_data(struct udevice *dev, int channel, unsigned int *data);
+
+/**
+ * adc_channels_data() - get conversion data for the channels selected by mask
+ *
+ * Note:
+ * To use this function, device must implement methods:
+ * - start_channels()
+ * - channels_data()
+ *
+ * @dev:          ADC device to read
+ * @channel_mask: channel selection - a bit mask
+ * @channels:     pointer to structure array of returned data for each channel
+ * @return:       0 if OK, -ve on error
+ */
+int adc_channels_data(struct udevice *dev, unsigned int channel_mask,
+		      struct adc_channel *channels);
+
+/**
+ * adc_data_mask() - get data mask (ADC resolution bitmask) for given ADC device
+ *
+ * This can be used if adc uclass platform data is filled.
+ *
+ * @dev:       ADC device to check
+ * @data_mask: pointer to the returned data bitmask
+ * @return: 0 if OK, -ve on error
+ */
+int adc_data_mask(struct udevice *dev, unsigned int *data_mask);
+
+/**
+ * adc_channel_single_shot() - get output data of conversion for the ADC
+ * device's channel. This function searches for the device with the given name,
+ * starts the given channel conversion and returns the output data.
+ *
+ * Note: To use this function, device must implement metods:
+ * - start_channel()
+ * - channel_data()
+ *
+ * @name:    device's name to search
+ * @channel: device's input channel to init
+ * @data:    pointer to conversion output data
+ * @return:  0 if OK, -ve on error
+ */
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data);
+
+/**
+ * adc_channels_single_shot() - get ADC conversion output data for the selected
+ * device's channels. This function searches for the device by the given name,
+ * starts the selected channels conversion and returns the output data as array
+ * of type 'struct adc_channel'.
+ *
+ * Note: This function can be used if device implements one of ADC's single
+ * or multi-channel operation API. If multi-channel operation is not supported,
+ * then each selected channel is triggered by the sequence start/data in a loop.
+ *
+ * @name:         device's name to search
+ * @channel_mask: channel selection - a bit mask
+ * @channels:     pointer to conversion output data for the selected channels
+ * @return:       0 if OK, -ve on error
+ */
+int adc_channels_single_shot(const char *name, unsigned int channel_mask,
+			     struct adc_channel *channels);
+
+/**
+ * adc_vdd_value() - get the ADC device's positive reference Voltage value
+ *
+ * Note: Depending on bool value 'vdd_supply_is_negative' of platform data,
+ * the returned uV value can be negative, and it's not an error.
+ *
+ * @dev:     ADC device to check
+ * @uV:      Voltage value with polarization sign (uV)
+ * @return:  0 on success or -ve on error
+*/
+int adc_vdd_value(struct udevice *dev, int *uV);
+
+/**
+ * adc_vss_value() - get the ADC device's negative reference Voltage value
+ *
+ * Note: Depending on bool value 'vdd_supply_is_negative' of platform data,
+ * the returned uV value can be negative, and it's not an error.
+ *
+ * @dev:     ADC device to check
+ * @uV:      Voltage value with polarization sign (uV)
+ * @return:  0 on success or -ve on error
+*/
+int adc_vss_value(struct udevice *dev, int *uV);
+
+/**
+ * adc_stop() - stop operation for given ADC device.
+ *
+ * @dev:     ADC device to stop
+ * @return:  0 if OK, -ve on error
+ */
+int adc_stop(struct udevice *dev);
+
+#endif
diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h
index 6e32de8..cb9544b 100644
--- a/include/configs/dra7xx_evm.h
+++ b/include/configs/dra7xx_evm.h
@@ -82,11 +82,24 @@
 	"fdt ram 0x80f80000 0x80000;" \
 	"ramdisk ram 0x81000000 0x4000000\0"
 
+#define DFU_ALT_INFO_QSPI \
+	"dfu_alt_info_qspi=" \
+	"MLO raw 0x0 0x010000;" \
+	"MLO.backup1 raw 0x010000 0x010000;" \
+	"MLO.backup2 raw 0x020000 0x010000;" \
+	"MLO.backup3 raw 0x030000 0x010000;" \
+	"u-boot.img raw 0x040000 0x0100000;" \
+	"u-boot-spl-os raw 0x140000 0x080000;" \
+	"u-boot-env raw 0x1C0000 0x010000;" \
+	"u-boot-env.backup raw 0x1D0000 0x010000;" \
+	"kernel raw 0x1E0000 0x800000\0"
+
 #define DFUARGS \
 	"dfu_bufsiz=0x10000\0" \
 	DFU_ALT_INFO_MMC \
 	DFU_ALT_INFO_EMMC \
-	DFU_ALT_INFO_RAM
+	DFU_ALT_INFO_RAM \
+	DFU_ALT_INFO_QSPI
 
 /* Fastboot */
 #define CONFIG_USB_FUNCTION_FASTBOOT
@@ -207,6 +220,7 @@
 
 #define CONFIG_DFU_MMC
 #define CONFIG_DFU_RAM
+#define CONFIG_DFU_SF
 
 /* SATA */
 #define CONFIG_BOARD_LATE_INIT
diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h
index 3c70158..648e48b 100644
--- a/include/configs/odroid_xu3.h
+++ b/include/configs/odroid_xu3.h
@@ -94,6 +94,8 @@
 	"boot.scr fat 0 1;"                 \
 	"boot.cmd fat 0 1;"                 \
 	"exynos5422-odroidxu3.dtb fat 0 1;" \
+	"exynos5422-odroidxu3-lite.dtb fat 0 1;" \
+	"exynos5422-odroidxu4.dtb fat 0 1;" \
 	"boot part 0 1;"                    \
 	"root part 0 2\0"
 
@@ -113,9 +115,19 @@
 
 /* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */
 #define CONFIG_MISC_COMMON
+#define CONFIG_MISC_INIT_R
 #define CONFIG_SET_DFU_ALT_INFO
 #define CONFIG_SET_DFU_ALT_BUF_LEN	(SZ_1K)
 
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */
+#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
+#define CONFIG_ODROID_REV_AIN			9
+#define CONFIG_REVISION_TAG
+#define CONFIG_BOARD_TYPES
+
+#undef CONFIG_SYS_BOARD
+#define CONFIG_SYS_BOARD	"odroid"
+
 /* Define new extra env settings, including DFU settings */
 #undef CONFIG_EXTRA_ENV_SETTINGS
 #define CONFIG_EXTRA_ENV_SETTINGS \
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 886a44c..d0cf4ce 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -25,6 +25,7 @@
 	UCLASS_SIMPLE_BUS,	/* bus with child devices */
 
 	/* U-Boot uclasses start here - in alphabetical order */
+	UCLASS_ADC,		/* Analog-to-digital converter */
 	UCLASS_CLK,		/* Clock source, e.g. used by peripherals */
 	UCLASS_CPU,		/* CPU, typically part of an SoC */
 	UCLASS_CROS_EC,		/* Chrome OS EC */
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 9fcc7a1..0e36664 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -490,6 +490,19 @@
 		s32 default_val);
 
 /**
+ * Unsigned version of fdtdec_get_int. The property must have at least
+ * 4 bytes of data. The value of the first cell is returned.
+ *
+ * @param blob	FDT blob
+ * @param node	node to examine
+ * @param prop_name	name of property to find
+ * @param default_val	default value to return if the property is not found
+ * @return unsigned integer value, if found, or default_val if not
+ */
+unsigned int fdtdec_get_uint(const void *blob, int node, const char *prop_name,
+			unsigned int default_val);
+
+/**
  * Get a variable-sized number from a property
  *
  * This reads a number from one or more cells.
diff --git a/include/power/regulator.h b/include/power/regulator.h
index 1a51c3f..63c0814 100644
--- a/include/power/regulator.h
+++ b/include/power/regulator.h
@@ -419,4 +419,20 @@
  */
 int regulator_get_by_platname(const char *platname, struct udevice **devp);
 
+/**
+ * device_get_supply_regulator: returns the pointer to the supply regulator.
+ * Search by phandle, found in device's node.
+ *
+ * Note: Please pay attention to proper order of device bind sequence.
+ * The regulator device searched by the phandle, must be binded before
+ * this function call.
+ *
+ * @dev         - device with supply phandle
+ * @supply_name - phandle name of regulator
+ * @devp        - returned pointer to the supply device
+ * @return 0 on success or negative value of errno.
+ */
+int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
+				struct udevice **devp);
+
 #endif /* _INCLUDE_REGULATOR_H_ */
diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h
new file mode 100644
index 0000000..5da4719
--- /dev/null
+++ b/include/power/s2mps11.h
@@ -0,0 +1,109 @@
+#ifndef __S2MPS11__H__
+#define __S2MPS11__H__
+
+enum s2mps11_reg {
+	S2MPS11_REG_ID = 0,
+	S2MPS11_REG_INT1,
+	S2MPS11_REG_INT2,
+	S2MPS11_REG_INT3,
+	S2MPS11_REG_INT1M,
+	S2MPS11_REG_INT2M,
+	S2MPS11_REG_INT3M,
+	S2MPS11_REG_STATUS1,
+	S2MPS11_REG_STATUS2,
+	S2MPS11_REG_OFFSRC,
+	S2MPS11_REG_PWRONSRC,
+	S2MPS11_REG_RTC_CTRL,
+	S2MPS11_REG_CTRL1,
+	S2MPS11_REG_ETC_TEST,
+	S2MPS11_REG_RSVD3,
+	S2MPS11_REG_BU_CHG,
+	S2MPS11_REG_RAMP,
+	S2MPS11_REG_RAMP_BUCK,
+	S2MPS11_REG_LDO1_8,
+	S2MPS11_REG_LDO9_16,
+	S2MPS11_REG_LDO17_24,
+	S2MPS11_REG_LDO25_32,
+	S2MPS11_REG_LDO33_38,
+	S2MPS11_REG_LDO1_8_OVC,
+	S2MPS11_REG_LDO9_16_OVC,
+	S2MPS11_REG_LDO17_24_OVC,
+	S2MPS11_REG_LDO25_32_OVC,
+	S2MPS11_REG_LDO33_38_OVC,
+	S2MPS11_REG_RESERVED1,
+	S2MPS11_REG_RESERVED2,
+	S2MPS11_REG_RESERVED3,
+	S2MPS11_REG_RESERVED4,
+	S2MPS11_REG_RESERVED5,
+	S2MPS11_REG_RESERVED6,
+	S2MPS11_REG_RESERVED7,
+	S2MPS11_REG_RESERVED8,
+	S2MPS11_REG_WDRSTEN_CTRL,
+	S2MPS11_REG_B1CTRL1,
+	S2MPS11_REG_B1CTRL2,
+	S2MPS11_REG_B2CTRL1,
+	S2MPS11_REG_B2CTRL2,
+	S2MPS11_REG_B3CTRL1,
+	S2MPS11_REG_B3CTRL2,
+	S2MPS11_REG_B4CTRL1,
+	S2MPS11_REG_B4CTRL2,
+	S2MPS11_REG_B5CTRL1,
+	S2MPS11_REG_BUCK5_SW,
+	S2MPS11_REG_B5CTRL2,
+	S2MPS11_REG_B5CTRL3,
+	S2MPS11_REG_B5CTRL4,
+	S2MPS11_REG_B5CTRL5,
+	S2MPS11_REG_B6CTRL1,
+	S2MPS11_REG_B6CTRL2,
+	S2MPS11_REG_B7CTRL1,
+	S2MPS11_REG_B7CTRL2,
+	S2MPS11_REG_B8CTRL1,
+	S2MPS11_REG_B8CTRL2,
+	S2MPS11_REG_B9CTRL1,
+	S2MPS11_REG_B9CTRL2,
+	S2MPS11_REG_B10CTRL1,
+	S2MPS11_REG_B10CTRL2,
+	S2MPS11_REG_L1CTRL,
+	S2MPS11_REG_L2CTRL,
+	S2MPS11_REG_L3CTRL,
+	S2MPS11_REG_L4CTRL,
+	S2MPS11_REG_L5CTRL,
+	S2MPS11_REG_L6CTRL,
+	S2MPS11_REG_L7CTRL,
+	S2MPS11_REG_L8CTRL,
+	S2MPS11_REG_L9CTRL,
+	S2MPS11_REG_L10CTRL,
+	S2MPS11_REG_L11CTRL,
+	S2MPS11_REG_L12CTRL,
+	S2MPS11_REG_L13CTRL,
+	S2MPS11_REG_L14CTRL,
+	S2MPS11_REG_L15CTRL,
+	S2MPS11_REG_L16CTRL,
+	S2MPS11_REG_L17CTRL,
+	S2MPS11_REG_L18CTRL,
+	S2MPS11_REG_L19CTRL,
+	S2MPS11_REG_L20CTRL,
+	S2MPS11_REG_L21CTRL,
+	S2MPS11_REG_L22CTRL,
+	S2MPS11_REG_L23CTRL,
+	S2MPS11_REG_L24CTRL,
+	S2MPS11_REG_L25CTRL,
+	S2MPS11_REG_L26CTRL,
+	S2MPS11_REG_L27CTRL,
+	S2MPS11_REG_L28CTRL,
+	S2MPS11_REG_L29CTRL,
+	S2MPS11_REG_L30CTRL,
+	S2MPS11_REG_L31CTRL,
+	S2MPS11_REG_L32CTRL,
+	S2MPS11_REG_L33CTRL,
+	S2MPS11_REG_L34CTRL,
+	S2MPS11_REG_L35CTRL,
+	S2MPS11_REG_L36CTRL,
+	S2MPS11_REG_L37CTRL,
+	S2MPS11_REG_L38CTRL,
+	S2MPS11_REG_COUNT,
+};
+
+#define S2MPS11_LDO26_ENABLE	0xec
+
+#endif
diff --git a/include/power/sandbox_pmic.h b/include/power/sandbox_pmic.h
index 8547674..7fdbfb9 100644
--- a/include/power/sandbox_pmic.h
+++ b/include/power/sandbox_pmic.h
@@ -126,6 +126,10 @@
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UA	200000
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_ENABLE	true
 
+/* BUCK2: for testing sandbox ADC's supply */
+#define SANDBOX_BUCK2_INITIAL_EXPECTED_UV	3000000
+#define SANDBOX_BUCK2_SET_UV			3300000
+
 /* LDO1/2 for testing regulator_list_autoset() */
 #define SANDBOX_LDO1_AUTOSET_EXPECTED_UV	1800000
 #define SANDBOX_LDO1_AUTOSET_EXPECTED_UA	100000
diff --git a/include/samsung/exynos5-dt-types.h b/include/samsung/exynos5-dt-types.h
new file mode 100644
index 0000000..479e2e7
--- /dev/null
+++ b/include/samsung/exynos5-dt-types.h
@@ -0,0 +1,27 @@
+#ifndef _EXYNOS5_DT_H_
+#define _EXYNOS5_DT_H_
+
+enum {
+	EXYNOS5_BOARD_GENERIC,
+
+	EXYNOS5_BOARD_ODROID_XU3,
+	EXYNOS5_BOARD_ODROID_XU3_REV01,
+	EXYNOS5_BOARD_ODROID_XU3_REV02,
+	EXYNOS5_BOARD_ODROID_XU4_REV01,
+	EXYNOS5_BOARD_ODROID_UNKNOWN,
+
+	EXYNOS5_BOARD_COUNT,
+};
+
+struct odroid_rev_info {
+	int board_type;
+	int board_rev;
+	int adc_val;
+	const char *name;
+};
+
+bool board_is_generic(void);
+bool board_is_odroidxu3(void);
+bool board_is_odroidxu4(void);
+
+#endif
diff --git a/include/sandbox-adc.h b/include/sandbox-adc.h
new file mode 100644
index 0000000..79ff01c
--- /dev/null
+++ b/include/sandbox-adc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SANDBOX_ADC_H_
+#define _SANDBOX_ADC_H_
+
+#define SANDBOX_ADC_DEVNAME		"adc@0"
+#define SANDBOX_ADC_DATA_MASK		0xffff /* 16-bits resolution */
+#define SANDBOX_ADC_CHANNELS		4
+#define SANDBOX_ADC_CHANNEL0_DATA	0x0
+#define SANDBOX_ADC_CHANNEL1_DATA	0x1000
+#define SANDBOX_ADC_CHANNEL2_DATA	0x2000
+#define SANDBOX_ADC_CHANNEL3_DATA	0x3000
+
+enum sandbox_adc_mode {
+	SANDBOX_ADC_MODE_SINGLE_CHANNEL = 0,
+	SANDBOX_ADC_MODE_MULTI_CHANNEL,
+};
+
+enum sandbox_adc_status {
+	SANDBOX_ADC_INACTIVE = 0,
+	SANDBOX_ADC_ACTIVE,
+};
+
+#define SANDBOX_ADC_VSS_VALUE		0
+
+#endif
diff --git a/lib/fdtdec_common.c b/lib/fdtdec_common.c
index 757931a..63b704a 100644
--- a/lib/fdtdec_common.c
+++ b/lib/fdtdec_common.c
@@ -36,3 +36,21 @@
 	debug("(not found)\n");
 	return default_val;
 }
+
+unsigned int fdtdec_get_uint(const void *blob, int node, const char *prop_name,
+			unsigned int default_val)
+{
+	const int *cell;
+	int len;
+
+	debug("%s: %s: ", __func__, prop_name);
+	cell = fdt_getprop(blob, node, prop_name, &len);
+	if (cell && len >= sizeof(unsigned int)) {
+		unsigned int val = fdt32_to_cpu(cell[0]);
+
+		debug("%#x (%d)\n", val, val);
+		return val;
+	}
+	debug("(not found)\n");
+	return default_val;
+}
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 7b3626c..39630f6 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -33,4 +33,5 @@
 obj-$(CONFIG_DM_USB) += usb.o
 obj-$(CONFIG_DM_PMIC) += pmic.o
 obj-$(CONFIG_DM_REGULATOR) += regulator.o
+obj-$(CONFIG_ADC) += adc.o
 endif
diff --git a/test/dm/adc.c b/test/dm/adc.c
new file mode 100644
index 0000000..b0d4fe5
--- /dev/null
+++ b/test/dm/adc.c
@@ -0,0 +1,165 @@
+/*
+ * Tests for the driver model ADC API
+ *
+ * Copyright (c) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <adc.h>
+#include <dm.h>
+#include <dm/root.h>
+#include <dm/util.h>
+#include <dm/test.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <power/regulator.h>
+#include <power/sandbox_pmic.h>
+#include <sandbox-adc.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int dm_test_adc_bind(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev));
+	ut_asserteq_str(SANDBOX_ADC_DEVNAME, dev->name);
+
+	return 0;
+}
+DM_TEST(dm_test_adc_bind, DM_TESTF_SCAN_FDT);
+
+static int dm_test_adc_wrong_channel_selection(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev));
+	ut_asserteq(-EINVAL, adc_start_channel(dev, SANDBOX_ADC_CHANNELS));
+
+	return 0;
+}
+DM_TEST(dm_test_adc_wrong_channel_selection, DM_TESTF_SCAN_FDT);
+
+static int dm_test_adc_supply(struct unit_test_state *uts)
+{
+	struct udevice *supply;
+	struct udevice *dev;
+	int uV;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev));
+
+	/* Test Vss value - predefined 0 uV */
+	ut_assertok(adc_vss_value(dev, &uV));
+	ut_asserteq(SANDBOX_ADC_VSS_VALUE, uV);
+
+	/* Test Vdd initial value - buck2 */
+	ut_assertok(adc_vdd_value(dev, &uV));
+	ut_asserteq(SANDBOX_BUCK2_INITIAL_EXPECTED_UV, uV);
+
+	/* Change Vdd value - buck2 manual preset */
+	ut_assertok(regulator_get_by_devname(SANDBOX_BUCK2_DEVNAME, &supply));
+	ut_assertok(regulator_set_value(supply, SANDBOX_BUCK2_SET_UV));
+	ut_asserteq(SANDBOX_BUCK2_SET_UV, regulator_get_value(supply));
+
+	/* Update ADC platdata and get new Vdd value */
+	ut_assertok(adc_vdd_value(dev, &uV));
+	ut_asserteq(SANDBOX_BUCK2_SET_UV, uV);
+
+	/* Disable buck2 and test ADC supply enable function */
+	ut_assertok(regulator_set_enable(supply, false));
+	ut_asserteq(false, regulator_get_enable(supply));
+	/* adc_start_channel() should enable the supply regulator */
+	ut_assertok(adc_start_channel(dev, 0));
+	ut_asserteq(true, regulator_get_enable(supply));
+
+	return 0;
+}
+DM_TEST(dm_test_adc_supply, DM_TESTF_SCAN_FDT);
+
+struct adc_channel adc_channel_test_data[] = {
+	{ 0, SANDBOX_ADC_CHANNEL0_DATA },
+	{ 1, SANDBOX_ADC_CHANNEL1_DATA },
+	{ 2, SANDBOX_ADC_CHANNEL2_DATA },
+	{ 3, SANDBOX_ADC_CHANNEL3_DATA },
+};
+
+static int dm_test_adc_single_channel_conversion(struct unit_test_state *uts)
+{
+	struct adc_channel *tdata = adc_channel_test_data;
+	unsigned int i, data;
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev));
+	/* Test each ADC channel's value */
+	for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++) {
+		ut_assertok(adc_start_channel(dev, tdata->id));
+		ut_assertok(adc_channel_data(dev, tdata->id, &data));
+		ut_asserteq(tdata->data, data);
+	}
+
+	return 0;
+}
+DM_TEST(dm_test_adc_single_channel_conversion, DM_TESTF_SCAN_FDT);
+
+static int dm_test_adc_multi_channel_conversion(struct unit_test_state *uts)
+{
+	struct adc_channel channels[SANDBOX_ADC_CHANNELS];
+	struct udevice *dev;
+	struct adc_channel *tdata = adc_channel_test_data;
+	unsigned int i, channel_mask;
+
+	channel_mask = ADC_CHANNEL(0) | ADC_CHANNEL(1) |
+		       ADC_CHANNEL(2) | ADC_CHANNEL(3);
+
+	/* Start multi channel conversion */
+	ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev));
+	ut_assertok(adc_start_channels(dev, channel_mask));
+	ut_assertok(adc_channels_data(dev, channel_mask, channels));
+
+	/* Compare the expected and returned conversion data. */
+	for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++)
+		ut_asserteq(tdata->data, channels[i].data);
+
+	return 0;
+}
+DM_TEST(dm_test_adc_multi_channel_conversion, DM_TESTF_SCAN_FDT);
+
+static int dm_test_adc_single_channel_shot(struct unit_test_state *uts)
+{
+	struct adc_channel *tdata = adc_channel_test_data;
+	unsigned int i, data;
+
+	for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++) {
+		/* Start single channel conversion */
+		ut_assertok(adc_channel_single_shot("adc", tdata->id, &data));
+		/* Compare the expected and returned conversion data. */
+		ut_asserteq(tdata->data, data);
+	}
+
+	return 0;
+}
+DM_TEST(dm_test_adc_single_channel_shot, DM_TESTF_SCAN_FDT);
+
+static int dm_test_adc_multi_channel_shot(struct unit_test_state *uts)
+{
+	struct adc_channel channels[SANDBOX_ADC_CHANNELS];
+	struct adc_channel *tdata = adc_channel_test_data;
+	unsigned int i, channel_mask;
+
+	channel_mask = ADC_CHANNEL(0) | ADC_CHANNEL(1) |
+		       ADC_CHANNEL(2) | ADC_CHANNEL(3);
+
+	/* Start single call and multi channel conversion */
+	ut_assertok(adc_channels_single_shot("adc", channel_mask, channels));
+
+	/* Compare the expected and returned conversion data. */
+	for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++)
+		ut_asserteq(tdata->data, channels[i].data);
+
+	return 0;
+}
+DM_TEST(dm_test_adc_multi_channel_shot, DM_TESTF_SCAN_FDT);