Merge git://git.denx.de/u-boot-dm
diff --git a/arch/arm/cpu/armv7/tegra124/Kconfig b/arch/arm/cpu/armv7/tegra124/Kconfig
index 6a1c83a..88f627c 100644
--- a/arch/arm/cpu/armv7/tegra124/Kconfig
+++ b/arch/arm/cpu/armv7/tegra124/Kconfig
@@ -6,6 +6,15 @@
 config TARGET_JETSON_TK1
 	bool "NVIDIA Tegra124 Jetson TK1 board"
 
+config TARGET_NYAN_BIG
+	bool "Google/NVIDIA Nyan-big Chrombook"
+	help
+	  Nyan Big is a Tegra124 clamshell board that is very similar
+	  to venice2, but it has a different panel, the sdcard CD and WP
+	  sense are flipped, and it has a different revision of the AS3722
+	  PMIC. The retail name is the Acer Chromebook 13 CB5-311-T7NN
+	  (13.3-inch HD, NVIDIA Tegra K1, 2GB).
+
 config TARGET_VENICE2
 	bool "NVIDIA Tegra124 Venice2"
 
@@ -15,6 +24,7 @@
 	default "tegra124"
 
 source "board/nvidia/jetson-tk1/Kconfig"
+source "board/nvidia/nyan-big/Kconfig"
 source "board/nvidia/venice2/Kconfig"
 
 endif
diff --git a/arch/arm/cpu/tegra20-common/pmu.c b/arch/arm/cpu/tegra20-common/pmu.c
index c595f70..36a76a2 100644
--- a/arch/arm/cpu/tegra20-common/pmu.c
+++ b/arch/arm/cpu/tegra20-common/pmu.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <i2c.h>
 #include <tps6586x.h>
 #include <asm/io.h>
 #include <asm/arch/tegra.h>
@@ -23,9 +24,13 @@
 #define VDD_TRANSITION_STEP	0x06	/* 150mv */
 #define VDD_TRANSITION_RATE	0x06	/* 3.52mv/us */
 
+#define PMI_I2C_ADDRESS	0x34	/* chip requires this address */
+
 int pmu_set_nominal(void)
 {
-	int core, cpu, bus;
+	struct udevice *bus, *dev;
+	int core, cpu;
+	int ret;
 
 	/* by default, the table has been filled with T25 settings */
 	switch (tegra_get_chip_sku()) {
@@ -42,12 +47,18 @@
 		return -1;
 	}
 
-	bus = tegra_i2c_get_dvc_bus_num();
-	if (bus == -1) {
+	ret = tegra_i2c_get_dvc_bus(&bus);
+	if (ret) {
 		debug("%s: Cannot find DVC I2C bus\n", __func__);
-		return -1;
+		return ret;
 	}
-	tps6586x_init(bus);
+	ret = i2c_get_chip(bus, PMI_I2C_ADDRESS, &dev);
+	if (ret) {
+		debug("%s: Cannot find DVC I2C chip\n", __func__);
+		return ret;
+	}
+
+	tps6586x_init(dev);
 	tps6586x_set_pwm_mode(TPS6586X_PWM_SM1);
 	return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP,
 				VDD_TRANSITION_RATE, VDD_RELATION);
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 187d58c..e6a495c 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -31,6 +31,7 @@
 	tegra30-tec-ng.dtb \
 	tegra114-dalmore.dtb \
 	tegra124-jetson-tk1.dtb \
+	tegra124-nyan-big.dtb \
 	tegra124-venice2.dtb
 dtb-$(CONFIG_ARCH_UNIPHIER) += \
 	uniphier-ph1-sld3-ref.dtb \
diff --git a/arch/arm/dts/cros-ec-keyboard.dtsi b/arch/arm/dts/cros-ec-keyboard.dtsi
new file mode 100644
index 0000000..9c7fb0a
--- /dev/null
+++ b/arch/arm/dts/cros-ec-keyboard.dtsi
@@ -0,0 +1,105 @@
+/*
+ * Keyboard dts fragment for devices that use cros-ec-keyboard
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <dt-bindings/input/input.h>
+
+&cros_ec {
+	keyboard-controller {
+		compatible = "google,cros-ec-keyb";
+		keypad,num-rows = <8>;
+		keypad,num-columns = <13>;
+		google,needs-ghost-filter;
+
+		linux,keymap = <
+			MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA)
+			MATRIX_KEY(0x00, 0x02, KEY_F1)
+			MATRIX_KEY(0x00, 0x03, KEY_B)
+			MATRIX_KEY(0x00, 0x04, KEY_F10)
+			MATRIX_KEY(0x00, 0x06, KEY_N)
+			MATRIX_KEY(0x00, 0x08, KEY_EQUAL)
+			MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT)
+
+			MATRIX_KEY(0x01, 0x01, KEY_ESC)
+			MATRIX_KEY(0x01, 0x02, KEY_F4)
+			MATRIX_KEY(0x01, 0x03, KEY_G)
+			MATRIX_KEY(0x01, 0x04, KEY_F7)
+			MATRIX_KEY(0x01, 0x06, KEY_H)
+			MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE)
+			MATRIX_KEY(0x01, 0x09, KEY_F9)
+			MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE)
+
+			MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL)
+			MATRIX_KEY(0x02, 0x01, KEY_TAB)
+			MATRIX_KEY(0x02, 0x02, KEY_F3)
+			MATRIX_KEY(0x02, 0x03, KEY_T)
+			MATRIX_KEY(0x02, 0x04, KEY_F6)
+			MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE)
+			MATRIX_KEY(0x02, 0x06, KEY_Y)
+			MATRIX_KEY(0x02, 0x07, KEY_102ND)
+			MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE)
+			MATRIX_KEY(0x02, 0x09, KEY_F8)
+
+			MATRIX_KEY(0x03, 0x01, KEY_GRAVE)
+			MATRIX_KEY(0x03, 0x02, KEY_F2)
+			MATRIX_KEY(0x03, 0x03, KEY_5)
+			MATRIX_KEY(0x03, 0x04, KEY_F5)
+			MATRIX_KEY(0x03, 0x06, KEY_6)
+			MATRIX_KEY(0x03, 0x08, KEY_MINUS)
+			MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH)
+
+			MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL)
+			MATRIX_KEY(0x04, 0x01, KEY_A)
+			MATRIX_KEY(0x04, 0x02, KEY_D)
+			MATRIX_KEY(0x04, 0x03, KEY_F)
+			MATRIX_KEY(0x04, 0x04, KEY_S)
+			MATRIX_KEY(0x04, 0x05, KEY_K)
+			MATRIX_KEY(0x04, 0x06, KEY_J)
+			MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON)
+			MATRIX_KEY(0x04, 0x09, KEY_L)
+			MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH)
+			MATRIX_KEY(0x04, 0x0b, KEY_ENTER)
+
+			MATRIX_KEY(0x05, 0x01, KEY_Z)
+			MATRIX_KEY(0x05, 0x02, KEY_C)
+			MATRIX_KEY(0x05, 0x03, KEY_V)
+			MATRIX_KEY(0x05, 0x04, KEY_X)
+			MATRIX_KEY(0x05, 0x05, KEY_COMMA)
+			MATRIX_KEY(0x05, 0x06, KEY_M)
+			MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT)
+			MATRIX_KEY(0x05, 0x08, KEY_SLASH)
+			MATRIX_KEY(0x05, 0x09, KEY_DOT)
+			MATRIX_KEY(0x05, 0x0b, KEY_SPACE)
+
+			MATRIX_KEY(0x06, 0x01, KEY_1)
+			MATRIX_KEY(0x06, 0x02, KEY_3)
+			MATRIX_KEY(0x06, 0x03, KEY_4)
+			MATRIX_KEY(0x06, 0x04, KEY_2)
+			MATRIX_KEY(0x06, 0x05, KEY_8)
+			MATRIX_KEY(0x06, 0x06, KEY_7)
+			MATRIX_KEY(0x06, 0x08, KEY_0)
+			MATRIX_KEY(0x06, 0x09, KEY_9)
+			MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT)
+			MATRIX_KEY(0x06, 0x0b, KEY_DOWN)
+			MATRIX_KEY(0x06, 0x0c, KEY_RIGHT)
+
+			MATRIX_KEY(0x07, 0x01, KEY_Q)
+			MATRIX_KEY(0x07, 0x02, KEY_E)
+			MATRIX_KEY(0x07, 0x03, KEY_R)
+			MATRIX_KEY(0x07, 0x04, KEY_W)
+			MATRIX_KEY(0x07, 0x05, KEY_I)
+			MATRIX_KEY(0x07, 0x06, KEY_U)
+			MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT)
+			MATRIX_KEY(0x07, 0x08, KEY_P)
+			MATRIX_KEY(0x07, 0x09, KEY_O)
+			MATRIX_KEY(0x07, 0x0b, KEY_UP)
+			MATRIX_KEY(0x07, 0x0c, KEY_LEFT)
+		>;
+	};
+};
diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts
index ffad116..f6fe9a0 100644
--- a/arch/arm/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/dts/tegra124-jetson-tk1.dts
@@ -16,7 +16,6 @@
 		i2c2 = "/i2c@7000c400";
 		i2c3 = "/i2c@7000c500";
 		i2c4 = "/i2c@7000c700";
-		i2c5 = "/i2c@7000d100";
 		sdhci0 = "/sdhci@700b0600";
 		sdhci1 = "/sdhci@700b0400";
 		spi0 = "/spi@7000d400";
diff --git a/arch/arm/dts/tegra124-nyan-big.dts b/arch/arm/dts/tegra124-nyan-big.dts
new file mode 100644
index 0000000..c1f35a0
--- /dev/null
+++ b/arch/arm/dts/tegra124-nyan-big.dts
@@ -0,0 +1,365 @@
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "tegra124.dtsi"
+
+/ {
+	model = "Acer Chromebook 13 CB5-311";
+	compatible = "google,nyan-big", "nvidia,tegra124";
+
+	aliases {
+		console = &uarta;
+		i2c0 = "/i2c@7000d000";
+		i2c1 = "/i2c@7000c000";
+		i2c2 = "/i2c@7000c400";
+		i2c3 = "/i2c@7000c500";
+		i2c4 = "/i2c@7000c700";
+		i2c5 = "/i2c@7000d100";
+		rtc0 = "/i2c@0,7000d000/pmic@40";
+		rtc1 = "/rtc@0,7000e000";
+		sdhci0 = "/sdhci@700b0600";
+		sdhci1 = "/sdhci@700b0400";
+		spi0 = "/spi@7000d400";
+		spi1 = "/spi@7000da00";
+		usb0 = "/usb@7d000000";
+		usb1 = "/usb@7d008000";
+	};
+
+	memory {
+		reg = <0x80000000 0x80000000>;
+	};
+
+	serial@70006000 {
+		/* Debug connector on the bottom of the board near SD card. */
+		status = "okay";
+	};
+
+	pwm@7000a000 {
+		status = "okay";
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <100000>;
+
+		acodec: audio-codec@10 {
+			compatible = "maxim,max98090";
+			reg = <0x10>;
+			interrupt-parent = <&gpio>;
+			interrupts = <TEGRA_GPIO(H, 4) GPIO_ACTIVE_HIGH>;
+		};
+
+		temperature-sensor@4c {
+			compatible = "ti,tmp451";
+			reg = <0x4c>;
+			interrupt-parent = <&gpio>;
+			interrupts = <TEGRA_GPIO(I, 6) IRQ_TYPE_LEVEL_LOW>;
+
+			#thermal-sensor-cells = <1>;
+		};
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000c500 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		tpm@20 {
+			compatible = "infineon,slb9645tt";
+			reg = <0x20>;
+		};
+	};
+
+	hdmi_ddc: i2c@7000c700 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		pmic: pmic@40 {
+			compatible = "ams,as3722";
+			reg = <0x40>;
+			interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
+
+			ams,system-power-controller;
+
+			#interrupt-cells = <2>;
+			interrupt-controller;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			pinctrl-names = "default";
+			pinctrl-0 = <&as3722_default>;
+
+			as3722_default: pinmux {
+				gpio0 {
+					pins = "gpio0";
+					function = "gpio";
+					bias-pull-down;
+				};
+
+				gpio1 {
+					pins = "gpio1";
+					function = "gpio";
+					bias-pull-up;
+				};
+
+				gpio2_4_7 {
+					pins = "gpio2", "gpio4", "gpio7";
+					function = "gpio";
+					bias-pull-up;
+				};
+
+				gpio3_6 {
+					pins = "gpio3", "gpio6";
+					bias-high-impedance;
+				};
+
+				gpio5 {
+					pins = "gpio5";
+					function = "clk32k-out";
+					bias-pull-down;
+				};
+			};
+		};
+	};
+
+	spi@7000d400 {
+		status = "okay";
+
+		cros_ec: cros-ec@0 {
+			compatible = "google,cros-ec-spi";
+			spi-max-frequency = <3000000>;
+			interrupt-parent = <&gpio>;
+			interrupts = <TEGRA_GPIO(C, 7) IRQ_TYPE_LEVEL_LOW>;
+			reg = <0>;
+
+			google,cros-ec-spi-msg-delay = <2000>;
+
+			i2c-tunnel {
+				compatible = "google,cros-ec-i2c-tunnel";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				google,remote-bus = <0>;
+
+				charger: bq24735@9 {
+					compatible = "ti,bq24735";
+					reg = <0x9>;
+					interrupt-parent = <&gpio>;
+					interrupts = <TEGRA_GPIO(J, 0)
+							GPIO_ACTIVE_HIGH>;
+					ti,ac-detect-gpios = <&gpio
+							TEGRA_GPIO(J, 0)
+							GPIO_ACTIVE_HIGH>;
+				};
+
+				battery: sbs-battery@b {
+					compatible = "sbs,sbs-battery";
+					reg = <0xb>;
+					sbs,i2c-retry-count = <2>;
+					sbs,poll-retry-count = <10>;
+					power-supplies = <&charger>;
+				};
+			};
+		};
+	};
+
+	spi@7000da00 {
+		status = "okay";
+		spi-max-frequency = <25000000>;
+
+		flash@0 {
+			compatible = "winbond,w25q32dw";
+			reg = <0>;
+		};
+	};
+
+	pmc@7000e400 {
+		nvidia,invert-interrupt;
+		nvidia,suspend-mode = <0>;
+		nvidia,cpu-pwr-good-time = <500>;
+		nvidia,cpu-pwr-off-time = <300>;
+		nvidia,core-pwr-good-time = <641 3845>;
+		nvidia,core-pwr-off-time = <61036>;
+		nvidia,core-power-req-active-high;
+		nvidia,sys-clock-req-active-high;
+	};
+
+	hda@70030000 {
+		status = "okay";
+	};
+
+	sdhci@700b0000 { /* WiFi/BT on this bus */
+		status = "okay";
+		power-gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_HIGH>;
+		bus-width = <4>;
+		no-1-8-v;
+		non-removable;
+	};
+
+	sdhci@700b0400 { /* SD Card on this bus */
+		status = "okay";
+		cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
+		power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
+		wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_LOW>;
+		bus-width = <4>;
+		no-1-8-v;
+	};
+
+	sdhci@700b0600 { /* eMMC on this bus */
+		status = "okay";
+		bus-width = <8>;
+		no-1-8-v;
+		non-removable;
+	};
+
+	ahub@70300000 {
+		i2s@70301100 {
+			status = "okay";
+		};
+	};
+
+	usb@7d000000 { /* Rear external USB port. */
+		status = "okay";
+	};
+
+	usb-phy@7d000000 {
+		status = "okay";
+	};
+
+	usb@7d004000 { /* Internal webcam. */
+		status = "okay";
+	};
+
+	usb-phy@7d004000 {
+		status = "okay";
+	};
+
+	usb@7d008000 { /* Left external USB port. */
+		status = "okay";
+	};
+
+	usb-phy@7d008000 {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+
+		enable-gpios = <&gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_HIGH>;
+		pwms = <&pwm 1 1000000>;
+
+		default-brightness-level = <224>;
+		brightness-levels =
+			<  0   1   2   3   4   5   6   7
+			   8   9  10  11  12  13  14  15
+			  16  17  18  19  20  21  22  23
+			  24  25  26  27  28  29  30  31
+			  32  33  34  35  36  37  38  39
+			  40  41  42  43  44  45  46  47
+			  48  49  50  51  52  53  54  55
+			  56  57  58  59  60  61  62  63
+			  64  65  66  67  68  69  70  71
+			  72  73  74  75  76  77  78  79
+			  80  81  82  83  84  85  86  87
+			  88  89  90  91  92  93  94  95
+			  96  97  98  99 100 101 102 103
+			 104 105 106 107 108 109 110 111
+			 112 113 114 115 116 117 118 119
+			 120 121 122 123 124 125 126 127
+			 128 129 130 131 132 133 134 135
+			 136 137 138 139 140 141 142 143
+			 144 145 146 147 148 149 150 151
+			 152 153 154 155 156 157 158 159
+			 160 161 162 163 164 165 166 167
+			 168 169 170 171 172 173 174 175
+			 176 177 178 179 180 181 182 183
+			 184 185 186 187 188 189 190 191
+			 192 193 194 195 196 197 198 199
+			 200 201 202 203 204 205 206 207
+			 208 209 210 211 212 213 214 215
+			 216 217 218 219 220 221 222 223
+			 224 225 226 227 228 229 230 231
+			 232 233 234 235 236 237 238 239
+			 240 241 242 243 244 245 246 247
+			 248 249 250 251 252 253 254 255
+			 256>;
+	};
+
+	clocks {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		clk32k_in: clock@0 {
+			compatible = "fixed-clock";
+			reg = <0>;
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		lid {
+			label = "Lid";
+			gpios = <&gpio TEGRA_GPIO(R, 4) GPIO_ACTIVE_LOW>;
+			linux,input-type = <5>;
+			linux,code = <KEY_RESERVED>;
+			debounce-interval = <1>;
+			gpio-key,wakeup;
+		};
+
+		power {
+			label = "Power";
+			gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_POWER>;
+			debounce-interval = <30>;
+			gpio-key,wakeup;
+		};
+	};
+
+	panel: panel {
+		compatible = "auo,b133xtn01";
+
+		backlight = <&backlight>;
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-max98090-nyan-big",
+			     "nvidia,tegra-audio-max98090";
+		nvidia,model = "Acer Chromebook 13";
+
+		nvidia,audio-routing =
+			"Headphones", "HPR",
+			"Headphones", "HPL",
+			"Speakers", "SPKR",
+			"Speakers", "SPKL",
+			"Mic Jack", "MICBIAS",
+			"DMICL", "Int Mic",
+			"DMICR", "Int Mic",
+			"IN34", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&acodec>;
+
+		clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
+			 <&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
+			 <&tegra_car TEGRA124_CLK_EXTERN1>;
+		clock-names = "pll_a", "pll_a_out0", "mclk";
+
+		nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(I, 7) GPIO_ACTIVE_HIGH>;
+	};
+};
+
+#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/dts/tegra124.dtsi b/arch/arm/dts/tegra124.dtsi
index 3288f28..6b5c2be 100644
--- a/arch/arm/dts/tegra124.dtsi
+++ b/arch/arm/dts/tegra124.dtsi
@@ -1,5 +1,6 @@
 #include <dt-bindings/clock/tegra124-car.h>
 #include <dt-bindings/gpio/tegra-gpio.h>
+#include <dt-bindings/pinctrl/pinctrl-tegra.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 #include "skeleton.dtsi"
@@ -192,6 +193,16 @@
 		status = "disabled";
 	};
 
+	pwm: pwm@7000a000 {
+		compatible = "nvidia,tegra124-pwm", "nvidia,tegra20-pwm";
+		reg = <0x7000a000 0x100>;
+		#pwm-cells = <2>;
+		clocks = <&tegra_car TEGRA124_CLK_PWM>;
+		resets = <&tegra_car 17>;
+		reset-names = "pwm";
+		status = "disabled";
+	};
+
 	spi@7000d400 {
 		compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi";
 		reg = <0x7000d400 0x200>;
@@ -290,6 +301,109 @@
 		status = "disabled";
 	};
 
+	ahub@70300000 {
+		compatible = "nvidia,tegra124-ahub";
+		reg = <0x70300000 0x200>,
+		      <0x70300800 0x800>,
+		      <0x70300200 0x600>;
+		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&tegra_car TEGRA124_CLK_D_AUDIO>,
+			 <&tegra_car TEGRA124_CLK_APBIF>;
+		clock-names = "d_audio", "apbif";
+		resets = <&tegra_car 106>, /* d_audio */
+			 <&tegra_car 107>, /* apbif */
+			 <&tegra_car 30>,  /* i2s0 */
+			 <&tegra_car 11>,  /* i2s1 */
+			 <&tegra_car 18>,  /* i2s2 */
+			 <&tegra_car 101>, /* i2s3 */
+			 <&tegra_car 102>, /* i2s4 */
+			 <&tegra_car 108>, /* dam0 */
+			 <&tegra_car 109>, /* dam1 */
+			 <&tegra_car 110>, /* dam2 */
+			 <&tegra_car 10>,  /* spdif */
+			 <&tegra_car 153>, /* amx */
+			 <&tegra_car 185>, /* amx1 */
+			 <&tegra_car 154>, /* adx */
+			 <&tegra_car 180>, /* adx1 */
+			 <&tegra_car 186>, /* afc0 */
+			 <&tegra_car 187>, /* afc1 */
+			 <&tegra_car 188>, /* afc2 */
+			 <&tegra_car 189>, /* afc3 */
+			 <&tegra_car 190>, /* afc4 */
+			 <&tegra_car 191>; /* afc5 */
+		reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
+			      "i2s3", "i2s4", "dam0", "dam1", "dam2",
+			      "spdif", "amx", "amx1", "adx", "adx1",
+			      "afc0", "afc1", "afc2", "afc3", "afc4", "afc5";
+		dmas = <&apbdma 1>, <&apbdma 1>,
+		       <&apbdma 2>, <&apbdma 2>,
+		       <&apbdma 3>, <&apbdma 3>,
+		       <&apbdma 4>, <&apbdma 4>,
+		       <&apbdma 6>, <&apbdma 6>,
+		       <&apbdma 7>, <&apbdma 7>,
+		       <&apbdma 12>, <&apbdma 12>,
+		       <&apbdma 13>, <&apbdma 13>,
+		       <&apbdma 14>, <&apbdma 14>,
+		       <&apbdma 29>, <&apbdma 29>;
+		dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2",
+			    "rx3", "tx3", "rx4", "tx4", "rx5", "tx5",
+			    "rx6", "tx6", "rx7", "tx7", "rx8", "tx8",
+			    "rx9", "tx9";
+		ranges;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		tegra_i2s0: i2s@70301000 {
+			compatible = "nvidia,tegra124-i2s";
+			reg = <0x70301000 0x100>;
+			nvidia,ahub-cif-ids = <4 4>;
+			clocks = <&tegra_car TEGRA124_CLK_I2S0>;
+			resets = <&tegra_car 30>;
+			reset-names = "i2s";
+			status = "disabled";
+		};
+
+		tegra_i2s1: i2s@70301100 {
+			compatible = "nvidia,tegra124-i2s";
+			reg = <0x70301100 0x100>;
+			nvidia,ahub-cif-ids = <5 5>;
+			clocks = <&tegra_car TEGRA124_CLK_I2S1>;
+			resets = <&tegra_car 11>;
+			reset-names = "i2s";
+			status = "disabled";
+		};
+
+		tegra_i2s2: i2s@70301200 {
+			compatible = "nvidia,tegra124-i2s";
+			reg = <0x70301200 0x100>;
+			nvidia,ahub-cif-ids = <6 6>;
+			clocks = <&tegra_car TEGRA124_CLK_I2S2>;
+			resets = <&tegra_car 18>;
+			reset-names = "i2s";
+			status = "disabled";
+		};
+
+		tegra_i2s3: i2s@70301300 {
+			compatible = "nvidia,tegra124-i2s";
+			reg = <0x70301300 0x100>;
+			nvidia,ahub-cif-ids = <7 7>;
+			clocks = <&tegra_car TEGRA124_CLK_I2S3>;
+			resets = <&tegra_car 101>;
+			reset-names = "i2s";
+			status = "disabled";
+		};
+
+		tegra_i2s4: i2s@70301400 {
+			compatible = "nvidia,tegra124-i2s";
+			reg = <0x70301400 0x100>;
+			nvidia,ahub-cif-ids = <8 8>;
+			clocks = <&tegra_car TEGRA124_CLK_I2S4>;
+			resets = <&tegra_car 102>;
+			reset-names = "i2s";
+			status = "disabled";
+		};
+	};
+
 	usb@7d000000 {
 		compatible = "nvidia,tegra124-ehci", "nvidia,tegra30-ehci";
 		reg = <0x7d000000 0x4000>;
diff --git a/arch/arm/dts/tegra30-tec-ng.dts b/arch/arm/dts/tegra30-tec-ng.dts
index 8a69e81..e924acc 100644
--- a/arch/arm/dts/tegra30-tec-ng.dts
+++ b/arch/arm/dts/tegra30-tec-ng.dts
@@ -6,6 +6,10 @@
 	model = "Avionic Design Tamonten™ NG Evaluation Carrier";
 	compatible = "ad,tec-ng", "nvidia,tegra30";
 
+	aliases {
+		i2c0 = "/i2c@7000c400";
+	};
+
 	/* GEN2 */
 	i2c@7000c400 {
 		status = "okay";
diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
index 7ca6907..eeeb247 100644
--- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h
+++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
@@ -167,6 +167,6 @@
  *
  * @return number of bus, or -1 if there is no DVC active
  */
-int tegra_i2c_get_dvc_bus_num(void);
+int tegra_i2c_get_dvc_bus(struct udevice **busp);
 
 #endif	/* _TEGRA_I2C_H_ */
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 7614715..11748ae 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -134,6 +134,23 @@
 		num-gpios = <20>;
 	};
 
+	i2c@0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		compatible = "sandbox,i2c";
+		clock-frequency = <400000>;
+		eeprom@2c {
+			reg = <0x2c>;
+			compatible = "i2c-eeprom";
+			emul {
+				compatible = "sandbox,i2c-eeprom";
+				sandbox,filename = "i2c.bin";
+				sandbox,size = <128>;
+			};
+		};
+	};
+
 	spi@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
new file mode 100644
index 0000000..25a0c85
--- /dev/null
+++ b/arch/sandbox/include/asm/test.h
@@ -0,0 +1,26 @@
+/*
+ * Test-related constants for sandbox
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ASM_TEST_H
+#define __ASM_TEST_H
+
+/* The sandbox driver always permits an I2C device with this address */
+#define SANDBOX_I2C_TEST_ADDR	0x59
+
+enum sandbox_i2c_eeprom_test_mode {
+	SIE_TEST_MODE_NONE,
+	/* Permits read/write of only one byte per I2C transaction */
+	SIE_TEST_MODE_SINGLE_BYTE,
+};
+
+void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
+				      enum sandbox_i2c_eeprom_test_mode mode);
+
+void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len);
+
+#endif
diff --git a/board/avionic-design/common/tamonten-ng.c b/board/avionic-design/common/tamonten-ng.c
index 5870b95..86a0844 100644
--- a/board/avionic-design/common/tamonten-ng.c
+++ b/board/avionic-design/common/tamonten-ng.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/gp_padctrl.h>
 #include <asm/arch/gpio.h>
@@ -51,8 +52,15 @@
 
 void pmu_write(uchar reg, uchar data)
 {
-	i2c_set_bus_num(4);	/* PMU is on bus 4 */
-	i2c_write(PMU_I2C_ADDRESS, reg, 1, &data, 1);
+	struct udevice *dev;
+	int ret;
+
+	ret = i2c_get_chip_for_busnum(4, PMU_I2C_ADDRESS, &dev);
+	if (ret) {
+		debug("%s: Cannot find PMIC I2C chip\n", __func__);
+		return;
+	}
+	i2c_write(dev, reg, &data, 1);
 }
 
 /*
diff --git a/board/nvidia/cardhu/cardhu.c b/board/nvidia/cardhu/cardhu.c
index cc0e5e1..026f45c 100644
--- a/board/nvidia/cardhu/cardhu.c
+++ b/board/nvidia/cardhu/cardhu.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/gp_padctrl.h>
 #include "pinmux-config-cardhu.h"
@@ -37,17 +38,23 @@
  */
 void board_sdmmc_voltage_init(void)
 {
+	struct udevice *dev;
 	uchar reg, data_buffer[1];
+	int ret;
 	int i;
 
-	i2c_set_bus_num(0);	/* PMU is on bus 0 */
+	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev);
+	if (ret) {
+		debug("%s: Cannot find PMIC I2C chip\n", __func__);
+		return;
+	}
 
 	/* TPS659110: LDO5_REG = 3.3v, ACTIVE to SDMMC1 */
 	data_buffer[0] = 0x65;
 	reg = 0x32;
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1))
+		if (i2c_write(dev, reg, data_buffer, 1))
 			udelay(100);
 	}
 
@@ -56,7 +63,7 @@
 	reg = 0x67;
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1))
+		if (i2c_write(dev, reg, data_buffer, 1))
 			udelay(100);
 	}
 }
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index 0e4a65a..4bdbf01 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -113,10 +113,6 @@
 	power_det_init();
 
 #ifdef CONFIG_SYS_I2C_TEGRA
-#ifndef CONFIG_SYS_I2C_INIT_BOARD
-#error "You must define CONFIG_SYS_I2C_INIT_BOARD to use i2c on Nvidia boards"
-#endif
-	i2c_init_board();
 # ifdef CONFIG_TEGRA_PMU
 	if (pmu_set_nominal())
 		debug("Failed to select nominal voltages\n");
diff --git a/board/nvidia/dalmore/dalmore.c b/board/nvidia/dalmore/dalmore.c
index f2d05af..2a73746 100644
--- a/board/nvidia/dalmore/dalmore.c
+++ b/board/nvidia/dalmore/dalmore.c
@@ -15,6 +15,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/gp_padctrl.h>
 #include "pinmux-config-dalmore.h"
@@ -50,18 +51,21 @@
  */
 void board_sdmmc_voltage_init(void)
 {
+	struct udevice *dev;
 	uchar reg, data_buffer[1];
 	int ret;
 
-	ret = i2c_set_bus_num(0);/* PMU is on bus 0 */
-	if (ret)
-		printf("%s: i2c_set_bus_num returned %d\n", __func__, ret);
+	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev);
+	if (ret) {
+		debug("%s: Cannot find PMIC I2C chip\n", __func__);
+		return;
+	}
 
 	/* TPS65913: LDO9_VOLTAGE = 3.3V */
 	data_buffer[0] = 0x31;
 	reg = 0x61;
 
-	ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1);
+	ret = i2c_write(dev, reg, data_buffer, 1);
 	if (ret)
 		printf("%s: PMU i2c_write %02X<-%02X returned %d\n",
 			__func__, reg, data_buffer[0], ret);
@@ -70,7 +74,7 @@
 	data_buffer[0] = 0x01;
 	reg = 0x60;
 
-	ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1);
+	ret = i2c_write(dev, reg, data_buffer, 1);
 	if (ret)
 		printf("%s: PMU i2c_write %02X<-%02X returned %d\n",
 			__func__, reg, data_buffer[0], ret);
@@ -79,7 +83,12 @@
 	data_buffer[0] = 0x03;
 	reg = 0x14;
 
-	ret = i2c_write(BAT_I2C_ADDRESS, reg, 1, data_buffer, 1);
+	ret = i2c_get_chip_for_busnum(0, BAT_I2C_ADDRESS, &dev);
+	if (ret) {
+		debug("%s: Cannot find charger I2C chip\n", __func__);
+		return;
+	}
+	ret = i2c_write(dev, reg, data_buffer, 1);
 	if (ret)
 		printf("%s: BAT i2c_write %02X<-%02X returned %d\n",
 			__func__, reg, data_buffer[0], ret);
diff --git a/board/nvidia/nyan-big/Kconfig b/board/nvidia/nyan-big/Kconfig
new file mode 100644
index 0000000..6c42bb9
--- /dev/null
+++ b/board/nvidia/nyan-big/Kconfig
@@ -0,0 +1,24 @@
+if TARGET_NYAN_BIG
+
+config SYS_CPU
+	string
+	default "arm720t" if SPL_BUILD
+	default "armv7" if !SPL_BUILD
+
+config SYS_BOARD
+	string
+	default "nyan-big"
+
+config SYS_VENDOR
+	string
+	default "nvidia"
+
+config SYS_SOC
+	string
+	default "tegra124"
+
+config SYS_CONFIG_NAME
+	string
+	default "nyan-big"
+
+endif
diff --git a/board/nvidia/nyan-big/MAINTAINERS b/board/nvidia/nyan-big/MAINTAINERS
new file mode 100644
index 0000000..ff74627
--- /dev/null
+++ b/board/nvidia/nyan-big/MAINTAINERS
@@ -0,0 +1,6 @@
+NORRIN BOARD
+M:	Allen Martin <amartin@nvidia.com>
+S:	Maintained
+F:	board/nvidia/nyan-big/
+F:	include/configs/nyan-big.h
+F:	configs/nyan-big_defconfig
diff --git a/board/nvidia/nyan-big/Makefile b/board/nvidia/nyan-big/Makefile
new file mode 100644
index 0000000..cd2f61d
--- /dev/null
+++ b/board/nvidia/nyan-big/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2014
+# NVIDIA Corporation <www.nvidia.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y	+= ../venice2/as3722_init.o
+obj-y	+= nyan-big.o
diff --git a/board/nvidia/nyan-big/nyan-big.c b/board/nvidia/nyan-big/nyan-big.c
new file mode 100644
index 0000000..d4d2496
--- /dev/null
+++ b/board/nvidia/nyan-big/nyan-big.c
@@ -0,0 +1,27 @@
+/*
+ * (C) Copyright 2014
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pinmux.h>
+#include "pinmux-config-nyan-big.h"
+
+/*
+ * Routine: pinmux_init
+ * Description: Do individual peripheral pinmux configs
+ */
+void pinmux_init(void)
+{
+	gpio_config_table(nyan_big_gpio_inits,
+			  ARRAY_SIZE(nyan_big_gpio_inits));
+
+	pinmux_config_pingrp_table(nyan_big_pingrps,
+				   ARRAY_SIZE(nyan_big_pingrps));
+
+	pinmux_config_drvgrp_table(nyan_big_drvgrps,
+				   ARRAY_SIZE(nyan_big_drvgrps));
+}
diff --git a/board/nvidia/nyan-big/pinmux-config-nyan-big.h b/board/nvidia/nyan-big/pinmux-config-nyan-big.h
new file mode 100644
index 0000000..9c5fbaa
--- /dev/null
+++ b/board/nvidia/nyan-big/pinmux-config-nyan-big.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _PINMUX_CONFIG_NYAN_BIG_H_
+#define _PINMUX_CONFIG_NYAN_BIG_H_
+
+#define GPIO_INIT(_gpio, _init)				\
+	{						\
+		.gpio	= GPIO_P##_gpio,		\
+		.init	= TEGRA_GPIO_INIT_##_init,	\
+	}
+
+static const struct tegra_gpio_config nyan_big_gpio_inits[] = {
+	/*        gpio, init_val */
+	GPIO_INIT(A0,   IN),
+	GPIO_INIT(C7,   IN),
+	GPIO_INIT(G0,   IN),
+	GPIO_INIT(G1,   IN),
+	GPIO_INIT(G2,   IN),
+	GPIO_INIT(G3,   IN),
+	GPIO_INIT(H2,   IN),
+	GPIO_INIT(H4,   IN),
+	GPIO_INIT(H6,   IN),
+	GPIO_INIT(H7,   OUT1),
+	GPIO_INIT(I0,   IN),
+	GPIO_INIT(I1,   IN),
+	GPIO_INIT(I5,   OUT1),
+	GPIO_INIT(I6,   IN),
+	GPIO_INIT(I7,   IN),
+	GPIO_INIT(J0,   IN),
+	GPIO_INIT(J7,   IN),
+	GPIO_INIT(K1,   OUT0),
+	GPIO_INIT(K2,   IN),
+	GPIO_INIT(K4,   OUT0),
+	GPIO_INIT(K6,   OUT0),
+	GPIO_INIT(K7,   IN),
+	GPIO_INIT(N7,   IN),
+	GPIO_INIT(P2,   OUT0),
+	GPIO_INIT(Q0,   IN),
+	GPIO_INIT(Q2,   IN),
+	GPIO_INIT(Q3,   IN),
+	GPIO_INIT(Q6,   IN),
+	GPIO_INIT(Q7,   IN),
+	GPIO_INIT(R0,   OUT0),
+	GPIO_INIT(R1,   IN),
+	GPIO_INIT(R4,   IN),
+	GPIO_INIT(R7,   IN),
+	GPIO_INIT(S3,   OUT0),
+	GPIO_INIT(S4,   OUT0),
+	GPIO_INIT(S7,   IN),
+	GPIO_INIT(T1,   IN),
+	GPIO_INIT(U4,   IN),
+	GPIO_INIT(U5,   IN),
+	GPIO_INIT(U6,   IN),
+	GPIO_INIT(V0,   IN),
+	GPIO_INIT(W3,   IN),
+	GPIO_INIT(X1,   IN),
+	GPIO_INIT(X4,   IN),
+	GPIO_INIT(X7,   OUT0),
+};
+
+#define PINCFG(_pingrp, _mux, _pull, _tri, _io, _od, _rcv_sel)	\
+	{							\
+		.pingrp		= PMUX_PINGRP_##_pingrp,	\
+		.func		= PMUX_FUNC_##_mux,		\
+		.pull		= PMUX_PULL_##_pull,		\
+		.tristate	= PMUX_TRI_##_tri,		\
+		.io		= PMUX_PIN_##_io,		\
+		.od		= PMUX_PIN_OD_##_od,		\
+		.rcv_sel	= PMUX_PIN_RCV_SEL_##_rcv_sel,	\
+		.lock		= PMUX_PIN_LOCK_DEFAULT,	\
+		.ioreset	= PMUX_PIN_IO_RESET_DEFAULT,	\
+	}
+
+static const struct pmux_pingrp_config nyan_big_pingrps[] = {
+	/*     pingrp,                 mux,         pull,   tri,      e_input, od,      rcv_sel */
+	PINCFG(CLK_32K_OUT_PA0,        DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(UART3_CTS_N_PA1,        GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP2_FS_PA2,            I2S1,        NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(DAP2_SCLK_PA3,          I2S1,        NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(DAP2_DIN_PA4,           I2S1,        NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(DAP2_DOUT_PA5,          I2S1,        NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_CLK_PA6,         SDMMC3,      NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_CMD_PA7,         SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PB0,                    RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PB1,                    RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_DAT3_PB4,        SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_DAT2_PB5,        SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_DAT1_PB6,        SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_DAT0_PB7,        SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(UART3_RTS_N_PC0,        GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(UART2_TXD_PC2,          IRDA,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(UART2_RXD_PC3,          IRDA,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(GEN1_I2C_SCL_PC4,       I2C1,        NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(GEN1_I2C_SDA_PC5,       I2C1,        NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(PC7,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PG0,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PG1,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PG2,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PG3,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PG4,                    SPI4,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PG5,                    SPI4,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PG6,                    SPI4,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PG7,                    SPI4,        NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PH0,                    GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PH1,                    PWM1,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PH2,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PH3,                    GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PH4,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PH5,                    RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PH6,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PH7,                    DEFAULT,     NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PI0,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PI1,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PI2,                    RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PI3,                    SPI4,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PI4,                    GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PI5,                    DEFAULT,     UP,     NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PI6,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PI7,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PJ0,                    DEFAULT,     UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PJ2,                    RSVD1,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(UART2_CTS_N_PJ5,        GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(UART2_RTS_N_PJ6,        GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PJ7,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PK0,                    RSVD1,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PK1,                    DEFAULT,     NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PK2,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PK3,                    GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PK4,                    DEFAULT,     UP,     NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SPDIF_OUT_PK5,          RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SPDIF_IN_PK6,           DEFAULT,     DOWN,   NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PK7,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(DAP1_FS_PN0,            RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP1_DIN_PN1,           RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP1_DOUT_PN2,          I2S0,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP1_SCLK_PN3,          RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(USB_VBUS_EN0_PN4,       USB,         NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(USB_VBUS_EN1_PN5,       USB,         NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(HDMI_INT_PN7,           DEFAULT,     DOWN,   NORMAL,   INPUT,   DEFAULT, NORMAL),
+	PINCFG(ULPI_DATA7_PO0,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DATA0_PO1,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DATA1_PO2,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DATA2_PO3,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DATA3_PO4,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DATA4_PO5,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DATA5_PO6,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DATA6_PO7,         ULPI,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP3_FS_PP0,            I2S2,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP3_DIN_PP1,           I2S2,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP3_DOUT_PP2,          DEFAULT,     NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP3_SCLK_PP3,          RSVD3,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP4_FS_PP4,            RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP4_DIN_PP5,           RSVD3,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP4_DOUT_PP6,          RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP4_SCLK_PP7,          RSVD3,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_COL0_PQ0,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_COL1_PQ1,            RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_COL2_PQ2,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_COL3_PQ3,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_COL4_PQ4,            SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_COL5_PQ5,            RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_COL6_PQ6,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_COL7_PQ7,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_ROW0_PR0,            DEFAULT,     NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW1_PR1,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_ROW2_PR2,            RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW3_PR3,            KBC,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW4_PR4,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_ROW5_PR5,            RSVD3,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW6_PR6,            KBC,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW7_PR7,            DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_ROW8_PS0,            RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW9_PS1,            UARTA,       DOWN,   NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW10_PS2,           UARTA,       NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_ROW11_PS3,           DEFAULT,     NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW12_PS4,           DEFAULT,     NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW13_PS5,           RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW14_PS6,           RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW15_PS7,           DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(KB_ROW16_PT0,           RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(KB_ROW17_PT1,           DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(GEN2_I2C_SCL_PT5,       I2C2,        NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(GEN2_I2C_SDA_PT6,       I2C2,        NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(SDMMC4_CMD_PT7,         SDMMC4,      NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PU0,                    RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PU1,                    RSVD1,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PU2,                    RSVD1,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PU3,                    GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PU4,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PU5,                    DEFAULT,     UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PU6,                    DEFAULT,     UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PV0,                    DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PV1,                    RSVD1,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_CD_N_PV2,        SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC1_WP_N_PV3,        SDMMC1,      DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DDC_SCL_PV4,            I2C4,        NORMAL, NORMAL,   INPUT,   DEFAULT, NORMAL),
+	PINCFG(DDC_SDA_PV5,            I2C4,        NORMAL, NORMAL,   INPUT,   DEFAULT, NORMAL),
+	PINCFG(GPIO_W2_AUD_PW2,        RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(GPIO_W3_AUD_PW3,        DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(DAP_MCLK1_PW4,          EXTPERIPH1,  NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(CLK2_OUT_PW5,           RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(UART3_TXD_PW6,          RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(UART3_RXD_PW7,          RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DVFS_PWM_PX0,           CLDVFS,      NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(GPIO_X1_AUD_PX1,        DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(DVFS_CLK_PX2,           CLDVFS,      NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(GPIO_X3_AUD_PX3,        RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(GPIO_X4_AUD_PX4,        DEFAULT,     NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(GPIO_X5_AUD_PX5,        RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(GPIO_X6_AUD_PX6,        GMI,         DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(GPIO_X7_AUD_PX7,        DEFAULT,     NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_CLK_PY0,           SPI1,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_DIR_PY1,           SPI1,        NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(ULPI_NXT_PY2,           SPI1,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(ULPI_STP_PY3,           SPI1,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SDMMC1_DAT3_PY4,        SDMMC1,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC1_DAT2_PY5,        SDMMC1,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC1_DAT1_PY6,        SDMMC1,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC1_DAT0_PY7,        SDMMC1,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC1_CLK_PZ0,         SDMMC1,      NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC1_CMD_PZ1,         SDMMC1,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PWR_I2C_SCL_PZ6,        I2CPWR,      NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(PWR_I2C_SDA_PZ7,        I2CPWR,      NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(SDMMC4_DAT0_PAA0,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_DAT1_PAA1,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_DAT2_PAA2,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_DAT3_PAA3,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_DAT4_PAA4,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_DAT5_PAA5,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_DAT6_PAA6,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_DAT7_PAA7,       SDMMC4,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(PBB0,                   VGP6,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(CAM_I2C_SCL_PBB1,       RSVD3,       DOWN,   TRISTATE, OUTPUT,  DISABLE, DEFAULT),
+	PINCFG(CAM_I2C_SDA_PBB2,       RSVD3,       DOWN,   TRISTATE, OUTPUT,  DISABLE, DEFAULT),
+	PINCFG(PBB3,                   VGP3,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PBB4,                   VGP4,        DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PBB5,                   RSVD3,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PBB6,                   RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PBB7,                   RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(CAM_MCLK_PCC0,          VI,          DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PCC1,                   RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PCC2,                   RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SDMMC4_CLK_PCC4,        SDMMC4,      NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(CLK2_REQ_PCC5,          RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PEX_L0_RST_N_PDD1,      RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PEX_L0_CLKREQ_N_PDD2,   RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PEX_WAKE_N_PDD3,        RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PEX_L1_RST_N_PDD5,      RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PEX_L1_CLKREQ_N_PDD6,   RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(CLK3_OUT_PEE0,          RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(CLK3_REQ_PEE1,          RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(DAP_MCLK1_REQ_PEE2,     RSVD4,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(HDMI_CEC_PEE3,          CEC,         NORMAL, NORMAL,   INPUT,   ENABLE,  DEFAULT),
+	PINCFG(SDMMC3_CLK_LB_OUT_PEE4, SDMMC3,      NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(SDMMC3_CLK_LB_IN_PEE5,  SDMMC3,      UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(DP_HPD_PFF0,            DP,          UP,     NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(USB_VBUS_EN2_PFF1,      RSVD2,       DOWN,   TRISTATE, OUTPUT,  DISABLE, DEFAULT),
+	PINCFG(PFF2,                   RSVD2,       DOWN,   TRISTATE, OUTPUT,  DISABLE, DEFAULT),
+	PINCFG(CORE_PWR_REQ,           PWRON,       NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(CPU_PWR_REQ,            CPU,         NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(PWR_INT_N,              PMI,         NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(RESET_OUT_N,            RESET_OUT_N, NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+	PINCFG(OWR,                    RSVD2,       DOWN,   TRISTATE, OUTPUT,  DEFAULT, NORMAL),
+	PINCFG(CLK_32K_IN,             CLK,         NORMAL, NORMAL,   INPUT,   DEFAULT, DEFAULT),
+	PINCFG(JTAG_RTCK,              RTCK,        NORMAL, NORMAL,   OUTPUT,  DEFAULT, DEFAULT),
+};
+
+#define DRVCFG(_drvgrp, _slwf, _slwr, _drvup, _drvdn, _lpmd, _schmt, _hsm) \
+	{						\
+		.drvgrp = PMUX_DRVGRP_##_drvgrp,	\
+		.slwf   = _slwf,			\
+		.slwr   = _slwr,			\
+		.drvup  = _drvup,			\
+		.drvdn  = _drvdn,			\
+		.lpmd   = PMUX_LPMD_##_lpmd,		\
+		.schmt  = PMUX_SCHMT_##_schmt,		\
+		.hsm    = PMUX_HSM_##_hsm,		\
+	}
+
+static const struct pmux_drvgrp_config nyan_big_drvgrps[] = {
+};
+
+#endif /* PINMUX_CONFIG_NYAN_BIG_H */
diff --git a/board/nvidia/venice2/as3722_init.h b/board/nvidia/venice2/as3722_init.h
index 06c366e..992b11f 100644
--- a/board/nvidia/venice2/as3722_init.h
+++ b/board/nvidia/venice2/as3722_init.h
@@ -18,7 +18,7 @@
 #define AS3722_LDO6VOLTAGE_REG	0x16	/* VDD_SDMMC */
 #define AS3722_LDCONTROL_REG	0x4E
 
-#ifdef CONFIG_TARGET_JETSON_TK1
+#if defined(CONFIG_TARGET_JETSON_TK1) || defined(CONFIG_TARGET_NYAN_BIG)
 #define AS3722_SD0VOLTAGE_DATA	(0x3C00 | AS3722_SD0VOLTAGE_REG)
 #else
 #define AS3722_SD0VOLTAGE_DATA	(0x2800 | AS3722_SD0VOLTAGE_REG)
diff --git a/board/nvidia/whistler/whistler.c b/board/nvidia/whistler/whistler.c
index 3e9d3d9..3114b20 100644
--- a/board/nvidia/whistler/whistler.c
+++ b/board/nvidia/whistler/whistler.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/io.h>
 #include <asm/arch/tegra.h>
 #include <asm/arch/clock.h>
@@ -21,23 +22,26 @@
  */
 void pin_mux_mmc(void)
 {
+	struct udevice *dev;
 	uchar val;
 	int ret;
 
 	/* Turn on MAX8907B LDO12 to 2.8V for J40 power */
-	ret = i2c_set_bus_num(0);
-	if (ret)
-		printf("i2c_set_bus_num failed: %d\n", ret);
+	ret = i2c_get_chip_for_busnum(0, 0x3c, &dev);
+	if (ret) {
+		printf("%s: Cannot find MAX8907B I2C chip\n", __func__);
+		return;
+	}
 	val = 0x29;
-	ret = i2c_write(0x3c, 0x46, 1, &val, 1);
+	ret = i2c_write(dev, 0x46, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x3c 0x46 failed: %d\n", ret);
 	val = 0x00;
-	ret = i2c_write(0x3c, 0x45, 1, &val, 1);
+	ret = i2c_write(dev, 0x45, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x3c 0x45 failed: %d\n", ret);
 	val = 0x1f;
-	ret = i2c_write(0x3c, 0x44, 1, &val, 1);
+	ret = i2c_write(dev, 0x44, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x3c 0x44 failed: %d\n", ret);
 
@@ -49,6 +53,7 @@
 /* this is a weak define that we are overriding */
 void pin_mux_usb(void)
 {
+	struct udevice *dev;
 	uchar val;
 	int ret;
 
@@ -59,15 +64,17 @@
 	 */
 
 	/* Turn on TAC6416's GPIO 0+1 for USB1/3's VBUS */
-	ret = i2c_set_bus_num(0);
-	if (ret)
-		printf("i2c_set_bus_num failed: %d\n", ret);
+	ret = i2c_get_chip_for_busnum(0, 0x20, &dev);
+	if (ret) {
+		printf("%s: Cannot find TAC6416 I2C chip\n", __func__);
+		return;
+	}
 	val = 0x03;
-	ret = i2c_write(0x20, 2, 1, &val, 1);
+	ret = i2c_write(dev, 2, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x20 2 failed: %d\n", ret);
 	val = 0xfc;
-	ret = i2c_write(0x20, 6, 1, &val, 1);
+	ret = i2c_write(dev, 6, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x20 6 failed: %d\n", ret);
 }
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 51a4fa1..7dbd40e 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -24,6 +24,7 @@
 #include <asm/arch/mbox.h>
 #include <asm/arch/sdhci.h>
 #include <asm/global_data.h>
+#include <dm/platform_data/serial_pl01x.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -36,6 +37,17 @@
 	.platdata = &gpio_platdata,
 };
 
+static const struct pl01x_serial_platdata serial_platdata = {
+	.base = 0x20201000,
+	.type = TYPE_PL011,
+	.clock = 3000000,
+};
+
+U_BOOT_DEVICE(bcm2835_serials) = {
+	.name = "serial_pl01x",
+	.platdata = &serial_platdata,
+};
+
 struct msg_get_arm_mem {
 	struct bcm2835_mbox_hdr hdr;
 	struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
diff --git a/board/toradex/apalis_t30/apalis_t30.c b/board/toradex/apalis_t30/apalis_t30.c
index b9d694a..5d2c024 100644
--- a/board/toradex/apalis_t30/apalis_t30.c
+++ b/board/toradex/apalis_t30/apalis_t30.c
@@ -6,7 +6,7 @@
  */
 
 #include <common.h>
-
+#include <dm.h>
 #include <asm/arch/gp_padctrl.h>
 #include <asm/arch/pinmux.h>
 #include <asm/gpio.h>
@@ -38,23 +38,20 @@
 #ifdef CONFIG_PCI_TEGRA
 int tegra_pcie_board_init(void)
 {
-	unsigned int old_bus;
+	struct udevice *dev;
 	u8 addr, data[1];
 	int err;
 
-	old_bus = i2c_get_bus_num();
-
-	err = i2c_set_bus_num(0);
+	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev);
 	if (err) {
-		debug("failed to set I2C bus\n");
+		debug("%s: Cannot find PMIC I2C chip\n", __func__);
 		return err;
 	}
-
 	/* TPS659110: VDD2_OP_REG = 1.05V */
 	data[0] = 0x27;
 	addr = 0x25;
 
-	err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1);
+	err = i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to set VDD supply\n");
 		return err;
@@ -64,7 +61,7 @@
 	data[0] = 0x0D;
 	addr = 0x24;
 
-	err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1);
+	err = i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to enable VDD supply\n");
 		return err;
@@ -74,14 +71,12 @@
 	data[0] = 0x0D;
 	addr = 0x35;
 
-	err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1);
+	err = i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to set AVDD supply\n");
 		return err;
 	}
 
-	i2c_set_bus_num(old_bus);
-
 	return 0;
 }
 
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index c266b88..22db1bb 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -69,8 +69,10 @@
 #include <bootretry.h>
 #include <cli.h>
 #include <command.h>
+#include <dm.h>
 #include <edid.h>
 #include <environment.h>
+#include <errno.h>
 #include <i2c.h>
 #include <malloc.h>
 #include <asm/byteorder.h>
@@ -117,6 +119,60 @@
 
 #define DISP_LINE_LEN	16
 
+/*
+ * Default for driver model is to use the chip's existing address length.
+ * For legacy code, this is not stored, so we need to use a suitable
+ * default.
+ */
+#ifdef CONFIG_DM_I2C
+#define DEFAULT_ADDR_LEN	(-1)
+#else
+#define DEFAULT_ADDR_LEN	1
+#endif
+
+#ifdef CONFIG_DM_I2C
+static struct udevice *i2c_cur_bus;
+
+static int i2c_set_bus_num(unsigned int busnum)
+{
+	struct udevice *bus;
+	int ret;
+
+	ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
+	if (ret) {
+		debug("%s: No bus %d\n", __func__, busnum);
+		return ret;
+	}
+	i2c_cur_bus = bus;
+
+	return 0;
+}
+
+static int i2c_get_cur_bus(struct udevice **busp)
+{
+	if (!i2c_cur_bus) {
+		puts("No I2C bus selected\n");
+		return -ENODEV;
+	}
+	*busp = i2c_cur_bus;
+
+	return 0;
+}
+
+static int i2c_get_cur_bus_chip(uint chip_addr, struct udevice **devp)
+{
+	struct udevice *bus;
+	int ret;
+
+	ret = i2c_get_cur_bus(&bus);
+	if (ret)
+		return ret;
+
+	return i2c_get_chip(bus, chip_addr, devp);
+}
+
+#endif
+
 /**
  * i2c_init_board() - Board-specific I2C bus init
  *
@@ -143,7 +199,7 @@
  *
  * Returns I2C bus speed in Hz.
  */
-#if !defined(CONFIG_SYS_I2C)
+#if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_DM_I2C)
 /*
  * TODO: Implement architecture-specific get/set functions
  * Should go away, if we switched completely to new multibus support
@@ -182,12 +238,12 @@
  *
  * Returns the address length.
  */
-static uint get_alen(char *arg)
+static uint get_alen(char *arg, int default_len)
 {
 	int	j;
 	int	alen;
 
-	alen = 1;
+	alen = default_len;
 	for (j = 0; j < 8; j++) {
 		if (arg[j] == '.') {
 			alen = arg[j+1] - '0';
@@ -227,8 +283,13 @@
 static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	u_char	chip;
-	uint	devaddr, alen, length;
+	uint	devaddr, length;
+	int alen;
 	u_char  *memaddr;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc != 5)
 		return CMD_RET_USAGE;
@@ -243,7 +304,7 @@
 	 * 2 bytes long.  Some day it might be 3 bytes long :-).
 	 */
 	devaddr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
 
@@ -257,18 +318,31 @@
 	 */
 	memaddr = (u_char *)simple_strtoul(argv[4], NULL, 16);
 
-	if (i2c_read(chip, devaddr, alen, memaddr, length) != 0) {
-		i2c_report_err(-1, I2C_ERR_READ);
-		return 1;
-	}
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_chip_offset_len(dev, alen);
+	if (!ret)
+		ret = i2c_read(dev, devaddr, memaddr, length);
+#else
+	ret = i2c_read(chip, devaddr, alen, memaddr, length);
+#endif
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+
 	return 0;
 }
 
 static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	u_char	chip;
-	uint	devaddr, alen, length;
+	uint	devaddr, length;
+	int alen;
 	u_char  *memaddr;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc != 5)
 		return cmd_usage(cmdtp);
@@ -288,7 +362,7 @@
 	 * 2 bytes long.  Some day it might be 3 bytes long :-).
 	 */
 	devaddr = simple_strtoul(argv[3], NULL, 16);
-	alen = get_alen(argv[3]);
+	alen = get_alen(argv[3], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return cmd_usage(cmdtp);
 
@@ -297,10 +371,22 @@
 	 */
 	length = simple_strtoul(argv[4], NULL, 16);
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_chip_offset_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
+
 	while (length-- > 0) {
-		if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) {
-			return i2c_report_err(-1, I2C_ERR_WRITE);
-		}
+#ifdef CONFIG_DM_I2C
+		ret = i2c_write(dev, devaddr++, memaddr++, 1);
+#else
+		ret = i2c_write(chip, devaddr++, alen, memaddr++, 1);
+#endif
+		if (ret)
+			return i2c_report_err(ret, I2C_ERR_WRITE);
 /*
  * No write delay with FRAM devices.
  */
@@ -311,6 +397,38 @@
 	return 0;
 }
 
+#ifdef CONFIG_DM_I2C
+static int do_i2c_flags(cmd_tbl_t *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	struct udevice *dev;
+	uint flags;
+	int chip;
+	int ret;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	chip = simple_strtoul(argv[1], NULL, 16);
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+
+	if (argc > 2) {
+		flags = simple_strtoul(argv[2], NULL, 16);
+		ret = i2c_set_chip_flags(dev, flags);
+	} else  {
+		ret = i2c_get_chip_flags(dev, &flags);
+		if (!ret)
+			printf("%x\n", flags);
+	}
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+
+	return 0;
+}
+#endif
+
 /**
  * do_i2c_md() - Handle the "i2c md" command-line command
  * @cmdtp:	Command data struct pointer
@@ -327,8 +445,13 @@
 static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	u_char	chip;
-	uint	addr, alen, length;
+	uint	addr, length;
+	int alen;
 	int	j, nbytes, linebytes;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	/* We use the last specified parameters, unless new ones are
 	 * entered.
@@ -356,7 +479,7 @@
 		 * 2 bytes long.  Some day it might be 3 bytes long :-).
 		 */
 		addr = simple_strtoul(argv[2], NULL, 16);
-		alen = get_alen(argv[2]);
+		alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 		if (alen > 3)
 			return CMD_RET_USAGE;
 
@@ -368,6 +491,14 @@
 			length = simple_strtoul(argv[3], NULL, 16);
 	}
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_chip_offset_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+#endif
+
 	/*
 	 * Print the lines.
 	 *
@@ -381,8 +512,13 @@
 
 		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
 
-		if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0)
-			i2c_report_err(-1, I2C_ERR_READ);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, linebuf, linebytes);
+#else
+		ret = i2c_read(chip, addr, alen, linebuf, linebytes);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_READ);
 		else {
 			printf("%04x:", addr);
 			cp = linebuf;
@@ -429,9 +565,13 @@
 {
 	uchar	chip;
 	ulong	addr;
-	uint	alen;
+	int	alen;
 	uchar	byte;
 	int	count;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if ((argc < 4) || (argc > 5))
 		return CMD_RET_USAGE;
@@ -445,10 +585,17 @@
 	 * Address is always specified.
 	 */
 	addr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_chip_offset_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
 	/*
 	 * Value to write is always specified.
 	 */
@@ -463,8 +610,13 @@
 		count = 1;
 
 	while (count-- > 0) {
-		if (i2c_write(chip, addr++, alen, &byte, 1) != 0)
-			i2c_report_err(-1, I2C_ERR_WRITE);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_write(dev, addr++, &byte, 1);
+#else
+		ret = i2c_write(chip, addr++, alen, &byte, 1);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_WRITE);
 		/*
 		 * Wait for the write to complete.  The write can take
 		 * up to 10mSec (we allow a little more time).
@@ -499,11 +651,15 @@
 {
 	uchar	chip;
 	ulong	addr;
-	uint	alen;
+	int	alen;
 	int	count;
 	uchar	byte;
 	ulong	crc;
 	ulong	err;
+	int ret = 0;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc < 4)
 		return CMD_RET_USAGE;
@@ -517,10 +673,17 @@
 	 * Address is always specified.
 	 */
 	addr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_chip_offset_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+#endif
 	/*
 	 * Count is always specified
 	 */
@@ -534,13 +697,18 @@
 	crc = 0;
 	err = 0;
 	while (count-- > 0) {
-		if (i2c_read(chip, addr, alen, &byte, 1) != 0)
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, &byte, 1);
+#else
+		ret = i2c_read(chip, addr, alen, &byte, 1);
+#endif
+		if (ret)
 			err++;
 		crc = crc32 (crc, &byte, 1);
 		addr++;
 	}
 	if (err > 0)
-		i2c_report_err(-1, I2C_ERR_READ);
+		i2c_report_err(ret, I2C_ERR_READ);
 	else
 		printf ("%08lx\n", crc);
 
@@ -568,10 +736,14 @@
 {
 	uchar	chip;
 	ulong	addr;
-	uint	alen;
+	int	alen;
 	ulong	data;
 	int	size = 1;
 	int	nbytes;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc != 3)
 		return CMD_RET_USAGE;
@@ -601,19 +773,32 @@
 		 * Address is always specified.
 		 */
 		addr = simple_strtoul(argv[2], NULL, 16);
-		alen = get_alen(argv[2]);
+		alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 		if (alen > 3)
 			return CMD_RET_USAGE;
 	}
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_chip_offset_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
+
 	/*
 	 * Print the address, followed by value.  Then accept input for
 	 * the next value.  A non-converted value exits.
 	 */
 	do {
 		printf("%08lx:", addr);
-		if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0)
-			i2c_report_err(-1, I2C_ERR_READ);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, (uchar *)&data, size);
+#else
+		ret = i2c_read(chip, addr, alen, (uchar *)&data, size);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_READ);
 		else {
 			data = cpu_to_be32(data);
 			if (size == 1)
@@ -655,8 +840,15 @@
 				 * good enough to not time out
 				 */
 				bootretry_reset_cmd_timeout();
-				if (i2c_write(chip, addr, alen, (uchar *)&data, size) != 0)
-					i2c_report_err(-1, I2C_ERR_WRITE);
+#ifdef CONFIG_DM_I2C
+				ret = i2c_write(dev, addr, (uchar *)&data,
+						size);
+#else
+				ret = i2c_write(chip, addr, alen,
+						(uchar *)&data, size);
+#endif
+				if (ret)
+					i2c_report_err(ret, I2C_ERR_WRITE);
 #ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
 				udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
 #endif
@@ -697,6 +889,13 @@
 	int k, skip;
 	unsigned int bus = GET_BUS_NUM;
 #endif	/* NOPROBES */
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *bus, *dev;
+
+	if (i2c_get_cur_bus(&bus))
+		return CMD_RET_FAILURE;
+#endif
 
 	if (argc == 2)
 		addr = simple_strtol(argv[1], 0, 16);
@@ -717,7 +916,12 @@
 		if (skip)
 			continue;
 #endif
-		if (i2c_probe(j) == 0) {
+#ifdef CONFIG_DM_I2C
+		ret = i2c_probe(bus, j, 0, &dev);
+#else
+		ret = i2c_probe(j);
+#endif
+		if (ret == 0) {
 			printf(" %02X", j);
 			found++;
 		}
@@ -754,11 +958,15 @@
 static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	u_char	chip;
-	ulong	alen;
+	int alen;
 	uint	addr;
 	uint	length;
 	u_char	bytes[16];
 	int	delay;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc < 3)
 		return CMD_RET_USAGE;
@@ -772,9 +980,16 @@
 	 * Address is always specified.
 	 */
 	addr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_chip_offset_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
 
 	/*
 	 * Length is the number of objects, not number of bytes.
@@ -794,8 +1009,13 @@
 	 * Run the loop...
 	 */
 	while (1) {
-		if (i2c_read(chip, addr, alen, bytes, length) != 0)
-			i2c_report_err(-1, I2C_ERR_READ);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, bytes, length);
+#else
+		ret = i2c_read(chip, addr, alen, bytes, length);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_READ);
 		udelay(delay);
 	}
 
@@ -1345,6 +1565,10 @@
 {
 	u_char chip;
 	struct edid1_info edid;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc < 2) {
 		cmd_usage(cmdtp);
@@ -1352,10 +1576,15 @@
 	}
 
 	chip = simple_strtoul(argv[1], NULL, 16);
-	if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) {
-		i2c_report_err(-1, I2C_ERR_READ);
-		return 1;
-	}
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret)
+		ret = i2c_read(dev, 0, (uchar *)&edid, sizeof(edid));
+#else
+	ret = i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid));
+#endif
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
 
 	if (edid_check_info(&edid)) {
 		puts("Content isn't valid EDID.\n");
@@ -1437,17 +1666,28 @@
  * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
  * on error.
  */
-#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS)
+#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) || \
+		defined(CONFIG_DM_I2C)
 static int do_i2c_bus_num(cmd_tbl_t *cmdtp, int flag, int argc,
 				char * const argv[])
 {
 	int		ret = 0;
-	unsigned int	bus_no;
+	int	bus_no;
 
-	if (argc == 1)
+	if (argc == 1) {
 		/* querying current setting */
-		printf("Current bus is %d\n", i2c_get_bus_num());
-	else {
+#ifdef CONFIG_DM_I2C
+		struct udevice *bus;
+
+		if (!i2c_get_cur_bus(&bus))
+			bus_no = bus->seq;
+		else
+			bus_no = -1;
+#else
+		bus_no = i2c_get_bus_num();
+#endif
+		printf("Current bus is %d\n", bus_no);
+	} else {
 		bus_no = simple_strtoul(argv[1], NULL, 10);
 #if defined(CONFIG_SYS_I2C)
 		if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES) {
@@ -1478,13 +1718,28 @@
 {
 	int speed, ret=0;
 
-	if (argc == 1)
+#ifdef CONFIG_DM_I2C
+	struct udevice *bus;
+
+	if (i2c_get_cur_bus(&bus))
+		return 1;
+#endif
+	if (argc == 1) {
+#ifdef CONFIG_DM_I2C
+		speed = i2c_get_bus_speed(bus);
+#else
+		speed = i2c_get_bus_speed();
+#endif
 		/* querying current speed */
-		printf("Current bus speed=%d\n", i2c_get_bus_speed());
-	else {
+		printf("Current bus speed=%d\n", speed);
+	} else {
 		speed = simple_strtoul(argv[1], NULL, 10);
 		printf("Setting bus speed to %d Hz\n", speed);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_set_bus_speed(bus, speed);
+#else
 		ret = i2c_set_bus_speed(speed);
+#endif
 		if (ret)
 			printf("Failure changing bus speed (%d)\n", ret);
 	}
@@ -1532,7 +1787,16 @@
  */
 static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
-#if defined(CONFIG_SYS_I2C)
+#if defined(CONFIG_DM_I2C)
+	struct udevice *bus;
+
+	if (i2c_get_cur_bus(&bus))
+		return CMD_RET_FAILURE;
+	if (i2c_deblock(bus)) {
+		printf("Error: Not supported by the driver\n");
+		return CMD_RET_FAILURE;
+	}
+#elif defined(CONFIG_SYS_I2C)
 	i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr);
 #else
 	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
@@ -1546,7 +1810,7 @@
 #endif
 	U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""),
 #if defined(CONFIG_SYS_I2C) || \
-	defined(CONFIG_I2C_MULTI_BUS)
+	defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C)
 	U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),
 #endif  /* CONFIG_I2C_MULTI_BUS */
 #if defined(CONFIG_I2C_EDID)
@@ -1560,6 +1824,9 @@
 	U_BOOT_CMD_MKENT(probe, 0, 1, do_i2c_probe, "", ""),
 	U_BOOT_CMD_MKENT(read, 5, 1, do_i2c_read, "", ""),
 	U_BOOT_CMD_MKENT(write, 5, 0, do_i2c_write, "", ""),
+#ifdef CONFIG_DM_I2C
+	U_BOOT_CMD_MKENT(flags, 2, 1, do_i2c_flags, "", ""),
+#endif
 	U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""),
 #if defined(CONFIG_CMD_SDRAM)
 	U_BOOT_CMD_MKENT(sdram, 1, 1, do_sdram, "", ""),
@@ -1610,7 +1877,7 @@
 #endif
 	"crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n"
 #if defined(CONFIG_SYS_I2C) || \
-	defined(CONFIG_I2C_MULTI_BUS)
+	defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C)
 	"i2c dev [dev] - show or set current I2C bus\n"
 #endif  /* CONFIG_I2C_MULTI_BUS */
 #if defined(CONFIG_I2C_EDID)
@@ -1622,8 +1889,11 @@
 	"i2c mw chip address[.0, .1, .2] value [count] - write to I2C device (fill)\n"
 	"i2c nm chip address[.0, .1, .2] - write to I2C device (constant address)\n"
 	"i2c probe [address] - test for and show device(s) on the I2C bus\n"
-	"i2c read chip address[.0, .1, .2] length memaddress - read to memory \n"
+	"i2c read chip address[.0, .1, .2] length memaddress - read to memory\n"
 	"i2c write memaddress chip address[.0, .1, .2] length - write memory to i2c\n"
+#ifdef CONFIG_DM_I2C
+	"i2c flags chip [flags] - set or get chip flags\n"
+#endif
 	"i2c reset - re-init the I2C Controller\n"
 #if defined(CONFIG_CMD_SDRAM)
 	"i2c sdram chip - print SDRAM configuration information\n"
diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig
new file mode 100644
index 0000000..ec79b5b
--- /dev/null
+++ b/configs/nyan-big_defconfig
@@ -0,0 +1,5 @@
++S:CONFIG_ARM=y
++S:CONFIG_TEGRA=y
++S:CONFIG_TEGRA124=y
++S:CONFIG_TARGET_NYAN_BIG=y
+CONFIG_DEFAULT_DEVICE_TREE="tegra124-nyan-big"
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 6793e1c..963b16f 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -234,7 +234,7 @@
 void *dev_get_platdata(struct udevice *dev)
 {
 	if (!dev) {
-		dm_warn("%s: null device", __func__);
+		dm_warn("%s: null device\n", __func__);
 		return NULL;
 	}
 
@@ -244,7 +244,7 @@
 void *dev_get_priv(struct udevice *dev)
 {
 	if (!dev) {
-		dm_warn("%s: null device", __func__);
+		dm_warn("%s: null device\n", __func__);
 		return NULL;
 	}
 
@@ -254,7 +254,7 @@
 void *dev_get_parentdata(struct udevice *dev)
 {
 	if (!dev) {
-		dm_warn("%s: null device", __func__);
+		dm_warn("%s: null device\n", __func__);
 		return NULL;
 	}
 
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index dae3d71..6f3c86c 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -4,6 +4,7 @@
 #
 # SPDX-License-Identifier:	GPL-2.0+
 #
+obj-$(CONFIG_DM_I2C) += i2c-uclass.o
 
 obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
 obj-$(CONFIG_I2C_MV) += mv_i2c.o
@@ -26,6 +27,7 @@
 obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
 obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o
+obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
 obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
 obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
 obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c
new file mode 100644
index 0000000..aa89f95
--- /dev/null
+++ b/drivers/i2c/i2c-emul-uclass.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+
+UCLASS_DRIVER(i2c_emul) = {
+	.id		= UCLASS_I2C_EMUL,
+	.name		= "i2c_emul",
+};
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
new file mode 100644
index 0000000..005bf86
--- /dev/null
+++ b/drivers/i2c/i2c-uclass.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define I2C_MAX_OFFSET_LEN	4
+
+/**
+ * i2c_setup_offset() - Set up a new message with a chip offset
+ *
+ * @chip:	Chip to use
+ * @offset:	Byte offset within chip
+ * @offset_buf:	Place to put byte offset
+ * @msg:	Message buffer
+ * @return 0 if OK, -EADDRNOTAVAIL if the offset length is 0. In that case the
+ * message is still set up but will not contain an offset.
+ */
+static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
+			    uint8_t offset_buf[], struct i2c_msg *msg)
+{
+	int offset_len;
+
+	msg->addr = chip->chip_addr;
+	msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+	msg->len = chip->offset_len;
+	msg->buf = offset_buf;
+	if (!chip->offset_len)
+		return -EADDRNOTAVAIL;
+	assert(chip->offset_len <= I2C_MAX_OFFSET_LEN);
+	offset_len = chip->offset_len;
+	while (offset_len--)
+		*offset_buf++ = offset >> (8 * offset_len);
+
+	return 0;
+}
+
+static int i2c_read_bytewise(struct udevice *dev, uint offset,
+			     uint8_t *buffer, int len)
+{
+	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct udevice *bus = dev_get_parent(dev);
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct i2c_msg msg[2], *ptr;
+	uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+	int ret;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
+			return -EINVAL;
+		ptr = msg + 1;
+		ptr->addr = chip->chip_addr;
+		ptr->flags = msg->flags | I2C_M_RD;
+		ptr->len = 1;
+		ptr->buf = &buffer[i];
+		ptr++;
+
+		ret = ops->xfer(bus, msg, ptr - msg);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int i2c_write_bytewise(struct udevice *dev, uint offset,
+			     const uint8_t *buffer, int len)
+{
+	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct udevice *bus = dev_get_parent(dev);
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct i2c_msg msg[1];
+	uint8_t buf[I2C_MAX_OFFSET_LEN + 1];
+	int ret;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (i2c_setup_offset(chip, offset + i, buf, msg))
+			return -EINVAL;
+		buf[msg->len++] = buffer[i];
+
+		ret = ops->xfer(bus, msg, 1);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
+{
+	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct udevice *bus = dev_get_parent(dev);
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct i2c_msg msg[2], *ptr;
+	uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+	int msg_count;
+
+	if (!ops->xfer)
+		return -ENOSYS;
+	if (chip->flags & DM_I2C_CHIP_RD_ADDRESS)
+		return i2c_read_bytewise(dev, offset, buffer, len);
+	ptr = msg;
+	if (!i2c_setup_offset(chip, offset, offset_buf, ptr))
+		ptr++;
+
+	if (len) {
+		ptr->addr = chip->chip_addr;
+		ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+		ptr->flags |= I2C_M_RD;
+		ptr->len = len;
+		ptr->buf = buffer;
+		ptr++;
+	}
+	msg_count = ptr - msg;
+
+	return ops->xfer(bus, msg, msg_count);
+}
+
+int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
+{
+	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct udevice *bus = dev_get_parent(dev);
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct i2c_msg msg[1];
+
+	if (!ops->xfer)
+		return -ENOSYS;
+
+	if (chip->flags & DM_I2C_CHIP_WR_ADDRESS)
+		return i2c_write_bytewise(dev, offset, buffer, len);
+	/*
+	 * The simple approach would be to send two messages here: one to
+	 * set the offset and one to write the bytes. However some drivers
+	 * will not be expecting this, and some chips won't like how the
+	 * driver presents this on the I2C bus.
+	 *
+	 * The API does not support separate offset and data. We could extend
+	 * it with a flag indicating that there is data in the next message
+	 * that needs to be processed in the same transaction. We could
+	 * instead add an additional buffer to each message. For now, handle
+	 * this in the uclass since it isn't clear what the impact on drivers
+	 * would be with this extra complication. Unfortunately this means
+	 * copying the message.
+	 *
+	 * Use the stack for small messages, malloc() for larger ones. We
+	 * need to allow space for the offset (up to 4 bytes) and the message
+	 * itself.
+	 */
+	if (len < 64) {
+		uint8_t buf[I2C_MAX_OFFSET_LEN + len];
+
+		i2c_setup_offset(chip, offset, buf, msg);
+		msg->len += len;
+		memcpy(buf + chip->offset_len, buffer, len);
+
+		return ops->xfer(bus, msg, 1);
+	} else {
+		uint8_t *buf;
+		int ret;
+
+		buf = malloc(I2C_MAX_OFFSET_LEN + len);
+		if (!buf)
+			return -ENOMEM;
+		i2c_setup_offset(chip, offset, buf, msg);
+		msg->len += len;
+		memcpy(buf + chip->offset_len, buffer, len);
+
+		ret = ops->xfer(bus, msg, 1);
+		free(buf);
+		return ret;
+	}
+}
+
+/**
+ * i2c_probe_chip() - probe for a chip on a bus
+ *
+ * @bus:	Bus to probe
+ * @chip_addr:	Chip address to probe
+ * @flags:	Flags for the chip
+ * @return 0 if found, -ENOSYS if the driver is invalid, -EREMOTEIO if the chip
+ * does not respond to probe
+ */
+static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
+			  enum dm_i2c_chip_flags chip_flags)
+{
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct i2c_msg msg[1];
+	int ret;
+
+	if (ops->probe_chip) {
+		ret = ops->probe_chip(bus, chip_addr, chip_flags);
+		if (!ret || ret != -ENOSYS)
+			return ret;
+	}
+
+	if (!ops->xfer)
+		return -ENOSYS;
+
+	/* Probe with a zero-length message */
+	msg->addr = chip_addr;
+	msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+	msg->len = 0;
+	msg->buf = NULL;
+
+	return ops->xfer(bus, msg, 1);
+}
+
+static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
+			   struct udevice **devp)
+{
+	struct dm_i2c_chip chip;
+	char name[30], *str;
+	struct udevice *dev;
+	int ret;
+
+	snprintf(name, sizeof(name), "generic_%x", chip_addr);
+	str = strdup(name);
+	ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev);
+	debug("%s:  device_bind_driver: ret=%d\n", __func__, ret);
+	if (ret)
+		goto err_bind;
+
+	/* Tell the device what we know about it */
+	memset(&chip, '\0', sizeof(chip));
+	chip.chip_addr = chip_addr;
+	chip.offset_len = 1;	/* we assume */
+	ret = device_probe_child(dev, &chip);
+	debug("%s:  device_probe_child: ret=%d\n", __func__, ret);
+	if (ret)
+		goto err_probe;
+
+	*devp = dev;
+	return 0;
+
+err_probe:
+	device_unbind(dev);
+err_bind:
+	free(str);
+	return ret;
+}
+
+int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	debug("%s: Searching bus '%s' for address %02x: ", __func__,
+	      bus->name, chip_addr);
+	for (device_find_first_child(bus, &dev); dev;
+			device_find_next_child(&dev)) {
+		struct dm_i2c_chip store;
+		struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+		int ret;
+
+		if (!chip) {
+			chip = &store;
+			i2c_chip_ofdata_to_platdata(gd->fdt_blob,
+						    dev->of_offset, chip);
+		}
+		if (chip->chip_addr == chip_addr) {
+			ret = device_probe(dev);
+			debug("found, ret=%d\n", ret);
+			if (ret)
+				return ret;
+			*devp = dev;
+			return 0;
+		}
+	}
+	debug("not found\n");
+	return i2c_bind_driver(bus, chip_addr, devp);
+}
+
+int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
+{
+	struct udevice *bus;
+	int ret;
+
+	ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
+	if (ret) {
+		debug("Cannot find I2C bus %d\n", busnum);
+		return ret;
+	}
+	ret = i2c_get_chip(bus, chip_addr, devp);
+	if (ret) {
+		debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
+		      busnum);
+		return ret;
+	}
+
+	return 0;
+}
+
+int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
+	      struct udevice **devp)
+{
+	int ret;
+
+	*devp = NULL;
+
+	/* First probe that chip */
+	ret = i2c_probe_chip(bus, chip_addr, chip_flags);
+	debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
+	      chip_addr, ret);
+	if (ret)
+		return ret;
+
+	/* The chip was found, see if we have a driver, and probe it */
+	ret = i2c_get_chip(bus, chip_addr, devp);
+	debug("%s:  i2c_get_chip: ret=%d\n", __func__, ret);
+
+	return ret;
+}
+
+int i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct dm_i2c_bus *i2c = bus->uclass_priv;
+	int ret;
+
+	/*
+	 * If we have a method, call it. If not then the driver probably wants
+	 * to deal with speed changes on the next transfer. It can easily read
+	 * the current speed from this uclass
+	 */
+	if (ops->set_bus_speed) {
+		ret = ops->set_bus_speed(bus, speed);
+		if (ret)
+			return ret;
+	}
+	i2c->speed_hz = speed;
+
+	return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ *  Returns speed of selected I2C bus in Hz
+ */
+int i2c_get_bus_speed(struct udevice *bus)
+{
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct dm_i2c_bus *i2c = bus->uclass_priv;
+
+	if (!ops->get_bus_speed)
+		return i2c->speed_hz;
+
+	return ops->get_bus_speed(bus);
+}
+
+int i2c_set_chip_flags(struct udevice *dev, uint flags)
+{
+	struct udevice *bus = dev->parent;
+	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	int ret;
+
+	if (ops->set_flags) {
+		ret = ops->set_flags(dev, flags);
+		if (ret)
+			return ret;
+	}
+	chip->flags = flags;
+
+	return 0;
+}
+
+int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
+{
+	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+
+	*flagsp = chip->flags;
+
+	return 0;
+}
+
+int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
+{
+	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+
+	if (offset_len > I2C_MAX_OFFSET_LEN)
+		return -EINVAL;
+	chip->offset_len = offset_len;
+
+	return 0;
+}
+
+int i2c_deblock(struct udevice *bus)
+{
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+
+	/*
+	 * We could implement a software deblocking here if we could get
+	 * access to the GPIOs used by I2C, and switch them to GPIO mode
+	 * and then back to I2C. This is somewhat beyond our powers in
+	 * driver model at present, so for now just fail.
+	 *
+	 * See https://patchwork.ozlabs.org/patch/399040/
+	 */
+	if (!ops->deblock)
+		return -ENOSYS;
+
+	return ops->deblock(bus);
+}
+
+int i2c_chip_ofdata_to_platdata(const void *blob, int node,
+				struct dm_i2c_chip *chip)
+{
+	chip->offset_len = 1;	/* default */
+	chip->flags = 0;
+	chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
+	if (chip->chip_addr == -1) {
+		debug("%s: I2C Node '%s' has no 'reg' property\n", __func__,
+		      fdt_get_name(blob, node, NULL));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int i2c_post_probe(struct udevice *dev)
+{
+	struct dm_i2c_bus *i2c = dev->uclass_priv;
+
+	i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				     "clock-frequency", 100000);
+
+	return i2c_set_bus_speed(dev, i2c->speed_hz);
+}
+
+int i2c_post_bind(struct udevice *dev)
+{
+	/* Scan the bus for devices */
+	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+UCLASS_DRIVER(i2c) = {
+	.id		= UCLASS_I2C,
+	.name		= "i2c",
+	.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+	.post_bind	= i2c_post_bind,
+	.post_probe	= i2c_post_probe,
+};
+
+UCLASS_DRIVER(i2c_generic) = {
+	.id		= UCLASS_I2C_GENERIC,
+	.name		= "i2c_generic",
+};
+
+U_BOOT_DRIVER(i2c_generic_chip_drv) = {
+	.name		= "i2c_generic_chip_drv",
+	.id		= UCLASS_I2C_GENERIC,
+};
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
new file mode 100644
index 0000000..f0e9f51
--- /dev/null
+++ b/drivers/i2c/sandbox_i2c.c
@@ -0,0 +1,111 @@
+/*
+ * Simulate an I2C port
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <asm/test.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct dm_sandbox_i2c_emul_priv {
+	struct udevice *emul;
+};
+
+static int get_emul(struct udevice *dev, struct udevice **devp,
+		    struct dm_i2c_ops **opsp)
+{
+	struct dm_i2c_chip *priv;
+	int ret;
+
+	*devp = NULL;
+	*opsp = NULL;
+	priv = dev_get_parentdata(dev);
+	if (!priv->emul) {
+		ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset,
+				       false);
+		if (ret)
+			return ret;
+
+		ret = device_get_child(dev, 0, &priv->emul);
+		if (ret)
+			return ret;
+	}
+	*devp = priv->emul;
+	*opsp = i2c_get_ops(priv->emul);
+
+	return 0;
+}
+
+static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+			    int nmsgs)
+{
+	struct dm_i2c_bus *i2c = bus->uclass_priv;
+	struct dm_i2c_ops *ops;
+	struct udevice *emul, *dev;
+	bool is_read;
+	int ret;
+
+	/* Special test code to return success but with no emulation */
+	if (msg->addr == SANDBOX_I2C_TEST_ADDR)
+		return 0;
+
+	ret = i2c_get_chip(bus, msg->addr, &dev);
+	if (ret)
+		return ret;
+
+	ret = get_emul(dev, &emul, &ops);
+	if (ret)
+		return ret;
+
+	/*
+	 * For testing, don't allow writing above 100KHz for writes and
+	 * 400KHz for reads
+	 */
+	is_read = nmsgs > 1;
+	if (i2c->speed_hz > (is_read ? 400000 : 100000))
+		return -EINVAL;
+	return ops->xfer(emul, msg, nmsgs);
+}
+
+static const struct dm_i2c_ops sandbox_i2c_ops = {
+	.xfer		= sandbox_i2c_xfer,
+};
+
+static int sandbox_i2c_child_pre_probe(struct udevice *dev)
+{
+	struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
+
+	/* Ignore our test address */
+	if (i2c_chip->chip_addr == SANDBOX_I2C_TEST_ADDR)
+		return 0;
+	if (dev->of_offset == -1)
+		return 0;
+
+	return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+					   i2c_chip);
+}
+
+static const struct udevice_id sandbox_i2c_ids[] = {
+	{ .compatible = "sandbox,i2c" },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_sandbox) = {
+	.name	= "i2c_sandbox",
+	.id	= UCLASS_I2C,
+	.of_match = sandbox_i2c_ids,
+	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+	.child_pre_probe = sandbox_i2c_child_pre_probe,
+	.ops	= &sandbox_i2c_ops,
+};
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index 562211e..87290c3 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -7,6 +7,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <asm/io.h>
@@ -19,6 +21,12 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+enum i2c_type {
+	TYPE_114,
+	TYPE_STD,
+	TYPE_DVC,
+};
+
 /* Information about i2c controller */
 struct i2c_bus {
 	int			id;
@@ -27,20 +35,17 @@
 	int			pinmux_config;
 	struct i2c_control	*control;
 	struct i2c_ctlr		*regs;
-	int			is_dvc;	/* DVC type, rather than I2C */
-	int			is_scs;	/* single clock source (T114+) */
+	enum i2c_type		type;
 	int			inited;	/* bus is inited */
 };
 
-static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS];
-
 static void set_packet_mode(struct i2c_bus *i2c_bus)
 {
 	u32 config;
 
 	config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
 
-	if (i2c_bus->is_dvc) {
+	if (i2c_bus->type == TYPE_DVC) {
 		struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
 
 		writel(config, &dvc->cnfg);
@@ -65,6 +70,9 @@
 
 static void i2c_init_controller(struct i2c_bus *i2c_bus)
 {
+	if (!i2c_bus->speed)
+		return;
+	debug("%s: speed=%d\n", __func__, i2c_bus->speed);
 	/*
 	 * Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
 	 * here, in section 23.3.1, but in fact we seem to need a factor of
@@ -73,7 +81,7 @@
 	clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
 		i2c_bus->speed * 2 * 8);
 
-	if (i2c_bus->is_scs) {
+	if (i2c_bus->type == TYPE_114) {
 		/*
 		 * T114 I2C went to a single clock source for standard/fast and
 		 * HS clock speeds. The new clock rate setting calculation is:
@@ -98,7 +106,7 @@
 	i2c_reset_controller(i2c_bus);
 
 	/* Configure I2C controller. */
-	if (i2c_bus->is_dvc) {	/* only for DVC I2C */
+	if (i2c_bus->type == TYPE_DVC) {	/* only for DVC I2C */
 		struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
 
 		setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
@@ -272,7 +280,7 @@
 	return error;
 }
 
-static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
+static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
 				u32 len, bool end_with_repeated_start)
 {
 	int error;
@@ -286,14 +294,14 @@
 	trans_info.num_bytes = len;
 	trans_info.is_10bit_address = 0;
 
-	error = send_recv_packets(bus, &trans_info);
+	error = send_recv_packets(i2c_bus, &trans_info);
 	if (error)
 		debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
 
 	return error;
 }
 
-static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
+static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
 			       u32 len)
 {
 	int error;
@@ -305,52 +313,32 @@
 	trans_info.num_bytes = len;
 	trans_info.is_10bit_address = 0;
 
-	error = send_recv_packets(bus, &trans_info);
+	error = send_recv_packets(i2c_bus, &trans_info);
 	if (error)
 		debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
 
 	return error;
 }
 
-#ifndef CONFIG_OF_CONTROL
-#error "Please enable device tree support to use this driver"
-#endif
-
-/**
- * Check that a bus number is valid and return a pointer to it
- *
- * @param bus_num	Bus number to check / return
- * @return pointer to bus, if valid, else NULL
- */
-static struct i2c_bus *tegra_i2c_get_bus(struct i2c_adapter *adap)
+static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
 {
-	struct i2c_bus *bus;
+	struct i2c_bus *i2c_bus = dev_get_priv(dev);
 
-	bus = &i2c_controllers[adap->hwadapnr];
-	if (!bus->inited) {
-		debug("%s: Bus %u not available\n", __func__, adap->hwadapnr);
-		return NULL;
-	}
-
-	return bus;
-}
-
-static unsigned int tegra_i2c_set_bus_speed(struct i2c_adapter *adap,
-			unsigned int speed)
-{
-	struct i2c_bus *bus;
-
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 0;
-	bus->speed = speed;
-	i2c_init_controller(bus);
+	i2c_bus->speed = speed;
+	i2c_init_controller(i2c_bus);
 
 	return 0;
 }
 
-static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
+static int tegra_i2c_probe(struct udevice *dev)
 {
+	struct i2c_bus *i2c_bus = dev_get_priv(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	bool is_dvc;
+
+	i2c_bus->id = dev->seq;
+	i2c_bus->type = dev_get_of_data(dev);
 	i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
 
 	/*
@@ -358,7 +346,6 @@
 	 * far no one needs anything other than the default.
 	 */
 	i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
-	i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0);
 	i2c_bus->periph_id = clock_decode_periph_id(blob, node);
 
 	/*
@@ -371,107 +358,25 @@
 	 *		i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
 	 */
 	if (i2c_bus->periph_id == -1)
-		return -FDT_ERR_NOTFOUND;
+		return -EINVAL;
 
-	return 0;
-}
-
-/*
- * Process a list of nodes, adding them to our list of I2C ports.
- *
- * @param blob		fdt blob
- * @param node_list	list of nodes to process (any <=0 are ignored)
- * @param count		number of nodes to process
- * @param is_dvc	1 if these are DVC ports, 0 if standard I2C
- * @param is_scs	1 if this HW uses a single clock source (T114+)
- * @return 0 if ok, -1 on error
- */
-static int process_nodes(const void *blob, int node_list[], int count,
-			 int is_dvc, int is_scs)
-{
-	struct i2c_bus *i2c_bus;
-	int i;
-
-	/* build the i2c_controllers[] for each controller */
-	for (i = 0; i < count; i++) {
-		int node = node_list[i];
-
-		if (node <= 0)
-			continue;
-
-		i2c_bus = &i2c_controllers[i];
-		i2c_bus->id = i;
-
-		if (i2c_get_config(blob, node, i2c_bus)) {
-			printf("i2c_init_board: failed to decode bus %d\n", i);
-			return -1;
-		}
-
-		i2c_bus->is_scs = is_scs;
-
-		i2c_bus->is_dvc = is_dvc;
-		if (is_dvc) {
-			i2c_bus->control =
-				&((struct dvc_ctlr *)i2c_bus->regs)->control;
-		} else {
-			i2c_bus->control = &i2c_bus->regs->control;
-		}
-		debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
-		      is_dvc ? "dvc" : "i2c", i, i2c_bus->regs,
-		      i2c_bus->periph_id, i2c_bus->speed);
-		i2c_init_controller(i2c_bus);
-		debug("ok\n");
-		i2c_bus->inited = 1;
-
-		/* Mark position as used */
-		node_list[i] = -1;
+	is_dvc = dev_get_of_data(dev) == TYPE_DVC;
+	if (is_dvc) {
+		i2c_bus->control =
+			&((struct dvc_ctlr *)i2c_bus->regs)->control;
+	} else {
+		i2c_bus->control = &i2c_bus->regs->control;
 	}
+	i2c_init_controller(i2c_bus);
+	debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
+	      is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
+	      i2c_bus->periph_id, i2c_bus->speed);
 
 	return 0;
 }
 
-/* Sadly there is no error return from this function */
-void i2c_init_board(void)
-{
-	int node_list[TEGRA_I2C_NUM_CONTROLLERS];
-	const void *blob = gd->fdt_blob;
-	int count;
-
-	/* First check for newer (T114+) I2C ports */
-	count = fdtdec_find_aliases_for_id(blob, "i2c",
-			COMPAT_NVIDIA_TEGRA114_I2C, node_list,
-			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 0, 1))
-		return;
-
-	/* Now get the older (T20/T30) normal I2C ports */
-	count = fdtdec_find_aliases_for_id(blob, "i2c",
-			COMPAT_NVIDIA_TEGRA20_I2C, node_list,
-			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 0, 0))
-		return;
-
-	/* Now look for dvc ports */
-	count = fdtdec_add_aliases_for_id(blob, "i2c",
-			COMPAT_NVIDIA_TEGRA20_DVC, node_list,
-			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 1, 0))
-		return;
-}
-
-static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
-{
-	/* No i2c support prior to relocation */
-	if (!(gd->flags & GD_FLG_RELOC))
-		return;
-
-	/* This will override the speed selected in the fdt for that port */
-	debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
-	i2c_set_bus_speed(speed);
-}
-
 /* i2c write version without the register address */
-static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer,
+static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
 			  int len, bool end_with_repeated_start)
 {
 	int rc;
@@ -484,7 +389,7 @@
 	debug("\n");
 
 	/* Shift 7-bit address over for lower-level i2c functions */
-	rc = tegra_i2c_write_data(bus, chip << 1, buffer, len,
+	rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len,
 				  end_with_repeated_start);
 	if (rc)
 		debug("i2c_write_data(): rc=%d\n", rc);
@@ -493,14 +398,14 @@
 }
 
 /* i2c read version without the register address */
-static int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer,
-				int len)
+static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
+			 int len)
 {
 	int rc;
 
 	debug("inside i2c_read_data():\n");
 	/* Shift 7-bit address over for lower-level i2c functions */
-	rc = tegra_i2c_read_data(bus, chip << 1, buffer, len);
+	rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len);
 	if (rc) {
 		debug("i2c_read_data(): rc=%d\n", rc);
 		return rc;
@@ -516,132 +421,99 @@
 }
 
 /* Probe to see if a chip is present. */
-static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip)
+static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+				uint chip_flags)
 {
-	struct i2c_bus *bus;
+	struct i2c_bus *i2c_bus = dev_get_priv(bus);
 	int rc;
-	uchar reg;
+	u8 reg;
 
-	debug("i2c_probe: addr=0x%x\n", chip);
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 1;
-	reg = 0;
-	rc = i2c_write_data(bus, chip, &reg, 1, false);
-	if (rc) {
-		debug("Error probing 0x%x.\n", chip);
-		return 1;
-	}
-	return 0;
+	/* Shift 7-bit address over for lower-level i2c functions */
+	rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, &reg, sizeof(reg),
+				  false);
+
+	return rc;
 }
 
-static int i2c_addr_ok(const uint addr, const int alen)
+static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+			  int nmsgs)
 {
-	/* We support 7 or 10 bit addresses, so one or two bytes each */
-	return alen == 1 || alen == 2;
-}
+	struct i2c_bus *i2c_bus = dev_get_priv(bus);
+	int ret;
 
-/* Read bytes */
-static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
-			int alen, uchar *buffer, int len)
-{
-	struct i2c_bus *bus;
-	uint offset;
-	int i;
+	debug("i2c_xfer: %d messages\n", nmsgs);
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
 
-	debug("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n",
-	      chip, addr, alen, len);
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 1;
-	if (!i2c_addr_ok(addr, alen)) {
-		debug("i2c_read: Bad address %x.%d.\n", addr, alen);
-		return 1;
-	}
-	for (offset = 0; offset < len; offset++) {
-		if (alen) {
-			uchar data[alen];
-			for (i = 0; i < alen; i++) {
-				data[alen - i - 1] =
-					(addr + offset) >> (8 * i);
-			}
-			if (i2c_write_data(bus, chip, data, alen, true)) {
-				debug("i2c_read: error sending (0x%x)\n",
-					addr);
-				return 1;
-			}
+		debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+		if (msg->flags & I2C_M_RD) {
+			ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
+					    msg->len);
+		} else {
+			ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
+					     msg->len, next_is_read);
 		}
-		if (i2c_read_data(bus, chip, buffer + offset, 1)) {
-			debug("i2c_read: error reading (0x%x)\n", addr);
-			return 1;
+		if (ret) {
+			debug("i2c_write: error sending\n");
+			return -EREMOTEIO;
 		}
 	}
 
 	return 0;
 }
 
-/* Write bytes */
-static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
-			int alen, uchar *buffer, int len)
+int tegra_i2c_get_dvc_bus(struct udevice **busp)
 {
-	struct i2c_bus *bus;
-	uint offset;
-	int i;
+	struct udevice *bus;
 
-	debug("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n",
-	      chip, addr, alen, len);
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 1;
-	if (!i2c_addr_ok(addr, alen)) {
-		debug("i2c_write: Bad address %x.%d.\n", addr, alen);
-		return 1;
-	}
-	for (offset = 0; offset < len; offset++) {
-		uchar data[alen + 1];
-		for (i = 0; i < alen; i++)
-			data[alen - i - 1] = (addr + offset) >> (8 * i);
-		data[alen] = buffer[offset];
-		if (i2c_write_data(bus, chip, data, alen + 1, false)) {
-			debug("i2c_write: error sending (0x%x)\n", addr);
-			return 1;
+	for (uclass_first_device(UCLASS_I2C, &bus);
+	     bus;
+	     uclass_next_device(&bus)) {
+		if (dev_get_of_data(bus) == TYPE_DVC) {
+			*busp = bus;
+			return 0;
 		}
 	}
 
+	return -ENODEV;
+}
+
+static const struct dm_i2c_ops tegra_i2c_ops = {
+	.xfer		= tegra_i2c_xfer,
+	.probe_chip	= tegra_i2c_probe_chip,
+	.set_bus_speed	= tegra_i2c_set_bus_speed,
+};
+
+static int tegra_i2c_child_pre_probe(struct udevice *dev)
+{
+	struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
+
+	if (dev->of_offset == -1)
+		return 0;
+	return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+					   i2c_chip);
+}
+
+static int tegra_i2c_ofdata_to_platdata(struct udevice *dev)
+{
 	return 0;
 }
 
-int tegra_i2c_get_dvc_bus_num(void)
-{
-	int i;
+static const struct udevice_id tegra_i2c_ids[] = {
+	{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+	{ .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
+	{ .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
+	{ }
+};
 
-	for (i = 0; i < TEGRA_I2C_NUM_CONTROLLERS; i++) {
-		struct i2c_bus *bus = &i2c_controllers[i];
-
-		if (bus->inited && bus->is_dvc)
-			return i;
-	}
-
-	return -1;
-}
-
-/*
- * Register soft i2c adapters
- */
-U_BOOT_I2C_ADAP_COMPLETE(tegra0, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 0)
-U_BOOT_I2C_ADAP_COMPLETE(tegra1, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 1)
-U_BOOT_I2C_ADAP_COMPLETE(tegra2, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 2)
-U_BOOT_I2C_ADAP_COMPLETE(tegra3, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 3)
-#if TEGRA_I2C_NUM_CONTROLLERS > 4
-U_BOOT_I2C_ADAP_COMPLETE(tegra4, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 4)
-#endif
+U_BOOT_DRIVER(i2c_tegra) = {
+	.name	= "i2c_tegra",
+	.id	= UCLASS_I2C,
+	.of_match = tegra_i2c_ids,
+	.ofdata_to_platdata = tegra_i2c_ofdata_to_platdata,
+	.probe	= tegra_i2c_probe,
+	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+	.child_pre_probe = tegra_i2c_child_pre_probe,
+	.priv_auto_alloc_size = sizeof(struct i2c_bus),
+	.ops	= &tegra_i2c_ops,
+};
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2f2e48f..6fa836f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -15,11 +15,15 @@
 obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
 obj-$(CONFIG_FSL_IIM) += fsl_iim.o
 obj-$(CONFIG_GPIO_LED) += gpio_led.o
+obj-$(CONFIG_I2C_EEPROM) += i2c_eeprom.o
 obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
 obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
 obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
 obj-$(CONFIG_NS87308) += ns87308.o
 obj-$(CONFIG_PDSP188x) += pdsp188x.o
+ifdef CONFIG_DM_I2C
+obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
+endif
 obj-$(CONFIG_STATUS_LED) += status_led.o
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
new file mode 100644
index 0000000..d0548ec
--- /dev/null
+++ b/drivers/misc/i2c_eeprom.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <i2c_eeprom.h>
+
+static int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf,
+			   int size)
+{
+	return -ENODEV;
+}
+
+static int i2c_eeprom_write(struct udevice *dev, int offset,
+			    const uint8_t *buf, int size)
+{
+	return -ENODEV;
+}
+
+struct i2c_eeprom_ops i2c_eeprom_std_ops = {
+	.read	= i2c_eeprom_read,
+	.write	= i2c_eeprom_write,
+};
+
+int i2c_eeprom_std_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct udevice_id i2c_eeprom_std_ids[] = {
+	{ .compatible = "i2c-eeprom" },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_eeprom_std) = {
+	.name		= "i2c_eeprom",
+	.id		= UCLASS_I2C_EEPROM,
+	.of_match	= i2c_eeprom_std_ids,
+	.probe		= i2c_eeprom_std_probe,
+	.priv_auto_alloc_size = sizeof(struct i2c_eeprom),
+	.ops		= &i2c_eeprom_std_ops,
+};
+
+UCLASS_DRIVER(i2c_eeprom) = {
+	.id		= UCLASS_I2C_EEPROM,
+	.name		= "i2c_eeprom",
+};
diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c
new file mode 100644
index 0000000..7343445
--- /dev/null
+++ b/drivers/misc/i2c_eeprom_emul.c
@@ -0,0 +1,168 @@
+/*
+ * Simulate an I2C eeprom
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/test.h>
+
+#ifdef DEBUG
+#define debug_buffer print_buffer
+#else
+#define debug_buffer(x, ...)
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sandbox_i2c_flash_plat_data {
+	enum sandbox_i2c_eeprom_test_mode test_mode;
+	const char *filename;
+	int offset_len;		/* Length of an offset in bytes */
+	int size;		/* Size of data buffer */
+};
+
+struct sandbox_i2c_flash {
+	uint8_t *data;
+};
+
+void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
+				      enum sandbox_i2c_eeprom_test_mode mode)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+
+	plat->test_mode = mode;
+}
+
+void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+
+	plat->offset_len = offset_len;
+}
+
+static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg,
+				  int nmsgs)
+{
+	struct sandbox_i2c_flash *priv = dev_get_priv(emul);
+	uint offset = 0;
+
+	debug("\n%s\n", __func__);
+	debug_buffer(0, priv->data, 1, 16, 0);
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		struct sandbox_i2c_flash_plat_data *plat =
+				dev_get_platdata(emul);
+		int len;
+		u8 *ptr;
+
+		if (!plat->size)
+			return -ENODEV;
+		if (msg->addr + msg->len > plat->size) {
+			debug("%s: Address %x, len %x is outside range 0..%x\n",
+			      __func__, msg->addr, msg->len, plat->size);
+			return -EINVAL;
+		}
+		len = msg->len;
+		debug("   %s: msg->len=%d",
+		      msg->flags & I2C_M_RD ? "read" : "write",
+		      msg->len);
+		if (msg->flags & I2C_M_RD) {
+			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
+				len = 1;
+			debug(", offset %x, len %x: ", offset, len);
+			memcpy(msg->buf, priv->data + offset, len);
+			memset(msg->buf + len, '\xff', msg->len - len);
+			debug_buffer(0, msg->buf, 1, msg->len, 0);
+		} else if (len >= plat->offset_len) {
+			int i;
+
+			ptr = msg->buf;
+			for (i = 0; i < plat->offset_len; i++, len--)
+				offset = (offset << 8) | *ptr++;
+			debug(", set offset %x: ", offset);
+			debug_buffer(0, msg->buf, 1, msg->len, 0);
+			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
+				len = min(len, 1);
+
+			/* For testing, map offsets into our limited buffer */
+			for (i = 24; i > 0; i -= 8) {
+				if (offset > (1 << i)) {
+					offset = (offset >> i) |
+						(offset & ((1 << i) - 1));
+					offset += i;
+				}
+			}
+			memcpy(priv->data + offset, ptr, len);
+		}
+	}
+	debug_buffer(0, priv->data, 1, 16, 0);
+
+	return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_emul_ops = {
+	.xfer = sandbox_i2c_eeprom_xfer,
+};
+
+static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+
+	plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				    "sandbox,size", 32);
+	plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset,
+				     "sandbox,filename", NULL);
+	if (!plat->filename) {
+		debug("%s: No filename for device '%s'\n", __func__,
+		      dev->name);
+		return -EINVAL;
+	}
+	plat->test_mode = SIE_TEST_MODE_NONE;
+	plat->offset_len = 1;
+
+	return 0;
+}
+
+static int sandbox_i2c_eeprom_probe(struct udevice *dev)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+	struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+
+	priv->data = calloc(1, plat->size);
+	if (!priv->data)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int sandbox_i2c_eeprom_remove(struct udevice *dev)
+{
+	struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+
+	free(priv->data);
+
+	return 0;
+}
+
+static const struct udevice_id sandbox_i2c_ids[] = {
+	{ .compatible = "sandbox,i2c-eeprom" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_emul) = {
+	.name		= "sandbox_i2c_eeprom_emul",
+	.id		= UCLASS_I2C_EMUL,
+	.of_match	= sandbox_i2c_ids,
+	.ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata,
+	.probe		= sandbox_i2c_eeprom_probe,
+	.remove		= sandbox_i2c_eeprom_remove,
+	.priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash),
+	.platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data),
+	.ops		= &sandbox_i2c_emul_ops,
+};
diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c
index d29d969..29bab4c 100644
--- a/drivers/power/tps6586x.c
+++ b/drivers/power/tps6586x.c
@@ -10,9 +10,7 @@
 #include <asm/io.h>
 #include <i2c.h>
 
-static int bus_num;		/* I2C bus we are on */
-#define I2C_ADDRESS		0x34	/* chip requires this address */
-static char inited;		/* 1 if we have been inited */
+static struct udevice *tps6586x_dev;
 
 enum {
 	/* Registers that we access */
@@ -37,13 +35,9 @@
 	int	i;
 	uchar	data;
 	int	retval = -1;
-	int	old_bus_num;
-
-	old_bus_num = i2c_get_bus_num();
-	i2c_set_bus_num(bus_num);
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (!i2c_read(I2C_ADDRESS, reg, 1, &data, 1)) {
+		if (!i2c_read(tps6586x_dev, reg,  &data, 1)) {
 			retval = (int)data;
 			goto exit;
 		}
@@ -53,7 +47,6 @@
 	}
 
 exit:
-	i2c_set_bus_num(old_bus_num);
 	debug("pmu_read %x=%x\n", reg, retval);
 	if (retval < 0)
 		debug("%s: failed to read register %#x: %d\n", __func__, reg,
@@ -65,13 +58,9 @@
 {
 	int	i;
 	int	retval = -1;
-	int	old_bus_num;
-
-	old_bus_num = i2c_get_bus_num();
-	i2c_set_bus_num(bus_num);
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (!i2c_write(I2C_ADDRESS, reg, 1, data, len)) {
+		if (!i2c_write(tps6586x_dev, reg, data, len)) {
 			retval = 0;
 			goto exit;
 		}
@@ -81,7 +70,6 @@
 	}
 
 exit:
-	i2c_set_bus_num(old_bus_num);
 	debug("pmu_write %x=%x: ", reg, retval);
 	for (i = 0; i < len; i++)
 		debug("%x ", data[i]);
@@ -163,7 +151,7 @@
 	uchar val;
 	int ret;
 
-	assert(inited);
+	assert(tps6586x_dev);
 	ret = tps6586x_read(PFM_MODE);
 	if (ret != -1) {
 		val = (uchar)ret;
@@ -184,7 +172,7 @@
 	int sm0, sm1;
 	int bad;
 
-	assert(inited);
+	assert(tps6586x_dev);
 
 	/* get current voltage settings */
 	if (read_voltages(&sm0, &sm1)) {
@@ -255,10 +243,9 @@
 	return bad ? -1 : 0;
 }
 
-int tps6586x_init(int bus)
+int tps6586x_init(struct udevice *dev)
 {
-	bus_num = bus;
-	inited = 1;
+	tps6586x_dev = dev;
 
 	return 0;
 }
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index e1bf496..75eb6bd 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -348,6 +348,7 @@
 	.probe = pl01x_serial_probe,
 	.ops	= &pl01x_serial_ops,
 	.flags = DM_FLAG_PRE_RELOC,
+	.priv_auto_alloc_size = sizeof(struct pl01x_priv),
 };
 
 #endif
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index d0dd29f..ba442d5 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -852,30 +852,6 @@
 DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT);
 #endif
 
-
-/**
- * strlcpy - Copy a %NUL terminated string into a sized buffer
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
- * @size: size of destination buffer
- *
- * Compatible with *BSD: the result is always a valid
- * NUL-terminated string that fits in the buffer (unless,
- * of course, the buffer size is zero). It does not pad
- * out the result like strncpy() does.
- */
-size_t strlcpy(char *dest, const char *src, size_t size)
-{
-	size_t ret = strlen(src);
-
-	if (size) {
-		size_t len = (ret >= size) ? size - 1 : ret;
-		memcpy(dest, src, len);
-		dest[len] = '\0';
-	}
-	return ret;
-}
-
 /*============================================================================*/
 
 /*
diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h
index 508db56..ddfe045 100644
--- a/include/config_fallbacks.h
+++ b/include/config_fallbacks.h
@@ -91,4 +91,10 @@
 #undef CONFIG_IMAGE_FORMAT_LEGACY
 #endif
 
+#ifdef CONFIG_DM_I2C
+# ifdef CONFIG_SYS_I2C
+#  error "Cannot define CONFIG_SYS_I2C when CONFIG_DM_I2C is used"
+# endif
+#endif
+
 #endif	/* __CONFIG_FALLBACKS_H */
diff --git a/include/configs/apalis_t30.h b/include/configs/apalis_t30.h
index 3cde923..61809fc 100644
--- a/include/configs/apalis_t30.h
+++ b/include/configs/apalis_t30.h
@@ -26,10 +26,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/beaver.h b/include/configs/beaver.h
index 164b2dd..5d765f3 100644
--- a/include/configs/beaver.h
+++ b/include/configs/beaver.h
@@ -40,10 +40,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h
index 09129c7..758b7ad 100644
--- a/include/configs/cardhu.h
+++ b/include/configs/cardhu.h
@@ -43,12 +43,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_I2C_MULTI_BUS
-#define CONFIG_SYS_MAX_I2C_BUS		TEGRA_I2C_NUM_CONTROLLERS
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/colibri_t30.h b/include/configs/colibri_t30.h
index a582e25..ce6f23b 100644
--- a/include/configs/colibri_t30.h
+++ b/include/configs/colibri_t30.h
@@ -25,10 +25,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/dalmore.h b/include/configs/dalmore.h
index ff7ec4a..0b04ee6 100644
--- a/include/configs/dalmore.h
+++ b/include/configs/dalmore.h
@@ -36,12 +36,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_I2C_MULTI_BUS
-#define CONFIG_SYS_MAX_I2C_BUS		TEGRA_I2C_NUM_CONTROLLERS
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/jetson-tk1.h b/include/configs/jetson-tk1.h
index d67c025..a7d7665 100644
--- a/include/configs/jetson-tk1.h
+++ b/include/configs/jetson-tk1.h
@@ -25,12 +25,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_I2C_MULTI_BUS
-#define CONFIG_SYS_MAX_I2C_BUS		TEGRA_I2C_NUM_CONTROLLERS
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/nyan-big.h b/include/configs/nyan-big.h
new file mode 100644
index 0000000..cf331ab
--- /dev/null
+++ b/include/configs/nyan-big.h
@@ -0,0 +1,74 @@
+/*
+ * (C) Copyright 2014
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <linux/sizes.h>
+
+#include "tegra124-common.h"
+
+/* High-level configuration options */
+#define V_PROMPT			"Tegra124 (Nyan-big) # "
+#define CONFIG_TEGRA_BOARD_STRING	"Google/NVIDIA Nyan-big"
+
+/* Board-specific serial config */
+#define CONFIG_SERIAL_MULTI
+#define CONFIG_TEGRA_ENABLE_UARTA
+#define CONFIG_SYS_NS16550_COM1		NV_PA_APB_UARTA_BASE
+
+#define CONFIG_BOARD_EARLY_INIT_F
+
+/* I2C */
+#define CONFIG_SYS_I2C_TEGRA
+#define CONFIG_CMD_I2C
+
+/* SD/MMC */
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_TEGRA_MMC
+#define CONFIG_CMD_MMC
+
+/* Environment in eMMC, at the end of 2nd "boot sector" */
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV		0
+#define CONFIG_SYS_MMC_ENV_PART		2
+#define CONFIG_ENV_OFFSET		(-CONFIG_ENV_SIZE)
+
+/* SPI */
+#define CONFIG_TEGRA114_SPI		/* Compatible w/ Tegra114 SPI */
+#define CONFIG_TEGRA114_SPI_CTRLS	6
+#define CONFIG_SPI_FLASH
+#define CONFIG_SPI_FLASH_WINBOND
+#define CONFIG_SF_DEFAULT_MODE         SPI_MODE_0
+#define CONFIG_SF_DEFAULT_SPEED        24000000
+#define CONFIG_CMD_SPI
+#define CONFIG_CMD_SF
+#define CONFIG_SPI_FLASH_SIZE          (4 << 20)
+
+/* USB Host support */
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_TEGRA
+#define CONFIG_USB_MAX_CONTROLLER_COUNT	2
+#define CONFIG_USB_STORAGE
+#define CONFIG_CMD_USB
+
+/* USB networking support */
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+
+/* General networking support */
+#define CONFIG_CMD_NET
+#define CONFIG_CMD_DHCP
+
+#define CONFIG_FIT
+#define CONFIG_OF_LIBFDT
+
+#include "tegra-common-usb-gadget.h"
+#include "tegra-common-post.h"
+
+#endif /* __CONFIG_H */
diff --git a/include/configs/rpi.h b/include/configs/rpi.h
index 4d5426e..c94f411 100644
--- a/include/configs/rpi.h
+++ b/include/configs/rpi.h
@@ -34,6 +34,7 @@
 #define CONFIG_DM
 #define CONFIG_CMD_DM
 #define CONFIG_DM_GPIO
+#define CONFIG_DM_SERIAL
 
 /* Memory layout */
 #define CONFIG_NR_DRAM_BANKS		1
@@ -51,6 +52,7 @@
 					 CONFIG_SYS_SDRAM_SIZE - \
 					 GENERATED_GBL_DATA_SIZE)
 #define CONFIG_SYS_MALLOC_LEN		SZ_4M
+#define CONFIG_SYS_MALLOC_F_LEN		(1 << 10)
 #define CONFIG_SYS_MEMTEST_START	0x00100000
 #define CONFIG_SYS_MEMTEST_END		0x00200000
 #define CONFIG_LOADADDR			0x00200000
@@ -92,9 +94,7 @@
 #endif
 
 /* Console UART */
-#define CONFIG_PL011_SERIAL
-#define CONFIG_PL011_CLOCK		3000000
-#define CONFIG_PL01x_PORTS		{ (void *)0x20201000 }
+#define CONFIG_PL01X_SERIAL
 #define CONFIG_CONS_INDEX		0
 #define CONFIG_BAUDRATE			115200
 
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 2b03841..657f751 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -112,6 +112,12 @@
 #define CONFIG_SPI_FLASH_STMICRO
 #define CONFIG_SPI_FLASH_WINBOND
 
+#define CONFIG_DM_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C_SANDBOX
+#define CONFIG_I2C_EDID
+#define CONFIG_I2C_EEPROM
+
 /* Memory things - we don't really want a memory test */
 #define CONFIG_SYS_LOAD_ADDR		0x00000000
 #define CONFIG_SYS_MEMTEST_START	0x00100000
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
index 04e4f82..5f77051 100644
--- a/include/configs/seaboard.h
+++ b/include/configs/seaboard.h
@@ -37,10 +37,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/tec-ng.h b/include/configs/tec-ng.h
index 51f87da..e37b233 100644
--- a/include/configs/tec-ng.h
+++ b/include/configs/tec-ng.h
@@ -23,12 +23,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_I2C_MULTI_BUS
-#define CONFIG_SYS_MAX_I2C_BUS		TEGRA_I2C_NUM_CONTROLLERS
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index d690045..0685328 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -26,6 +26,7 @@
 #endif
 #define CONFIG_DM_SPI
 #define CONFIG_DM_SPI_FLASH
+#define CONFIG_DM_I2C
 
 #define CONFIG_SYS_TIMER_RATE		1000000
 #define CONFIG_SYS_TIMER_COUNTER	NV_PA_TMRUS_BASE
diff --git a/include/configs/tegra114-common.h b/include/configs/tegra114-common.h
index 555c237..9eba5d5 100644
--- a/include/configs/tegra114-common.h
+++ b/include/configs/tegra114-common.h
@@ -76,9 +76,6 @@
 #define CONFIG_SYS_SPL_MALLOC_START	0x80090000
 #define CONFIG_SPL_STACK		0x800ffffc
 
-/* Total I2C ports on Tegra114 */
-#define TEGRA_I2C_NUM_CONTROLLERS	5
-
 /* For USB EHCI controller */
 #define CONFIG_EHCI_IS_TDI
 #define CONFIG_USB_EHCI_TXFIFO_THRESH	0x10
diff --git a/include/configs/tegra124-common.h b/include/configs/tegra124-common.h
index 61e5026..f2b3774 100644
--- a/include/configs/tegra124-common.h
+++ b/include/configs/tegra124-common.h
@@ -68,9 +68,6 @@
 #define CONFIG_SYS_SPL_MALLOC_START	0x80090000
 #define CONFIG_SPL_STACK		0x800ffffc
 
-/* Total I2C ports on Tegra124 */
-#define TEGRA_I2C_NUM_CONTROLLERS	5
-
 /* For USB EHCI controller */
 #define CONFIG_EHCI_IS_TDI
 #define CONFIG_USB_EHCI_TXFIFO_THRESH	0x10
diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h
index 21bf977..6330281 100644
--- a/include/configs/tegra20-common.h
+++ b/include/configs/tegra20-common.h
@@ -97,9 +97,6 @@
 #define CONFIG_EHCI_IS_TDI
 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
 
-/* Total I2C ports on Tegra20 */
-#define TEGRA_I2C_NUM_CONTROLLERS	4
-
 #define CONFIG_SYS_NAND_SELF_INIT
 #define CONFIG_SYS_NAND_ONFI_DETECTION
 
diff --git a/include/configs/tegra30-common.h b/include/configs/tegra30-common.h
index 443c842..bfdbeb7 100644
--- a/include/configs/tegra30-common.h
+++ b/include/configs/tegra30-common.h
@@ -73,9 +73,6 @@
 #define CONFIG_SYS_SPL_MALLOC_START	0x80090000
 #define CONFIG_SPL_STACK		0x800ffffc
 
-/* Total I2C ports on Tegra30 */
-#define TEGRA_I2C_NUM_CONTROLLERS	5
-
 /* For USB EHCI controller */
 #define CONFIG_EHCI_IS_TDI
 #define CONFIG_USB_EHCI_TXFIFO_THRESH	0x10
diff --git a/include/configs/trimslice.h b/include/configs/trimslice.h
index 7c00642..a254f86 100644
--- a/include/configs/trimslice.h
+++ b/include/configs/trimslice.h
@@ -34,10 +34,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/venice2.h b/include/configs/venice2.h
index 6897aa8..8880de8 100644
--- a/include/configs/venice2.h
+++ b/include/configs/venice2.h
@@ -25,12 +25,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_I2C_MULTI_BUS
-#define CONFIG_SYS_MAX_I2C_BUS		TEGRA_I2C_NUM_CONTROLLERS
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/whistler.h b/include/configs/whistler.h
index 10e70d2..e083cbd 100644
--- a/include/configs/whistler.h
+++ b/include/configs/whistler.h
@@ -26,10 +26,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 202f59b..f17c3c2 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -19,6 +19,7 @@
 	UCLASS_TEST_FDT,
 	UCLASS_TEST_BUS,
 	UCLASS_SPI_EMUL,	/* sandbox SPI device emulator */
+	UCLASS_I2C_EMUL,	/* sandbox I2C device emulator */
 	UCLASS_SIMPLE_BUS,
 
 	/* U-Boot uclasses start here */
@@ -29,6 +30,9 @@
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_CROS_EC,	/* Chrome OS EC */
 	UCLASS_THERMAL,		/* Thermal sensor */
+	UCLASS_I2C,		/* I2C bus */
+	UCLASS_I2C_GENERIC,	/* Generic I2C device */
+	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/dm/ut.h b/include/dm/ut.h
index fa9eac0..ec61465 100644
--- a/include/dm/ut.h
+++ b/include/dm/ut.h
@@ -89,6 +89,18 @@
 	}								\
 }
 
+/* Assert that a pointer is not NULL */
+#define ut_assertnonnull(expr) {					\
+	const void *val = (expr);					\
+									\
+	if (val == NULL) {						\
+		ut_failf(dms, __FILE__, __LINE__, __func__,		\
+			 #expr " = NULL",				\
+			 "Expected non-null, got NULL");		\
+		return -1;						\
+	}								\
+}
+
 /* Assert that an operation succeeds (returns 0) */
 #define ut_assertok(cond)	ut_asserteq(0, cond)
 
diff --git a/include/dt-bindings/pinctrl/pinctrl-tegra.h b/include/dt-bindings/pinctrl/pinctrl-tegra.h
new file mode 100644
index 0000000..ebafa49
--- /dev/null
+++ b/include/dt-bindings/pinctrl/pinctrl-tegra.h
@@ -0,0 +1,45 @@
+/*
+ * This header provides constants for Tegra pinctrl bindings.
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_TEGRA_H
+#define _DT_BINDINGS_PINCTRL_TEGRA_H
+
+/*
+ * Enable/disable for diffeent dt properties. This is applicable for
+ * properties nvidia,enable-input, nvidia,tristate, nvidia,open-drain,
+ * nvidia,lock, nvidia,rcv-sel, nvidia,high-speed-mode, nvidia,schmitt.
+ */
+#define TEGRA_PIN_DISABLE				0
+#define TEGRA_PIN_ENABLE				1
+
+#define TEGRA_PIN_PULL_NONE				0
+#define TEGRA_PIN_PULL_DOWN				1
+#define TEGRA_PIN_PULL_UP				2
+
+/* Low power mode driver */
+#define TEGRA_PIN_LP_DRIVE_DIV_8			0
+#define TEGRA_PIN_LP_DRIVE_DIV_4			1
+#define TEGRA_PIN_LP_DRIVE_DIV_2			2
+#define TEGRA_PIN_LP_DRIVE_DIV_1			3
+
+/* Rising/Falling slew rate */
+#define TEGRA_PIN_SLEW_RATE_FASTEST			0
+#define TEGRA_PIN_SLEW_RATE_FAST			1
+#define TEGRA_PIN_SLEW_RATE_SLOW			2
+#define TEGRA_PIN_SLEW_RATE_SLOWEST			3
+
+#endif
diff --git a/include/errno.h b/include/errno.h
index e24a33b..14ac3cb 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -6,4 +6,7 @@
 
 #define __set_errno(val) do { errno = val; } while (0)
 
+#ifdef CONFIG_ERRNO_STR
+const char *errno_str(int errno);
+#endif
 #endif /* _ERRNO_H */
diff --git a/include/i2c.h b/include/i2c.h
index 1b4078e..9c6a60c 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -18,6 +18,355 @@
 #define _I2C_H_
 
 /*
+ * For now there are essentially two parts to this file - driver model
+ * here at the top, and the older code below (with CONFIG_SYS_I2C being
+ * most recent). The plan is to migrate everything to driver model.
+ * The driver model structures and API are separate as they are different
+ * enough as to be incompatible for compilation purposes.
+ */
+
+#ifdef CONFIG_DM_I2C
+
+enum dm_i2c_chip_flags {
+	DM_I2C_CHIP_10BIT	= 1 << 0, /* Use 10-bit addressing */
+	DM_I2C_CHIP_RD_ADDRESS	= 1 << 1, /* Send address for each read byte */
+	DM_I2C_CHIP_WR_ADDRESS	= 1 << 2, /* Send address for each write byte */
+};
+
+/**
+ * struct dm_i2c_chip - information about an i2c chip
+ *
+ * An I2C chip is a device on the I2C bus. It sits at a particular address
+ * and normally supports 7-bit or 10-bit addressing.
+ *
+ * To obtain this structure, use dev_get_parentdata(dev) where dev is the
+ * chip to examine.
+ *
+ * @chip_addr:	Chip address on bus
+ * @offset_len: Length of offset in bytes. A single byte offset can
+ *		represent up to 256 bytes. A value larger than 1 may be
+ *		needed for larger devices.
+ * @flags:	Flags for this chip (dm_i2c_chip_flags)
+ * @emul: Emulator for this chip address (only used for emulation)
+ */
+struct dm_i2c_chip {
+	uint chip_addr;
+	uint offset_len;
+	uint flags;
+#ifdef CONFIG_SANDBOX
+	struct udevice *emul;
+#endif
+};
+
+/**
+ * struct dm_i2c_bus- information about an i2c bus
+ *
+ * An I2C bus contains 0 or more chips on it, each at its own address. The
+ * bus can operate at different speeds (measured in Hz, typically 100KHz
+ * or 400KHz).
+ *
+ * To obtain this structure, use bus->uclass_priv where bus is the I2C
+ * bus udevice.
+ *
+ * @speed_hz: Bus speed in hertz (typically 100000)
+ */
+struct dm_i2c_bus {
+	int speed_hz;
+};
+
+/**
+ * i2c_read() - read bytes from an I2C chip
+ *
+ * To obtain an I2C device (called a 'chip') given the I2C bus address you
+ * can use i2c_get_chip(). To obtain a bus by bus number use
+ * uclass_get_device_by_seq(UCLASS_I2C, <bus number>).
+ *
+ * To set the address length of a devce use i2c_set_addr_len(). It
+ * defaults to 1.
+ *
+ * @dev:	Chip to read from
+ * @offset:	Offset within chip to start reading
+ * @buffer:	Place to put data
+ * @len:	Number of bytes to read
+ *
+ * @return 0 on success, -ve on failure
+ */
+int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer,
+	     int len);
+
+/**
+ * i2c_write() - write bytes to an I2C chip
+ *
+ * See notes for i2c_read() above.
+ *
+ * @dev:	Chip to write to
+ * @offset:	Offset within chip to start writing
+ * @buffer:	Buffer containing data to write
+ * @len:	Number of bytes to write
+ *
+ * @return 0 on success, -ve on failure
+ */
+int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
+	      int len);
+
+/**
+ * i2c_probe() - probe a particular chip address
+ *
+ * This can be useful to check for the existence of a chip on the bus.
+ * It is typically implemented by writing the chip address to the bus
+ * and checking that the chip replies with an ACK.
+ *
+ * @bus:	Bus to probe
+ * @chip_addr:	7-bit address to probe (10-bit and others are not supported)
+ * @chip_flags:	Flags for the probe (see enum dm_i2c_chip_flags)
+ * @devp:	Returns the device found, or NULL if none
+ * @return 0 if a chip was found at that address, -ve if not
+ */
+int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
+	      struct udevice **devp);
+
+/**
+ * i2c_set_bus_speed() - set the speed of a bus
+ *
+ * @bus:	Bus to adjust
+ * @speed:	Requested speed in Hz
+ * @return 0 if OK, -EINVAL for invalid values
+ */
+int i2c_set_bus_speed(struct udevice *bus, unsigned int speed);
+
+/**
+ * i2c_get_bus_speed() - get the speed of a bus
+ *
+ * @bus:	Bus to check
+ * @return speed of selected I2C bus in Hz, -ve on error
+ */
+int i2c_get_bus_speed(struct udevice *bus);
+
+/**
+ * i2c_set_chip_flags() - set flags for a chip
+ *
+ * Typically addresses are 7 bits, but for 10-bit addresses you should set
+ * flags to DM_I2C_CHIP_10BIT. All accesses will then use 10-bit addressing.
+ *
+ * @dev:	Chip to adjust
+ * @flags:	New flags
+ * @return 0 if OK, -EINVAL if value is unsupported, other -ve value on error
+ */
+int i2c_set_chip_flags(struct udevice *dev, uint flags);
+
+/**
+ * i2c_get_chip_flags() - get flags for a chip
+ *
+ * @dev:	Chip to check
+ * @flagsp:	Place to put flags
+ * @return 0 if OK, other -ve value on error
+ */
+int i2c_get_chip_flags(struct udevice *dev, uint *flagsp);
+
+/**
+ * i2c_set_offset_len() - set the offset length for a chip
+ *
+ * The offset used to access a chip may be up to 4 bytes long. Typically it
+ * is only 1 byte, which is enough for chips with 256 bytes of memory or
+ * registers. The default value is 1, but you can call this function to
+ * change it.
+ *
+ * @offset_len:	New offset length value (typically 1 or 2)
+ */
+
+int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len);
+/**
+ * i2c_deblock() - recover a bus that is in an unknown state
+ *
+ * See the deblock() method in 'struct dm_i2c_ops' for full information
+ *
+ * @bus:	Bus to recover
+ * @return 0 if OK, -ve on error
+ */
+int i2c_deblock(struct udevice *bus);
+
+/*
+ * Not all of these flags are implemented in the U-Boot API
+ */
+enum dm_i2c_msg_flags {
+	I2C_M_TEN		= 0x0010, /* ten-bit chip address */
+	I2C_M_RD		= 0x0001, /* read data, from slave to master */
+	I2C_M_STOP		= 0x8000, /* send stop after this message */
+	I2C_M_NOSTART		= 0x4000, /* no start before this message */
+	I2C_M_REV_DIR_ADDR	= 0x2000, /* invert polarity of R/W bit */
+	I2C_M_IGNORE_NAK	= 0x1000, /* continue after NAK */
+	I2C_M_NO_RD_ACK		= 0x0800, /* skip the Ack bit on reads */
+	I2C_M_RECV_LEN		= 0x0400, /* length is first received byte */
+};
+
+/**
+ * struct i2c_msg - an I2C message
+ *
+ * @addr:	Slave address
+ * @flags:	Flags (see enum dm_i2c_msg_flags)
+ * @len:	Length of buffer in bytes, may be 0 for a probe
+ * @buf:	Buffer to send/receive, or NULL if no data
+ */
+struct i2c_msg {
+	uint addr;
+	uint flags;
+	uint len;
+	u8 *buf;
+};
+
+/**
+ * struct i2c_msg_list - a list of I2C messages
+ *
+ * This is called i2c_rdwr_ioctl_data in Linux but the name does not seem
+ * appropriate in U-Boot.
+ *
+ * @msg:	Pointer to i2c_msg array
+ * @nmsgs:	Number of elements in the array
+ */
+struct i2c_msg_list {
+	struct i2c_msg *msgs;
+	uint nmsgs;
+};
+
+/**
+ * struct dm_i2c_ops - driver operations for I2C uclass
+ *
+ * Drivers should support these operations unless otherwise noted. These
+ * operations are intended to be used by uclass code, not directly from
+ * other code.
+ */
+struct dm_i2c_ops {
+	/**
+	 * xfer() - transfer a list of I2C messages
+	 *
+	 * @bus:	Bus to read from
+	 * @msg:	List of messages to transfer
+	 * @nmsgs:	Number of messages in the list
+	 * @return 0 if OK, -EREMOTEIO if the slave did not ACK a byte,
+	 *	-ECOMM if the speed cannot be supported, -EPROTO if the chip
+	 *	flags cannot be supported, other -ve value on some other error
+	 */
+	int (*xfer)(struct udevice *bus, struct i2c_msg *msg, int nmsgs);
+
+	/**
+	 * probe_chip() - probe for the presense of a chip address
+	 *
+	 * This function is optional. If omitted, the uclass will send a zero
+	 * length message instead.
+	 *
+	 * @bus:	Bus to probe
+	 * @chip_addr:	Chip address to probe
+	 * @chip_flags:	Probe flags (enum dm_i2c_chip_flags)
+	 * @return 0 if chip was found, -EREMOTEIO if not, -ENOSYS to fall back
+	 * to default probem other -ve value on error
+	 */
+	int (*probe_chip)(struct udevice *bus, uint chip_addr, uint chip_flags);
+
+	/**
+	 * set_bus_speed() - set the speed of a bus (optional)
+	 *
+	 * The bus speed value will be updated by the uclass if this function
+	 * does not return an error. This method is optional - if it is not
+	 * provided then the driver can read the speed from
+	 * bus->uclass_priv->speed_hz
+	 *
+	 * @bus:	Bus to adjust
+	 * @speed:	Requested speed in Hz
+	 * @return 0 if OK, -EINVAL for invalid values
+	 */
+	int (*set_bus_speed)(struct udevice *bus, unsigned int speed);
+
+	/**
+	 * get_bus_speed() - get the speed of a bus (optional)
+	 *
+	 * Normally this can be provided by the uclass, but if you want your
+	 * driver to check the bus speed by looking at the hardware, you can
+	 * implement that here. This method is optional. This method would
+	 * normally be expected to return bus->uclass_priv->speed_hz.
+	 *
+	 * @bus:	Bus to check
+	 * @return speed of selected I2C bus in Hz, -ve on error
+	 */
+	int (*get_bus_speed)(struct udevice *bus);
+
+	/**
+	 * set_flags() - set the flags for a chip (optional)
+	 *
+	 * This is generally implemented by the uclass, but drivers can
+	 * check the value to ensure that unsupported options are not used.
+	 * This method is optional. If provided, this method will always be
+	 * called when the flags change.
+	 *
+	 * @dev:	Chip to adjust
+	 * @flags:	New flags value
+	 * @return 0 if OK, -EINVAL if value is unsupported
+	 */
+	int (*set_flags)(struct udevice *dev, uint flags);
+
+	/**
+	 * deblock() - recover a bus that is in an unknown state
+	 *
+	 * I2C is a synchronous protocol and resets of the processor in the
+	 * middle of an access can block the I2C Bus until a powerdown of
+	 * the full unit is done. This is because slaves can be stuck
+	 * waiting for addition bus transitions for a transaction that will
+	 * never complete. Resetting the I2C master does not help. The only
+	 * way is to force the bus through a series of transitions to make
+	 * sure that all slaves are done with the transaction. This method
+	 * performs this 'deblocking' if support by the driver.
+	 *
+	 * This method is optional.
+	 */
+	int (*deblock)(struct udevice *bus);
+};
+
+#define i2c_get_ops(dev)	((struct dm_i2c_ops *)(dev)->driver->ops)
+
+/**
+ * i2c_get_chip() - get a device to use to access a chip on a bus
+ *
+ * This returns the device for the given chip address. The device can then
+ * be used with calls to i2c_read(), i2c_write(), i2c_probe(), etc.
+ *
+ * @bus:	Bus to examine
+ * @chip_addr:	Chip address for the new device
+ * @devp:	Returns pointer to new device if found or -ENODEV if not
+ *		found
+ */
+int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp);
+
+/**
+ * i2c_get_chip() - get a device to use to access a chip on a bus number
+ *
+ * This returns the device for the given chip address on a particular bus
+ * number.
+ *
+ * @busnum:	Bus number to examine
+ * @chip_addr:	Chip address for the new device
+ * @devp:	Returns pointer to new device if found or -ENODEV if not
+ *		found
+ */
+int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp);
+
+/**
+ * i2c_chip_ofdata_to_platdata() - Decode standard I2C platform data
+ *
+ * This decodes the chip address from a device tree node and puts it into
+ * its dm_i2c_chip structure. This should be called in your driver's
+ * ofdata_to_platdata() method.
+ *
+ * @blob:	Device tree blob
+ * @node:	Node offset to read from
+ * @spi:	Place to put the decoded information
+ */
+int i2c_chip_ofdata_to_platdata(const void *blob, int node,
+				struct dm_i2c_chip *chip);
+
+#endif
+
+#ifndef CONFIG_DM_I2C
+
+/*
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
  *
  * The implementation MUST NOT use static or global variables if the
@@ -451,4 +800,7 @@
  * @return 0 if port was reset, -1 if not found
  */
 int i2c_reset_port_fdt(const void *blob, int node);
+
+#endif /* !CONFIG_DM_I2C */
+
 #endif	/* _I2C_H_ */
diff --git a/include/i2c_eeprom.h b/include/i2c_eeprom.h
new file mode 100644
index 0000000..ea6c962
--- /dev/null
+++ b/include/i2c_eeprom.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __I2C_EEPROM
+#define __I2C_EEPROM
+
+struct i2c_eeprom_ops {
+	int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size);
+	int (*write)(struct udevice *dev, int offset, const uint8_t *buf,
+		     int size);
+};
+
+struct i2c_eeprom {
+};
+
+#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index 96348d6..c7047ba 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -30,6 +30,9 @@
 #ifndef __HAVE_ARCH_STRNCPY
 extern char * strncpy(char *,const char *, __kernel_size_t);
 #endif
+#ifndef __HAVE_ARCH_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
 #ifndef __HAVE_ARCH_STRCAT
 extern char * strcat(char *, const char *);
 #endif
diff --git a/include/tps6586x.h b/include/tps6586x.h
index 78ce428..eefc95f 100644
--- a/include/tps6586x.h
+++ b/include/tps6586x.h
@@ -44,9 +44,9 @@
  * Set up the TPS6586X I2C bus number. This will be used for all operations
  * on the device. This function must be called before using other functions.
  *
- * @param bus	I2C bus number containing the TPS6586X chip
+ * @param bus	I2C bus containing the TPS6586X chip
  * @return 0 (always succeeds)
  */
-int tps6586x_init(int bus);
+int tps6586x_init(struct udevice *bus);
 
 #endif	/* _TPS6586X_H_ */
diff --git a/lib/Makefile b/lib/Makefile
index 3ceb697..07d175f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -51,6 +51,7 @@
 obj-$(CONFIG_ADDR_MAP) += addr_map.o
 obj-y += hashtable.o
 obj-y += errno.o
+obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-y += display_options.o
 obj-$(CONFIG_BCH) += bch.o
 obj-y += crc32.o
diff --git a/lib/errno_str.c b/lib/errno_str.c
new file mode 100644
index 0000000..0ba950e
--- /dev/null
+++ b/lib/errno_str.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SDPX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+
+#define ERRNO_MSG(errno, msg)	msg
+#define SAME_AS(x)		(const char *)&errno_message[x]
+
+static const char * const errno_message[] = {
+	ERRNO_MSG(0, "Success"),
+	ERRNO_MSG(EPERM, "Operation not permitted"),
+	ERRNO_MSG(ENOEN, "No such file or directory"),
+	ERRNO_MSG(ESRCH, "No such process"),
+	ERRNO_MSG(EINTR, "Interrupted system call"),
+	ERRNO_MSG(EIO, "I/O error"),
+	ERRNO_MSG(ENXIO, "No such device or address"),
+	ERRNO_MSG(E2BIG, "Argument list too long"),
+	ERRNO_MSG(ENOEXEC, "Exec format error"),
+	ERRNO_MSG(EBADF, "Bad file number"),
+	ERRNO_MSG(ECHILD, "No child processes"),
+	ERRNO_MSG(EAGAIN, "Try again"),
+	ERRNO_MSG(ENOMEM, "Out of memory"),
+	ERRNO_MSG(EACCES, "Permission denied"),
+	ERRNO_MSG(EFAULT, "Bad address"),
+	ERRNO_MSG(ENOTBL, "Block device required"),
+	ERRNO_MSG(EBUSY, "Device or resource busy"),
+	ERRNO_MSG(EEXIST, "File exists"),
+	ERRNO_MSG(EXDEV, "Cross-device link"),
+	ERRNO_MSG(ENODEV, "No such device"),
+	ERRNO_MSG(ENOTDIR, "Not a directory"),
+	ERRNO_MSG(EISDIR, "Is a directory"),
+	ERRNO_MSG(EINVAL, "Invalid argument"),
+	ERRNO_MSG(ENFILE, "File table overflow"),
+	ERRNO_MSG(EMFILE, "Too many open files"),
+	ERRNO_MSG(ENOTTY, "Not a typewriter"),
+	ERRNO_MSG(ETXTBSY, "Text file busy"),
+	ERRNO_MSG(EFBIG, "File too large"),
+	ERRNO_MSG(ENOSPC, "No space left on device"),
+	ERRNO_MSG(ESPIPE, "Illegal seek"),
+	ERRNO_MSG(EROFS, "Read-only file system"),
+	ERRNO_MSG(EMLINK, "Too many links"),
+	ERRNO_MSG(EPIPE, "Broken pipe"),
+	ERRNO_MSG(EDOM, "Math argument out of domain of func"),
+	ERRNO_MSG(ERANGE, "Math result not representable"),
+	ERRNO_MSG(EDEADLK, "Resource deadlock would occur"),
+	ERRNO_MSG(ENAMETOOLONG, "File name too long"),
+	ERRNO_MSG(ENOLCK, "No record locks available"),
+	ERRNO_MSG(ENOSYS, "Function not implemented"),
+	ERRNO_MSG(ENOTEMPTY, "Directory not empty"),
+	ERRNO_MSG(ELOOP, "Too many symbolic links encountered"),
+	ERRNO_MSG(EWOULDBLOCK, SAME_AS(EAGAIN)),
+	ERRNO_MSG(ENOMSG, "No message of desired type"),
+	ERRNO_MSG(EIDRM, "Identifier removed"),
+	ERRNO_MSG(ECHRNG, "Channel number out of range"),
+	ERRNO_MSG(EL2NSYNC, "Level 2 not synchronized"),
+	ERRNO_MSG(EL3HLT, "Level 3 halted"),
+	ERRNO_MSG(EL3RST, "Level 3 reset"),
+	ERRNO_MSG(ELNRNG, "Link number out of range"),
+	ERRNO_MSG(EUNATCH, "Protocol driver not attached"),
+	ERRNO_MSG(ENOCSI, "No CSI structure available"),
+	ERRNO_MSG(EL2HLT, "Level 2 halted"),
+	ERRNO_MSG(EBADE, "Invalid exchange"),
+	ERRNO_MSG(EBADR, "Invalid request descriptor"),
+	ERRNO_MSG(EXFULL, "Exchange full"),
+	ERRNO_MSG(ENOANO, "No anode"),
+	ERRNO_MSG(EBADRQC, "Invalid request code"),
+	ERRNO_MSG(EBADSLT, "Invalid slot"),
+	ERRNO_MSG(EDEADLOCK, SAME_AS(EDEADLK)),
+	ERRNO_MSG(EBFONT, "Bad font file format"),
+	ERRNO_MSG(ENOSTR, "Device not a stream"),
+	ERRNO_MSG(ENODATA, "No data available"),
+	ERRNO_MSG(ETIME, "Timer expired"),
+	ERRNO_MSG(ENOSR, "Out of streams resources"),
+	ERRNO_MSG(ENONET, "Machine is not on the network"),
+	ERRNO_MSG(ENOPKG, "Package not installed"),
+	ERRNO_MSG(EREMOTE, "Object is remote"),
+	ERRNO_MSG(ENOLINK, "Link has been severed"),
+	ERRNO_MSG(EADV, "Advertise error"),
+	ERRNO_MSG(ESRMNT, "Srmount error"),
+	ERRNO_MSG(ECOMM, "Communication error on send"),
+	ERRNO_MSG(EPROTO, "Protocol error"),
+	ERRNO_MSG(EMULTIHOP, "Multihop attempted"),
+	ERRNO_MSG(EDOTDOT, "RFS specific error"),
+	ERRNO_MSG(EBADMSG, "Not a data message"),
+	ERRNO_MSG(EOVERFLOW, "Value too large for defined data type"),
+	ERRNO_MSG(ENOTUNIQ, "Name not unique on network"),
+	ERRNO_MSG(EBADFD, "File descriptor in bad state"),
+	ERRNO_MSG(EREMCHG, "Remote address changed"),
+	ERRNO_MSG(ELIBACC, "Can not access a needed shared library"),
+	ERRNO_MSG(ELIBBAD, "Accessing a corrupted shared library"),
+	ERRNO_MSG(ELIBSCN, ".lib section in a.out corrupted"),
+	ERRNO_MSG(ELIBMAX, "Attempting to link in too many shared libraries"),
+	ERRNO_MSG(ELIBEXEC, "Cannot exec a shared library directly"),
+	ERRNO_MSG(EILSEQ, "Illegal byte sequence"),
+	ERRNO_MSG(ERESTART, "Interrupted system call should be restarted"),
+	ERRNO_MSG(ESTRPIPE, "Streams pipe error"),
+	ERRNO_MSG(EUSERS, "Too many users"),
+	ERRNO_MSG(ENOTSOCK, "Socket operation on non-socket"),
+	ERRNO_MSG(EDESTADDRREQ, "Destination address required"),
+	ERRNO_MSG(EMSGSIZE, "Message too long"),
+	ERRNO_MSG(EPROTOTYPE, "Protocol wrong type for socket"),
+	ERRNO_MSG(ENOPROTOOPT, "Protocol not available"),
+	ERRNO_MSG(EPROTONOSUPPORT, "Protocol not supported"),
+	ERRNO_MSG(ESOCKTNOSUPPORT, "Socket type not supported"),
+	ERRNO_MSG(EOPNOTSUPP, "Operation not supported on transport endpoint"),
+	ERRNO_MSG(EPFNOSUPPORT, "Protocol family not supported"),
+	ERRNO_MSG(AFNOSUPPORT, "Address family not supported by protocol"),
+	ERRNO_MSG(EADDRINUSE, "Address already in use"),
+	ERRNO_MSG(EADDRNOTAVAIL, "Cannot assign requested address"),
+	ERRNO_MSG(ENETDOWN, "Network is down"),
+	ERRNO_MSG(ENETUNREACH, "Network is unreachable"),
+	ERRNO_MSG(ENETRESET, "Network dropped connection because of reset"),
+	ERRNO_MSG(ECONNABORTED, "Software caused connection abort"),
+	ERRNO_MSG(ECONNRESET, "Connection reset by peer"),
+	ERRNO_MSG(ENOBUFS, "No buffer space available"),
+	ERRNO_MSG(EISCONN, "Transport endpoint is already connected"),
+	ERRNO_MSG(ENOTCONN, "Transport endpoint is not connected"),
+	ERRNO_MSG(ESHUTDOWN, "Cannot send after transport endpoint shutdown"),
+	ERRNO_MSG(ETOOMANYREFS, "Too many references: cannot splice"),
+	ERRNO_MSG(ETIMEDOUT, "Connection timed out"),
+	ERRNO_MSG(ECONNREFUSED, "Connection refused"),
+	ERRNO_MSG(EHOSTDOWN, "Host is down"),
+	ERRNO_MSG(EHOSTUNREACH, "No route to host"),
+	ERRNO_MSG(EALREADY, "Operation already in progress"),
+	ERRNO_MSG(EINPROGRESS, "Operation now in progress"),
+	ERRNO_MSG(ESTALE, "Stale NFS file handle"),
+	ERRNO_MSG(EUCLEAN, "Structure needs cleaning"),
+	ERRNO_MSG(ENOTNAM, "Not a XENIX named type file"),
+	ERRNO_MSG(ENAVAIL, "No XENIX semaphores available"),
+	ERRNO_MSG(EISNAM, "Is a named type file"),
+	ERRNO_MSG(EREMOTEIO, "Remote I/O error"),
+	ERRNO_MSG(EDQUOT, "Quota exceeded"),
+	ERRNO_MSG(ENOMEDIUM, "No medium found"),
+	ERRNO_MSG(EMEDIUMTYPE, "Wrong medium type"),
+};
+
+const char *errno_str(int errno)
+{
+	if (errno >= 0)
+		return errno_message[0];
+
+	return errno_message[abs(errno)];
+}
diff --git a/lib/string.c b/lib/string.c
index 29c2ca7..87c9a40 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -102,6 +102,31 @@
 }
 #endif
 
+#ifndef __HAVE_ARCH_STRLCPY
+/**
+ * strlcpy - Copy a C-string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+	size_t ret = strlen(src);
+
+	if (size) {
+		size_t len = (ret >= size) ? size - 1 : ret;
+		memcpy(dest, src, len);
+		dest[len] = '\0';
+	}
+	return ret;
+}
+#endif
+
 #ifndef __HAVE_ARCH_STRCAT
 /**
  * strcat - Append one %NUL-terminated string to another
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 75d3d41..612aa95 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -20,4 +20,5 @@
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_SPI) += spi.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
+obj-$(CONFIG_DM_I2C) += i2c.o
 endif
diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 26980d2..79a674e 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -16,59 +16,38 @@
 #include <dm/test.h>
 #include <dm/uclass-internal.h>
 
-/**
- * dm_display_line() - Display information about a single device
- *
- * Displays a single line of information with an option prefix
- *
- * @dev:	Device to display
- * @buf:	Prefix to display at the start of the line
- */
-static void dm_display_line(struct udevice *dev, char *buf)
+static void show_devices(struct udevice *dev, int depth, int last_flag)
 {
-	printf("%s- %c %s @ %08lx", buf,
-	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
-	       dev->name, (ulong)map_to_sysmem(dev));
-	if (dev->req_seq != -1)
-		printf(", %d", dev->req_seq);
-	puts("\n");
-}
+	int i, is_last;
+	struct udevice *child;
+	char class_name[12];
 
-static int display_succ(struct udevice *in, char *buf)
-{
-	int len;
-	int ip = 0;
-	char local[16];
-	struct udevice *pos, *n, *prev = NULL;
+	/* print the first 11 characters to not break the tree-format. */
+	strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
+	printf(" %-11s [ %c ]    ", class_name,
+	       dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
 
-	dm_display_line(in, buf);
-
-	if (list_empty(&in->child_head))
-		return 0;
-
-	len = strlen(buf);
-	strncpy(local, buf, sizeof(local));
-	snprintf(local + len, 2, "|");
-	if (len && local[len - 1] == '`')
-		local[len - 1] = ' ';
-
-	list_for_each_entry_safe(pos, n, &in->child_head, sibling_node) {
-		if (ip++)
-			display_succ(prev, local);
-		prev = pos;
+	for (i = depth; i >= 0; i--) {
+		is_last = (last_flag >> i) & 1;
+		if (i) {
+			if (is_last)
+				printf("    ");
+			else
+				printf("|   ");
+		} else {
+			if (is_last)
+				printf("`-- ");
+			else
+				printf("|-- ");
+		}
 	}
 
-	snprintf(local + len, 2, "`");
-	display_succ(prev, local);
+	printf("%s\n", dev->name);
 
-	return 0;
-}
-
-static int dm_dump(struct udevice *dev)
-{
-	if (!dev)
-		return -EINVAL;
-	return display_succ(dev, "");
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		is_last = list_is_last(&child->sibling_node, &dev->child_head);
+		show_devices(child, depth + 1, (last_flag << 1) | is_last);
+	}
 }
 
 static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc,
@@ -77,8 +56,30 @@
 	struct udevice *root;
 
 	root = dm_root();
-	printf("ROOT %08lx\n", (ulong)map_to_sysmem(root));
-	return dm_dump(root);
+	if (root) {
+		printf(" Class       Probed   Name\n");
+		printf("----------------------------------------\n");
+		show_devices(root, -1, 0);
+	}
+
+	return 0;
+}
+
+/**
+ * dm_display_line() - Display information about a single device
+ *
+ * Displays a single line of information with an option prefix
+ *
+ * @dev:	Device to display
+ */
+static void dm_display_line(struct udevice *dev)
+{
+	printf("- %c %s @ %08lx",
+	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
+	       dev->name, (ulong)map_to_sysmem(dev));
+	if (dev->req_seq != -1)
+		printf(", %d", dev->req_seq);
+	puts("\n");
 }
 
 static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
@@ -99,7 +100,7 @@
 		if (list_empty(&uc->dev_head))
 			continue;
 		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
-			dm_display_line(dev, "");
+			dm_display_line(dev);
 		}
 		puts("\n");
 	}
diff --git a/test/dm/i2c.c b/test/dm/i2c.c
new file mode 100644
index 0000000..a53e28d
--- /dev/null
+++ b/test/dm/i2c.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Note: Test coverage does not include 10-bit addressing
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <dm/device-internal.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <dm/ut.h>
+#include <dm/util.h>
+#include <asm/state.h>
+#include <asm/test.h>
+
+static const int busnum;
+static const int chip = 0x2c;
+
+/* Test that we can find buses and chips */
+static int dm_test_i2c_find(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	const int no_chip = 0x10;
+
+	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_I2C, busnum,
+						       false, &bus));
+
+	/*
+	 * i2c_post_bind() will bind devices to chip selects. Check this then
+	 * remove the emulation and the slave device.
+	 */
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_probe(bus, chip, 0, &dev));
+	ut_asserteq(-ENODEV, i2c_probe(bus, no_chip, 0, &dev));
+	ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_I2C, 1, &bus));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_read_write(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	uint8_t buf[5];
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf)));
+	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0AB\0", sizeof(buf)));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_read_write, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_speed(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	uint8_t buf[5];
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_set_bus_speed(bus, 100000));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(i2c_set_bus_speed(bus, 400000));
+	ut_asserteq(400000, i2c_get_bus_speed(bus));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_asserteq(-EINVAL, i2c_write(dev, 0, buf, 5));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_speed, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_offset_len(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	uint8_t buf[5];
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_set_chip_offset_len(dev, 1));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+
+	/* This is not supported by the uclass */
+	ut_asserteq(-EINVAL, i2c_set_chip_offset_len(dev, 5));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_offset_len, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_probe_empty(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_probe_empty, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_bytewise(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	struct udevice *eeprom;
+	uint8_t buf[5];
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf)));
+
+	/* Tell the EEPROM to only read/write one register at a time */
+	ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom));
+	ut_assertnonnull(eeprom);
+	sandbox_i2c_eeprom_set_test_mode(eeprom, SIE_TEST_MODE_SINGLE_BYTE);
+
+	/* Now we only get the first byte - the rest will be 0xff */
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf)));
+
+	/* If we do a separate transaction for each byte, it works */
+	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf)));
+
+	/* This will only write A */
+	ut_assertok(i2c_set_chip_flags(dev, 0));
+	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf)));
+
+	/* Check that the B was ignored */
+	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0A\0\0\0", sizeof(buf)));
+
+	/* Now write it again with the new flags, it should work */
+	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS));
+	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf)));
+
+	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS |
+						DM_I2C_CHIP_RD_ADDRESS));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0AB\0\0", sizeof(buf)));
+
+	/* Restore defaults */
+	sandbox_i2c_eeprom_set_test_mode(eeprom, SIE_TEST_MODE_NONE);
+	ut_assertok(i2c_set_chip_flags(dev, 0));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_bytewise, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_offset(struct dm_test_state *dms)
+{
+	struct udevice *eeprom;
+	struct udevice *dev;
+	uint8_t buf[5];
+
+	ut_assertok(i2c_get_chip_for_busnum(busnum, chip, &dev));
+
+	/* Do a transfer so we can find the emulator */
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom));
+
+	/* Offset length 0 */
+	sandbox_i2c_eeprom_set_offset_len(eeprom, 0);
+	ut_assertok(i2c_set_chip_offset_len(dev, 0));
+	ut_assertok(i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "AB\0\0\0\0", sizeof(buf)));
+
+	/* Offset length 1 */
+	sandbox_i2c_eeprom_set_offset_len(eeprom, 1);
+	ut_assertok(i2c_set_chip_offset_len(dev, 1));
+	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "ABAB\0", sizeof(buf)));
+
+	/* Offset length 2 */
+	sandbox_i2c_eeprom_set_offset_len(eeprom, 2);
+	ut_assertok(i2c_set_chip_offset_len(dev, 2));
+	ut_assertok(i2c_write(dev, 0x210, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0x210, buf, 5));
+	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf)));
+
+	/* Offset length 3 */
+	sandbox_i2c_eeprom_set_offset_len(eeprom, 2);
+	ut_assertok(i2c_set_chip_offset_len(dev, 2));
+	ut_assertok(i2c_write(dev, 0x410, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0x410, buf, 5));
+	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf)));
+
+	/* Offset length 4 */
+	sandbox_i2c_eeprom_set_offset_len(eeprom, 2);
+	ut_assertok(i2c_set_chip_offset_len(dev, 2));
+	ut_assertok(i2c_write(dev, 0x420, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0x420, buf, 5));
+	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf)));
+
+	/* Restore defaults */
+	sandbox_i2c_eeprom_set_offset_len(eeprom, 1);
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test.dts b/test/dm/test.dts
index 1fba792..fb0272a 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -93,6 +93,23 @@
 		num-gpios = <10>;
 	};
 
+	i2c@0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		compatible = "sandbox,i2c";
+		clock-frequency = <100000>;
+		eeprom@2c {
+			reg = <0x2c>;
+			compatible = "i2c-eeprom";
+			emul {
+				compatible = "sandbox,i2c-eeprom";
+				sandbox,filename = "i2c.bin";
+				sandbox,size = <256>;
+			};
+		};
+	};
+
 	spi@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;