Merge git://git.denx.de/u-boot-dm
diff --git a/README b/README
index a52ff46..1acc355 100644
--- a/README
+++ b/README
@@ -1494,12 +1494,6 @@
 		Support for i2c bus TPM devices. Only one device
 		per system is supported at this time.
 
-			CONFIG_TPM_TIS_I2C_BUS_NUMBER
-			Define the the i2c bus number for the TPM device
-
-			CONFIG_TPM_TIS_I2C_SLAVE_ADDRESS
-			Define the TPM's address on the i2c bus
-
 			CONFIG_TPM_TIS_I2C_BURST_LIMITATION
 			Define the burst count bytes upper limit
 
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts
index 32c0098..bda5499 100644
--- a/arch/arm/dts/exynos5250-snow.dts
+++ b/arch/arm/dts/exynos5250-snow.dts
@@ -206,6 +206,15 @@
 		};
 	};
 
+	i2c@12C90000 {
+		clock-frequency = <100000>;
+		tpm@20 {
+			reg = <0x20>;
+			u-boot,i2c-offset-len = <0>;
+			compatible = "infineon,slb9635tt";
+		};
+	};
+
 	spi@12d30000 {
 		spi-max-frequency = <50000000>;
 		firmware_storage_spi: flash@0 {
diff --git a/arch/arm/dts/exynos5250-spring.dts b/arch/arm/dts/exynos5250-spring.dts
index 76d5323..81b3d29 100644
--- a/arch/arm/dts/exynos5250-spring.dts
+++ b/arch/arm/dts/exynos5250-spring.dts
@@ -59,6 +59,14 @@
 					 <&gpy4 2 0>;
 	};
 
+	i2c@12C90000 {
+		clock-frequency = <100000>;
+		tpm@20 {
+			reg = <0x20>;
+			compatible = "infineon,slb9645tt";
+		};
+	};
+
 	mmc@12200000 {
 		samsung,bus-width = <8>;
 		samsung,timing = <1 3 3>;
diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts
index 2d2b7c9..16d52f4 100644
--- a/arch/arm/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/dts/exynos5420-peach-pit.dts
@@ -197,9 +197,9 @@
 
 	i2c@12E10000 { /* i2c9 */
 		clock-frequency = <400000>;
-                tpm@20 {
-                        compatible = "infineon,slb9645tt";
-                        reg = <0x20>;
+		tpm@20 {
+			compatible = "infineon,slb9645tt";
+			reg = <0x20>;
 		};
 	};
 
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts
index 600c294..1d7ff23 100644
--- a/arch/arm/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/dts/exynos5800-peach-pi.dts
@@ -72,9 +72,9 @@
 
 	i2c@12E10000 { /* i2c9 */
 		clock-frequency = <400000>;
-                tpm@20 {
-                        compatible = "infineon,slb9645tt";
-                        reg = <0x20>;
+		tpm@20 {
+			compatible = "infineon,slb9645tt";
+			reg = <0x20>;
 		};
 	};
 
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 8927527..65b9125 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -92,6 +92,8 @@
 		reg = <0 0>;
 		compatible = "sandbox,i2c";
 		clock-frequency = <400000>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_i2c0>;
 		eeprom@2c {
 			reg = <0x2c>;
 			compatible = "i2c-eeprom";
@@ -136,6 +138,21 @@
 		};
 	};
 
+	pinctrl {
+		compatible = "sandbox,pinctrl";
+
+		pinctrl_i2c0: i2c0 {
+			groups = "i2c";
+			function = "i2c";
+			bias-pull-up;
+		};
+
+		pinctrl_serial0: uart0 {
+			groups = "serial_a";
+			function = "serial";
+		};
+	};
+
 	spi@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -156,6 +173,10 @@
 		sides = <4>;
 	};
 
+	tpm {
+		compatible = "google,sandbox-tpm";
+	};
+
 	triangle {
 		compatible = "demo-shape";
 		colour = "cyan";
@@ -168,6 +189,8 @@
 	uart0: serial {
 		compatible = "sandbox,serial";
 		sandbox,text-colour = "cyan";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_serial0>;
 	};
 
 	usb@0 {
diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts
index ad390bf..4291141 100644
--- a/arch/x86/dts/chromebook_link.dts
+++ b/arch/x86/dts/chromebook_link.dts
@@ -237,6 +237,11 @@
 		};
 	};
 
+	tpm {
+		reg = <0xfed40000 0x5000>;
+		compatible = "infineon,slb9635lpc";
+	};
+
 	microcode {
 		update@0 {
 #include "microcode/m12306a9_0000001b.dtsi"
diff --git a/arch/x86/dts/chromebox_panther.dts b/arch/x86/dts/chromebox_panther.dts
index 84eae3a..36feb96 100644
--- a/arch/x86/dts/chromebox_panther.dts
+++ b/arch/x86/dts/chromebox_panther.dts
@@ -62,4 +62,9 @@
 		};
 	};
 
+	tpm {
+		reg = <0xfed40000 0x5000>;
+		compatible = "infineon,slb9635lpc";
+	};
+
 };
diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c
index 7d1b88a..4250f72 100644
--- a/board/samsung/common/exynos5-dt.c
+++ b/board/samsung/common/exynos5-dt.c
@@ -121,11 +121,12 @@
 		return ret;
 
 	/*
-	 * This would normally be 1.3V, but since we are running slowly 1V
+	 * This would normally be 1.3V, but since we are running slowly 1.1V
 	 * is enough. For spring it helps reduce CPU temperature and avoid
-	 * hangs with the case open.
+	 * hangs with the case open. 1.1V is minimum voltage borderline for
+	 * chained bootloaders.
 	 */
-	ret = exynos_set_regulator("vdd_arm", 1000000);
+	ret = exynos_set_regulator("vdd_arm", 1100000);
 	if (ret)
 		return ret;
 	ret = exynos_set_regulator("vdd_int", 1012500);
diff --git a/common/Kconfig b/common/Kconfig
index 88dc016..2c42b8e 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -625,4 +625,26 @@
 
 endmenu
 
+menu "Security commands"
+config CMD_TPM
+	bool "Enable the 'tpm' command"
+	depends on TPM
+	help
+	  This provides a means to talk to a TPM from the command line. A wide
+	  range of commands if provided - see 'tpm help' for details. The
+	  command requires a suitable TPM on your board and the correct driver
+	  must be enabled.
+
+config CMD_TPM_TEST
+	bool "Enable the 'tpm test' command"
+	depends on CMD_TPM
+	help
+	  This provides a a series of tests to confirm that the TPM is working
+	  correctly. The tests cover initialisation, non-volatile RAM, extend,
+	  global lock and checking that timing is within expectations. The
+	  tests pass correctly on Infineon TPMs but may need to be adjusted
+	  for other devices.
+
+endmenu
+
 endmenu
diff --git a/common/Makefile b/common/Makefile
index dc82433..f4ba878 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -169,6 +169,7 @@
 obj-$(CONFIG_CMD_TRACE) += cmd_trace.o
 obj-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o
 obj-$(CONFIG_CMD_TPM) += cmd_tpm.o
+obj-$(CONFIG_CMD_TPM_TEST) += cmd_tpm_test.o
 obj-$(CONFIG_CMD_TSI148) += cmd_tsi148.o
 obj-$(CONFIG_CMD_UBI) += cmd_ubi.o
 obj-$(CONFIG_CMD_UBIFS) += cmd_ubifs.o
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 1bc0db8..864b259 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -453,6 +453,37 @@
 
 	return 0;
 }
+
+static int do_i2c_olen(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	struct udevice *dev;
+	uint olen;
+	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) {
+		olen = simple_strtoul(argv[2], NULL, 16);
+		ret = i2c_set_chip_offset_len(dev, olen);
+	} else  {
+		ret = i2c_get_chip_offset_len(dev);
+		if (ret >= 0) {
+			printf("%x\n", ret);
+			ret = 0;
+		}
+	}
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+
+	return 0;
+}
 #endif
 
 /**
@@ -1903,6 +1934,7 @@
 	U_BOOT_CMD_MKENT(write, 6, 0, do_i2c_write, "", ""),
 #ifdef CONFIG_DM_I2C
 	U_BOOT_CMD_MKENT(flags, 2, 1, do_i2c_flags, "", ""),
+	U_BOOT_CMD_MKENT(olen, 2, 1, do_i2c_olen, "", ""),
 #endif
 	U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""),
 #if defined(CONFIG_CMD_SDRAM)
@@ -1971,6 +2003,7 @@
 	"          to I2C; the -s option selects bulk write in a single transaction\n"
 #ifdef CONFIG_DM_I2C
 	"i2c flags chip [flags] - set or get chip flags\n"
+	"i2c olen chip [offset_length] - set or get chip offset length\n"
 #endif
 	"i2c reset - re-init the I2C Controller\n"
 #if defined(CONFIG_CMD_SDRAM)
diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c
index 0294952..97501cc 100644
--- a/common/cmd_tpm.c
+++ b/common/cmd_tpm.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <malloc.h>
 #include <tpm.h>
 #include <asm/unaligned.h>
@@ -57,6 +58,8 @@
 	size_t count, length;
 	int i;
 
+	if (!bytes)
+		return NULL;
 	length = strlen(bytes);
 	count = length / 2;
 
@@ -79,17 +82,19 @@
 }
 
 /**
- * Convert TPM command return code to U-Boot command error codes.
+ * report_return_code() - Report any error and return failure or success
  *
  * @param return_code	TPM command return code
  * @return value of enum command_ret_t
  */
-static int convert_return_code(uint32_t return_code)
+static int report_return_code(int return_code)
 {
-	if (return_code)
+	if (return_code) {
+		printf("Error: %d\n", return_code);
 		return CMD_RET_FAILURE;
-	else
+	} else {
 		return CMD_RET_SUCCESS;
+	}
 }
 
 /**
@@ -251,7 +256,7 @@
 		return CMD_RET_FAILURE;
 	}
 
-	return convert_return_code(tpm_startup(mode));
+	return report_return_code(tpm_startup(mode));
 }
 
 static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag,
@@ -265,7 +270,7 @@
 	perm = simple_strtoul(argv[2], NULL, 0);
 	size = simple_strtoul(argv[3], NULL, 0);
 
-	return convert_return_code(tpm_nv_define_space(index, perm, size));
+	return report_return_code(tpm_nv_define_space(index, perm, size));
 }
 
 static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag,
@@ -286,7 +291,7 @@
 		print_byte_string(data, count);
 	}
 
-	return convert_return_code(rc);
+	return report_return_code(rc);
 }
 
 static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag,
@@ -308,7 +313,7 @@
 	rc = tpm_nv_write_value(index, data, count);
 	free(data);
 
-	return convert_return_code(rc);
+	return report_return_code(rc);
 }
 
 static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag,
@@ -331,7 +336,7 @@
 		print_byte_string(out_digest, sizeof(out_digest));
 	}
 
-	return convert_return_code(rc);
+	return report_return_code(rc);
 }
 
 static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag,
@@ -352,7 +357,7 @@
 		print_byte_string(data, count);
 	}
 
-	return convert_return_code(rc);
+	return report_return_code(rc);
 }
 
 static int do_tpm_tsc_physical_presence(cmd_tbl_t *cmdtp, int flag,
@@ -364,7 +369,7 @@
 		return CMD_RET_USAGE;
 	presence = (uint16_t)simple_strtoul(argv[1], NULL, 0);
 
-	return convert_return_code(tpm_tsc_physical_presence(presence));
+	return report_return_code(tpm_tsc_physical_presence(presence));
 }
 
 static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag,
@@ -384,7 +389,7 @@
 		print_byte_string(data, count);
 	}
 
-	return convert_return_code(rc);
+	return report_return_code(rc);
 }
 
 static int do_tpm_physical_set_deactivated(cmd_tbl_t *cmdtp, int flag,
@@ -396,7 +401,7 @@
 		return CMD_RET_USAGE;
 	state = (uint8_t)simple_strtoul(argv[1], NULL, 0);
 
-	return convert_return_code(tpm_physical_set_deactivated(state));
+	return report_return_code(tpm_physical_set_deactivated(state));
 }
 
 static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag,
@@ -419,7 +424,7 @@
 		print_byte_string(cap, count);
 	}
 
-	return convert_return_code(rc);
+	return report_return_code(rc);
 }
 
 #define TPM_COMMAND_NO_ARG(cmd)				\
@@ -428,7 +433,7 @@
 {							\
 	if (argc != 1)					\
 		return CMD_RET_USAGE;			\
-	return convert_return_code(cmd());		\
+	return report_return_code(cmd());		\
 }
 
 TPM_COMMAND_NO_ARG(tpm_init)
@@ -438,6 +443,41 @@
 TPM_COMMAND_NO_ARG(tpm_physical_enable)
 TPM_COMMAND_NO_ARG(tpm_physical_disable)
 
+#ifdef CONFIG_DM_TPM
+static int get_tpm(struct udevice **devp)
+{
+	int rc;
+
+	rc = uclass_first_device(UCLASS_TPM, devp);
+	if (rc) {
+		printf("Could not find TPM (ret=%d)\n", rc);
+		return CMD_RET_FAILURE;
+	}
+
+	return 0;
+}
+
+static int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc,
+		       char *const argv[])
+{
+	struct udevice *dev;
+	char buf[80];
+	int rc;
+
+	rc = get_tpm(&dev);
+	if (rc)
+		return rc;
+	rc = tpm_get_desc(dev, buf, sizeof(buf));
+	if (rc < 0) {
+		printf("Couldn't get TPM info (%d)\n", rc);
+		return CMD_RET_FAILURE;
+	}
+	printf("%s\n", buf);
+
+	return 0;
+}
+#endif
+
 static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag,
 		int argc, char * const argv[])
 {
@@ -452,14 +492,24 @@
 		return CMD_RET_FAILURE;
 	}
 
+#ifdef CONFIG_DM_TPM
+	struct udevice *dev;
+
+	rc = get_tpm(&dev);
+	if (rc)
+		return rc;
+
+	rc = tpm_xfer(dev, command, count, response, &response_length);
+#else
 	rc = tis_sendrecv(command, count, response, &response_length);
+#endif
 	free(command);
 	if (!rc) {
 		puts("tpm response:\n");
 		print_byte_string(response, response_length);
 	}
 
-	return convert_return_code(rc);
+	return report_return_code(rc);
 }
 
 static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag,
@@ -477,7 +527,7 @@
 	index = simple_strtoul(argv[2], NULL, 0);
 	perm = simple_strtoul(argv[3], NULL, 0);
 
-	return convert_return_code(tpm_nv_define_space(index, perm, size));
+	return report_return_code(tpm_nv_define_space(index, perm, size));
 }
 
 static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag,
@@ -506,7 +556,7 @@
 	}
 	free(data);
 
-	return convert_return_code(err);
+	return report_return_code(err);
 }
 
 static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag,
@@ -534,7 +584,7 @@
 	err = tpm_nv_write_value(index, data, count);
 	free(data);
 
-	return convert_return_code(err);
+	return report_return_code(err);
 }
 
 #ifdef CONFIG_TPM_AUTH_SESSIONS
@@ -546,7 +596,7 @@
 
 	err = tpm_oiap(&auth_handle);
 
-	return convert_return_code(err);
+	return report_return_code(err);
 }
 
 static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag,
@@ -571,7 +621,7 @@
 	if (!err)
 		printf("Key handle is 0x%x\n", key_handle);
 
-	return convert_return_code(err);
+	return report_return_code(err);
 }
 
 static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag,
@@ -596,7 +646,7 @@
 		printf("dump of received pub key structure:\n");
 		print_byte_string(pub_key_buffer, pub_key_len);
 	}
-	return convert_return_code(err);
+	return report_return_code(err);
 }
 
 TPM_COMMAND_NO_ARG(tpm_end_oiap)
@@ -607,6 +657,9 @@
 	U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "")
 
 static cmd_tbl_t tpm_commands[] = {
+#ifdef CONFIG_DM_TPM
+	U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
+#endif
 	U_BOOT_CMD_MKENT(init, 0, 1,
 			do_tpm_init, "", ""),
 	U_BOOT_CMD_MKENT(startup, 0, 1,
@@ -677,6 +730,9 @@
 "cmd args...\n"
 "    - Issue TPM command <cmd> with arguments <args...>.\n"
 "Admin Startup and State Commands:\n"
+#ifdef CONFIG_DM_TPM
+"  info - Show information about the TPM\n"
+#endif
 "  init\n"
 "    - Put TPM into a state where it waits for 'startup' command.\n"
 "  startup mode\n"
diff --git a/common/cmd_tpm_test.c b/common/cmd_tpm_test.c
new file mode 100644
index 0000000..65332d1
--- /dev/null
+++ b/common/cmd_tpm_test.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <tpm.h>
+
+/* Prints error and returns on failure */
+#define TPM_CHECK(tpm_command) do { \
+	uint32_t result; \
+	\
+	result = (tpm_command); \
+	if (result != TPM_SUCCESS) { \
+		printf("TEST FAILED: line %d: " #tpm_command ": 0x%x\n", \
+			__LINE__, result); \
+		return result; \
+	} \
+} while (0)
+
+#define INDEX0			0xda70
+#define INDEX1			0xda71
+#define INDEX2			0xda72
+#define INDEX3			0xda73
+#define INDEX_INITIALISED	0xda80
+#define PHYS_PRESENCE		4
+#define PRESENCE		8
+
+static uint32_t TlclStartupIfNeeded(void)
+{
+	uint32_t result = tpm_startup(TPM_ST_CLEAR);
+
+	return result == TPM_INVALID_POSTINIT ? TPM_SUCCESS : result;
+}
+
+static int test_timer(void)
+{
+	printf("get_timer(0) = %lu\n", get_timer(0));
+	return 0;
+}
+
+static uint32_t tpm_get_flags(uint8_t *disable, uint8_t *deactivated,
+			      uint8_t *nvlocked)
+{
+	struct tpm_permanent_flags pflags;
+	uint32_t result;
+
+	result = tpm_get_permanent_flags(&pflags);
+	if (result)
+		return result;
+	if (disable)
+		*disable = pflags.disable;
+	if (deactivated)
+		*deactivated = pflags.deactivated;
+	if (nvlocked)
+		*nvlocked = pflags.nv_locked;
+	debug("TPM: Got flags disable=%d, deactivated=%d, nvlocked=%d\n",
+	      pflags.disable, pflags.deactivated, pflags.nv_locked);
+
+	return 0;
+}
+
+static uint32_t tpm_set_global_lock(void)
+{
+	uint32_t x;
+
+	debug("TPM: Set global lock\n");
+	return tpm_nv_write_value(INDEX0, (uint8_t *)&x, 0);
+}
+
+static uint32_t tpm_nv_write_value_lock(uint32_t index)
+{
+	debug("TPM: Write lock 0x%x\n", index);
+
+	return tpm_nv_write_value(index, NULL, 0);
+}
+
+static uint32_t tpm_nv_set_locked(void)
+{
+	debug("TPM: Set NV locked\n");
+
+	return tpm_nv_define_space(TPM_NV_INDEX_LOCK, 0, 0);
+}
+
+static int tpm_is_owned(void)
+{
+	uint8_t response[TPM_PUBEK_SIZE];
+	uint32_t result;
+
+	result = tpm_read_pubek(response, sizeof(response));
+
+	return result != TPM_SUCCESS;
+}
+
+static int test_early_extend(void)
+{
+	uint8_t value_in[20];
+	uint8_t value_out[20];
+
+	printf("Testing earlyextend ...");
+	tpm_init();
+	TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
+	TPM_CHECK(tpm_continue_self_test());
+	TPM_CHECK(tpm_extend(1, value_in, value_out));
+	printf("done\n");
+	return 0;
+}
+
+static int test_early_nvram(void)
+{
+	uint32_t x;
+
+	printf("Testing earlynvram ...");
+	tpm_init();
+	TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
+	TPM_CHECK(tpm_continue_self_test());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+	printf("done\n");
+	return 0;
+}
+
+static int test_early_nvram2(void)
+{
+	uint32_t x;
+
+	printf("Testing earlynvram2 ...");
+	tpm_init();
+	TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
+	TPM_CHECK(tpm_continue_self_test());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+	printf("done\n");
+	return 0;
+}
+
+static int test_enable(void)
+{
+	uint8_t disable = 0, deactivated = 0;
+
+	printf("Testing enable ...\n");
+	tpm_init();
+	TPM_CHECK(TlclStartupIfNeeded());
+	TPM_CHECK(tpm_self_test_full());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+	printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
+	TPM_CHECK(tpm_physical_enable());
+	TPM_CHECK(tpm_physical_set_deactivated(0));
+	TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+	printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
+	if (disable == 1 || deactivated == 1)
+		printf("\tfailed to enable or activate\n");
+	printf("\tdone\n");
+	return 0;
+}
+
+#define reboot() do { \
+	printf("\trebooting...\n"); \
+	reset_cpu(0); \
+} while (0)
+
+static int test_fast_enable(void)
+{
+	uint8_t disable = 0, deactivated = 0;
+	int i;
+
+	printf("Testing fastenable ...\n");
+	tpm_init();
+	TPM_CHECK(TlclStartupIfNeeded());
+	TPM_CHECK(tpm_self_test_full());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+	printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
+	for (i = 0; i < 2; i++) {
+		TPM_CHECK(tpm_force_clear());
+		TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+		printf("\tdisable is %d, deactivated is %d\n", disable,
+		       deactivated);
+		assert(disable == 1 && deactivated == 1);
+		TPM_CHECK(tpm_physical_enable());
+		TPM_CHECK(tpm_physical_set_deactivated(0));
+		TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+		printf("\tdisable is %d, deactivated is %d\n", disable,
+		       deactivated);
+		assert(disable == 0 && deactivated == 0);
+	}
+	printf("\tdone\n");
+	return 0;
+}
+
+static int test_global_lock(void)
+{
+	uint32_t zero = 0;
+	uint32_t result;
+	uint32_t x;
+
+	printf("Testing globallock ...\n");
+	tpm_init();
+	TPM_CHECK(TlclStartupIfNeeded());
+	TPM_CHECK(tpm_self_test_full());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+	TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&zero,
+				     sizeof(uint32_t)));
+	TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+	TPM_CHECK(tpm_nv_write_value(INDEX1, (uint8_t *)&zero,
+				     sizeof(uint32_t)));
+	TPM_CHECK(tpm_set_global_lock());
+	/* Verifies that write to index0 fails */
+	x = 1;
+	result = tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x));
+	assert(result == TPM_AREA_LOCKED);
+	TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+	assert(x == 0);
+	/* Verifies that write to index1 is still possible */
+	x = 2;
+	TPM_CHECK(tpm_nv_write_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+	TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+	assert(x == 2);
+	/* Turns off PP */
+	tpm_tsc_physical_presence(PHYS_PRESENCE);
+	/* Verifies that write to index1 fails */
+	x = 3;
+	result = tpm_nv_write_value(INDEX1, (uint8_t *)&x, sizeof(x));
+	assert(result == TPM_BAD_PRESENCE);
+	TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+	assert(x == 2);
+	printf("\tdone\n");
+	return 0;
+}
+
+static int test_lock(void)
+{
+	printf("Testing lock ...\n");
+	tpm_init();
+	tpm_startup(TPM_ST_CLEAR);
+	tpm_self_test_full();
+	tpm_tsc_physical_presence(PRESENCE);
+	tpm_nv_write_value_lock(INDEX0);
+	printf("\tLocked 0x%x\n", INDEX0);
+	printf("\tdone\n");
+	return 0;
+}
+
+static void initialise_spaces(void)
+{
+	uint32_t zero = 0;
+	uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE;
+
+	printf("\tInitialising spaces\n");
+	tpm_nv_set_locked();  /* useful only the first time */
+	tpm_nv_define_space(INDEX0, perm, 4);
+	tpm_nv_write_value(INDEX0, (uint8_t *)&zero, 4);
+	tpm_nv_define_space(INDEX1, perm, 4);
+	tpm_nv_write_value(INDEX1, (uint8_t *)&zero, 4);
+	tpm_nv_define_space(INDEX2, perm, 4);
+	tpm_nv_write_value(INDEX2, (uint8_t *)&zero, 4);
+	tpm_nv_define_space(INDEX3, perm, 4);
+	tpm_nv_write_value(INDEX3, (uint8_t *)&zero, 4);
+	perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR |
+		TPM_NV_PER_PPWRITE;
+	tpm_nv_define_space(INDEX_INITIALISED, perm, 1);
+}
+
+static int test_readonly(void)
+{
+	uint8_t c;
+	uint32_t index_0, index_1, index_2, index_3;
+	int read0, read1, read2, read3;
+
+	printf("Testing readonly ...\n");
+	tpm_init();
+	tpm_startup(TPM_ST_CLEAR);
+	tpm_self_test_full();
+	tpm_tsc_physical_presence(PRESENCE);
+	/*
+	 * Checks if initialisation has completed by trying to read-lock a
+	 * space that's created at the end of initialisation
+	 */
+	if (tpm_nv_read_value(INDEX_INITIALISED, &c, 0) == TPM_BADINDEX) {
+		/* The initialisation did not complete */
+		initialise_spaces();
+	}
+
+	/* Checks if spaces are OK or messed up */
+	read0 = tpm_nv_read_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0));
+	read1 = tpm_nv_read_value(INDEX1, (uint8_t *)&index_1, sizeof(index_1));
+	read2 = tpm_nv_read_value(INDEX2, (uint8_t *)&index_2, sizeof(index_2));
+	read3 = tpm_nv_read_value(INDEX3, (uint8_t *)&index_3, sizeof(index_3));
+	if (read0 || read1 || read2 || read3) {
+		printf("Invalid contents\n");
+		return 0;
+	}
+
+	/*
+	 * Writes space, and locks it.  Then attempts to write again.
+	 * I really wish I could use the imperative.
+	 */
+	index_0 += 1;
+	if (tpm_nv_write_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0) !=
+		TPM_SUCCESS)) {
+		error("\tcould not write index 0\n");
+	}
+	tpm_nv_write_value_lock(INDEX0);
+	if (tpm_nv_write_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0)) ==
+			TPM_SUCCESS)
+		error("\tindex 0 is not locked\n");
+
+	printf("\tdone\n");
+	return 0;
+}
+
+static int test_redefine_unowned(void)
+{
+	uint32_t perm;
+	uint32_t result;
+	uint32_t x;
+
+	printf("Testing redefine_unowned ...");
+	tpm_init();
+	TPM_CHECK(TlclStartupIfNeeded());
+	TPM_CHECK(tpm_self_test_full());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	assert(!tpm_is_owned());
+
+	/* Ensures spaces exist. */
+	TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+	TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+
+	/* Redefines spaces a couple of times. */
+	perm = TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK;
+	TPM_CHECK(tpm_nv_define_space(INDEX0, perm, 2 * sizeof(uint32_t)));
+	TPM_CHECK(tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t)));
+	perm = TPM_NV_PER_PPWRITE;
+	TPM_CHECK(tpm_nv_define_space(INDEX1, perm, 2 * sizeof(uint32_t)));
+	TPM_CHECK(tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t)));
+
+	/* Sets the global lock */
+	tpm_set_global_lock();
+
+	/* Verifies that index0 cannot be redefined */
+	result = tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t));
+	assert(result == TPM_AREA_LOCKED);
+
+	/* Checks that index1 can */
+	TPM_CHECK(tpm_nv_define_space(INDEX1, perm, 2 * sizeof(uint32_t)));
+	TPM_CHECK(tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t)));
+
+	/* Turns off PP */
+	tpm_tsc_physical_presence(PHYS_PRESENCE);
+
+	/* Verifies that neither index0 nor index1 can be redefined */
+	result = tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t));
+	assert(result == TPM_BAD_PRESENCE);
+	result = tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t));
+	assert(result == TPM_BAD_PRESENCE);
+
+	printf("done\n");
+	return 0;
+}
+
+#define PERMPPGL (TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK)
+#define PERMPP TPM_NV_PER_PPWRITE
+
+static int test_space_perm(void)
+{
+	uint32_t perm;
+
+	printf("Testing spaceperm ...");
+	tpm_init();
+	TPM_CHECK(TlclStartupIfNeeded());
+	TPM_CHECK(tpm_continue_self_test());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	TPM_CHECK(tpm_get_permissions(INDEX0, &perm));
+	assert((perm & PERMPPGL) == PERMPPGL);
+	TPM_CHECK(tpm_get_permissions(INDEX1, &perm));
+	assert((perm & PERMPP) == PERMPP);
+	printf("done\n");
+	return 0;
+}
+
+static int test_startup(void)
+{
+	uint32_t result;
+	printf("Testing startup ...\n");
+
+	tpm_init();
+	result = tpm_startup(TPM_ST_CLEAR);
+	if (result != 0 && result != TPM_INVALID_POSTINIT)
+		printf("\ttpm startup failed with 0x%x\n", result);
+	result = tpm_get_flags(NULL, NULL, NULL);
+	if (result != 0)
+		printf("\ttpm getflags failed with 0x%x\n", result);
+	printf("\texecuting SelfTestFull\n");
+	tpm_self_test_full();
+	result = tpm_get_flags(NULL, NULL, NULL);
+	if (result != 0)
+		printf("\ttpm getflags failed with 0x%x\n", result);
+	printf("\tdone\n");
+	return 0;
+}
+
+/*
+ * Runs [op] and ensures it returns success and doesn't run longer than
+ * [time_limit] in milliseconds.
+ */
+#define TTPM_CHECK(op, time_limit) do { \
+	ulong start, time; \
+	uint32_t __result; \
+	\
+	start = get_timer(0); \
+	__result = op; \
+	if (__result != TPM_SUCCESS) { \
+		printf("\t" #op ": error 0x%x\n", __result); \
+		return -1; \
+	} \
+	time = get_timer(start); \
+	printf("\t" #op ": %lu ms\n", time); \
+	if (time > (ulong)time_limit) { \
+		printf("\t" #op " exceeded " #time_limit " ms\n"); \
+	} \
+} while (0)
+
+
+static int test_timing(void)
+{
+	uint32_t x;
+	uint8_t in[20], out[20];
+
+	printf("Testing timing ...");
+	tpm_init();
+	TTPM_CHECK(TlclStartupIfNeeded(), 50);
+	TTPM_CHECK(tpm_continue_self_test(), 100);
+	TTPM_CHECK(tpm_self_test_full(), 1000);
+	TTPM_CHECK(tpm_tsc_physical_presence(PRESENCE), 100);
+	TTPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x)), 100);
+	TTPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)), 100);
+	TTPM_CHECK(tpm_extend(0, in, out), 200);
+	TTPM_CHECK(tpm_set_global_lock(), 50);
+	TTPM_CHECK(tpm_tsc_physical_presence(PHYS_PRESENCE), 100);
+	printf("done\n");
+	return 0;
+}
+
+#define TPM_MAX_NV_WRITES_NOOWNER 64
+
+static int test_write_limit(void)
+{
+	printf("Testing writelimit ...\n");
+	int i;
+	uint32_t result;
+
+	tpm_init();
+	TPM_CHECK(TlclStartupIfNeeded());
+	TPM_CHECK(tpm_self_test_full());
+	TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+	TPM_CHECK(tpm_force_clear());
+	TPM_CHECK(tpm_physical_enable());
+	TPM_CHECK(tpm_physical_set_deactivated(0));
+
+	for (i = 0; i < TPM_MAX_NV_WRITES_NOOWNER + 2; i++) {
+		printf("\twriting %d\n", i);
+		result = tpm_nv_write_value(INDEX0, (uint8_t *)&i, sizeof(i));
+		switch (result) {
+		case TPM_SUCCESS:
+			break;
+		case TPM_MAXNVWRITES:
+			assert(i >= TPM_MAX_NV_WRITES_NOOWNER);
+		default:
+			error("\tunexpected error code %d (0x%x)\n",
+			      result, result);
+		}
+	}
+
+	/* Reset write count */
+	TPM_CHECK(tpm_force_clear());
+	TPM_CHECK(tpm_physical_enable());
+	TPM_CHECK(tpm_physical_set_deactivated(0));
+
+	/* Try writing again. */
+	TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&i, sizeof(i)));
+	printf("\tdone\n");
+	return 0;
+}
+
+#define VOIDTEST(XFUNC) \
+	int do_test_##XFUNC(cmd_tbl_t *cmd_tbl, int flag, int argc, \
+	char * const argv[]) \
+	{ \
+		return test_##XFUNC(); \
+	}
+
+#define VOIDENT(XNAME) \
+	U_BOOT_CMD_MKENT(XNAME, 0, 1, do_test_##XNAME, "", ""),
+
+VOIDTEST(early_extend)
+VOIDTEST(early_nvram)
+VOIDTEST(early_nvram2)
+VOIDTEST(enable)
+VOIDTEST(fast_enable)
+VOIDTEST(global_lock)
+VOIDTEST(lock)
+VOIDTEST(readonly)
+VOIDTEST(redefine_unowned)
+VOIDTEST(space_perm)
+VOIDTEST(startup)
+VOIDTEST(timing)
+VOIDTEST(write_limit)
+VOIDTEST(timer)
+
+static cmd_tbl_t cmd_cros_tpm_sub[] = {
+	VOIDENT(early_extend)
+	VOIDENT(early_nvram)
+	VOIDENT(early_nvram2)
+	VOIDENT(enable)
+	VOIDENT(fast_enable)
+	VOIDENT(global_lock)
+	VOIDENT(lock)
+	VOIDENT(readonly)
+	VOIDENT(redefine_unowned)
+	VOIDENT(space_perm)
+	VOIDENT(startup)
+	VOIDENT(timing)
+	VOIDENT(write_limit)
+	VOIDENT(timer)
+};
+
+static int do_tpmtest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	cmd_tbl_t *c;
+
+	printf("argc = %d, argv = ", argc);
+	do {
+		int i = 0;
+
+		for (i = 0; i < argc; i++)
+			printf(" %s", argv[i]);
+			printf("\n------\n");
+		} while (0);
+	argc--;
+	argv++;
+	c = find_cmd_tbl(argv[0], cmd_cros_tpm_sub,
+			 ARRAY_SIZE(cmd_cros_tpm_sub));
+	return c ? c->cmd(cmdtp, flag, argc, argv) : cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(tpmtest, 2, 1, do_tpmtest, "TPM tests",
+	"\n\tearly_extend\n"
+	"\tearly_nvram\n"
+	"\tearly_nvram2\n"
+	"\tenable\n"
+	"\tfast_enable\n"
+	"\tglobal_lock\n"
+	"\tlock\n"
+	"\treadonly\n"
+	"\tredefine_unowned\n"
+	"\tspace_perm\n"
+	"\tstartup\n"
+	"\ttiming\n"
+	"\twrite_limit\n");
diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig
index b987f3f..9855736 100644
--- a/configs/chromebook_link_defconfig
+++ b/configs/chromebook_link_defconfig
@@ -11,15 +11,20 @@
 CONFIG_BOOTSTAGE=y
 CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_OF_CONTROL=y
 CONFIG_DM_PCI=y
 CONFIG_SPI_FLASH=y
 CONFIG_CMD_CROS_EC=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_LPC=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_LPC=y
 CONFIG_VIDEO_VESA=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
 CONFIG_DM_RTC=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_VSNPRINTF=y
+CONFIG_TPM=y
diff --git a/configs/chromebox_panther_defconfig b/configs/chromebox_panther_defconfig
index e82c8ec..c75b20d 100644
--- a/configs/chromebox_panther_defconfig
+++ b/configs/chromebox_panther_defconfig
@@ -11,15 +11,20 @@
 CONFIG_BOOTSTAGE=y
 CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_OF_CONTROL=y
 CONFIG_DM_PCI=y
 CONFIG_SPI_FLASH=y
 CONFIG_CMD_CROS_EC=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_LPC=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_LPC=y
 CONFIG_VIDEO_VESA=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
 CONFIG_DM_RTC=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_VSNPRINTF=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig b/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig
index 37ead03..c8ab862 100644
--- a/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig
+++ b/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig
@@ -4,4 +4,8 @@
 CONFIG_SYS_EXTRA_OPTIONS="36BIT,SDCARD,DEVELOP"
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_FLASH is not set
+CONFIG_CMD_TPM=y
 CONFIG_SPI_FLASH=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_36BIT_SDCARD_defconfig b/configs/controlcenterd_36BIT_SDCARD_defconfig
index 7166edb..21c0eab 100644
--- a/configs/controlcenterd_36BIT_SDCARD_defconfig
+++ b/configs/controlcenterd_36BIT_SDCARD_defconfig
@@ -4,4 +4,8 @@
 CONFIG_SYS_EXTRA_OPTIONS="36BIT,SDCARD"
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_FLASH is not set
+CONFIG_CMD_TPM=y
 CONFIG_SPI_FLASH=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig b/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig
index d99fcd4..c3a0920 100644
--- a/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig
+++ b/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig
@@ -6,3 +6,7 @@
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TPM=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_TRAILBLAZER_defconfig b/configs/controlcenterd_TRAILBLAZER_defconfig
index 3557aea..08aae9a 100644
--- a/configs/controlcenterd_TRAILBLAZER_defconfig
+++ b/configs/controlcenterd_TRAILBLAZER_defconfig
@@ -6,3 +6,7 @@
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TPM=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/coreboot-x86_defconfig b/configs/coreboot-x86_defconfig
index df3a624..ebaf86b 100644
--- a/configs/coreboot-x86_defconfig
+++ b/configs/coreboot-x86_defconfig
@@ -9,10 +9,15 @@
 CONFIG_BOOTSTAGE=y
 CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_OF_CONTROL=y
 CONFIG_DM_PCI=y
 CONFIG_SPI_FLASH=y
 CONFIG_NETDEVICES=y
 CONFIG_E1000=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_LPC=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_VSNPRINTF=y
+CONFIG_TPM=y
diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig
index 274e955..6464c37 100644
--- a/configs/nyan-big_defconfig
+++ b/configs/nyan-big_defconfig
@@ -9,16 +9,21 @@
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_SETEXPR is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_SPL_DM=y
 CONFIG_SPI_FLASH=y
 CONFIG_CMD_CROS_EC=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_SPI=y
 CONFIG_CROS_EC_KEYB=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
 CONFIG_TEGRA114_SPI=y
 CONFIG_DISPLAY_PORT=y
 CONFIG_VIDEO_TEGRA124=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
+CONFIG_TPM=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_PROMPT="Tegra124 (Nyan-big) # "
diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig
index 323a2d3..56a5185 100644
--- a/configs/peach-pi_defconfig
+++ b/configs/peach-pi_defconfig
@@ -7,11 +7,15 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_SPI_FLASH=y
 CONFIG_CMD_CROS_EC=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_SPI=y
 CONFIG_CROS_EC_KEYB=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
 CONFIG_DM_I2C=y
 CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
@@ -30,5 +34,6 @@
 CONFIG_SOUND_WM8994=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
+CONFIG_TPM=y
 CONFIG_ERRNO_STR=y
 CONFIG_SYS_PROMPT="Peach-Pi # "
diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig
index 6a08296..1934bf3 100644
--- a/configs/peach-pit_defconfig
+++ b/configs/peach-pit_defconfig
@@ -7,11 +7,15 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_SPI_FLASH=y
 CONFIG_CMD_CROS_EC=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_SPI=y
 CONFIG_CROS_EC_KEYB=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
 CONFIG_DM_I2C=y
 CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
@@ -30,5 +34,6 @@
 CONFIG_SOUND_WM8994=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
+CONFIG_TPM=y
 CONFIG_ERRNO_STR=y
 CONFIG_SYS_PROMPT="Peach-Pit # "
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 85ff95d..e9e1597 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -11,6 +11,8 @@
 CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_HOSTFILE=y
 CONFIG_CLK=y
@@ -30,9 +32,13 @@
 CONFIG_LED=y
 CONFIG_LED_GPIO=y
 CONFIG_SANDBOX_SERIAL=y
+CONFIG_DM_TPM=y
 CONFIG_TPM_TIS_SANDBOX=y
 CONFIG_SYS_I2C_SANDBOX=y
 CONFIG_SANDBOX_SPI=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_SANDBOX=y
 CONFIG_SANDBOX_GPIO=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_PMIC_SANDBOX=y
@@ -49,6 +55,7 @@
 CONFIG_DM_RTC=y
 CONFIG_SYS_VSNPRINTF=y
 CONFIG_CMD_DHRYSTONE=y
+CONFIG_TPM=y
 CONFIG_ERRNO_STR=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
diff --git a/configs/snow_defconfig b/configs/snow_defconfig
index f5decd5..32c7c5d 100644
--- a/configs/snow_defconfig
+++ b/configs/snow_defconfig
@@ -8,6 +8,8 @@
 CONFIG_CMD_SOUND=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_SPI_FLASH=y
 CONFIG_CMD_CROS_EC=y
 CONFIG_CROS_EC=y
@@ -17,6 +19,8 @@
 CONFIG_DEBUG_UART_S5P=y
 CONFIG_DEBUG_UART_BASE=0x12c30000
 CONFIG_DEBUG_UART_CLOCK=100000000
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
 CONFIG_DM_I2C=y
 CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_LDO=y
@@ -41,4 +45,5 @@
 CONFIG_SOUND_WM8994=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
+CONFIG_TPM=y
 CONFIG_ERRNO_STR=y
diff --git a/configs/spring_defconfig b/configs/spring_defconfig
index f1d9a58..b20bfed 100644
--- a/configs/spring_defconfig
+++ b/configs/spring_defconfig
@@ -8,6 +8,8 @@
 CONFIG_CMD_SOUND=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
 CONFIG_SPI_FLASH=y
 CONFIG_CMD_CROS_EC=y
 CONFIG_CROS_EC=y
@@ -17,6 +19,8 @@
 CONFIG_DEBUG_UART_S5P=y
 CONFIG_DEBUG_UART_BASE=0x12c30000
 CONFIG_DEBUG_UART_CLOCK=100000000
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
 CONFIG_DM_I2C=y
 CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_LDO=y
@@ -40,4 +44,5 @@
 CONFIG_SOUND_WM8994=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
+CONFIG_TPM=y
 CONFIG_ERRNO_STR=y
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 092bc02..63c92c5 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,66 +1,68 @@
 menu "Device Drivers"
 
-source "drivers/clk/Kconfig"
-
 source "drivers/core/Kconfig"
 
-source "drivers/cpu/Kconfig"
-
-source "drivers/demo/Kconfig"
-
-source "drivers/pci/Kconfig"
-
-source "drivers/pcmcia/Kconfig"
-
-source "drivers/mtd/Kconfig"
+# types of drivers sorted in alphabetical order
 
 source "drivers/block/Kconfig"
 
-source "drivers/misc/Kconfig"
+source "drivers/clk/Kconfig"
 
-source "drivers/net/Kconfig"
+source "drivers/cpu/Kconfig"
+
+source "drivers/crypto/Kconfig"
+
+source "drivers/demo/Kconfig"
+
+source "drivers/dfu/Kconfig"
+
+source "drivers/dma/Kconfig"
+
+source "drivers/gpio/Kconfig"
+
+source "drivers/hwmon/Kconfig"
+
+source "drivers/i2c/Kconfig"
 
 source "drivers/input/Kconfig"
 
 source "drivers/led/Kconfig"
 
-source "drivers/serial/Kconfig"
+source "drivers/misc/Kconfig"
 
-source "drivers/tpm/Kconfig"
+source "drivers/mmc/Kconfig"
 
-source "drivers/i2c/Kconfig"
+source "drivers/mtd/Kconfig"
 
-source "drivers/spi/Kconfig"
+source "drivers/net/Kconfig"
 
-source "drivers/gpio/Kconfig"
+source "drivers/pci/Kconfig"
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pinctrl/Kconfig"
 
 source "drivers/power/Kconfig"
 
 source "drivers/ram/Kconfig"
 
-source "drivers/hwmon/Kconfig"
+source "drivers/rtc/Kconfig"
 
-source "drivers/watchdog/Kconfig"
-
-source "drivers/video/Kconfig"
+source "drivers/serial/Kconfig"
 
 source "drivers/sound/Kconfig"
 
-source "drivers/usb/Kconfig"
-
-source "drivers/dfu/Kconfig"
-
-source "drivers/mmc/Kconfig"
-
-source "drivers/rtc/Kconfig"
-
-source "drivers/dma/Kconfig"
-
-source "drivers/crypto/Kconfig"
+source "drivers/spi/Kconfig"
 
 source "drivers/thermal/Kconfig"
 
-endmenu
+source "drivers/tpm/Kconfig"
+
+source "drivers/usb/Kconfig"
+
+source "drivers/video/Kconfig"
+
+source "drivers/watchdog/Kconfig"
 
 config PHYS_TO_BUS
 	bool "Custom physical to bus address mapping"
@@ -69,3 +71,5 @@
 	  peripheral DMA master accesses. If yours does, select this option in
 	  your platform's Kconfig, and implement the appropriate mapping
 	  functions in your platform's support code.
+
+endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index a721ec8..9d0a595 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,6 +1,7 @@
 obj-$(CONFIG_$(SPL_)DM)		+= core/
 obj-$(CONFIG_$(SPL_)CLK)	+= clk/
 obj-$(CONFIG_$(SPL_)LED)	+= led/
+obj-$(CONFIG_$(SPL_)PINCTRL)	+= pinctrl/
 obj-$(CONFIG_$(SPL_)RAM)	+= ram/
 
 ifdef CONFIG_SPL_BUILD
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 788f8b7..41f4e69 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -105,4 +105,19 @@
 
 	  If you are unsure about this, Say N here.
 
+config SIMPLE_BUS
+	bool "Support simple-bus driver"
+	depends on DM && OF_CONTROL
+	default y
+	help
+	  Supports the 'simple-bus' driver, which is used on some systems.
+
+config SPL_SIMPLE_BUS
+	bool "Support simple-bus driver in SPL"
+	depends on SPL_DM && SPL_OF_CONTROL
+	default n
+	help
+	  Supports the 'simple-bus' driver, which is used on some systems
+	  in SPL.
+
 endmenu
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 11e0276..f19f67d 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -6,10 +6,8 @@
 
 obj-y	+= device.o lists.o root.o uclass.o util.o
 obj-$(CONFIG_DEVRES) += devres.o
-ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_$(SPL_)OF_CONTROL) += simple-bus.o
-endif
 obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE)	+= device-remove.o
+obj-$(CONFIG_$(SPL_)SIMPLE_BUS)	+= simple-bus.o
 obj-$(CONFIG_DM)	+= dump.o
 obj-$(CONFIG_REGMAP)	+= regmap.o
 obj-$(CONFIG_SYSCON)	+= syscon-uclass.o
diff --git a/drivers/core/device.c b/drivers/core/device.c
index a31e25f..a6cd936 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -15,6 +15,7 @@
 #include <dm/device.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
+#include <dm/pinctrl.h>
 #include <dm/platdata.h>
 #include <dm/uclass.h>
 #include <dm/uclass-internal.h>
@@ -32,7 +33,8 @@
 	struct uclass *uc;
 	int size, ret = 0;
 
-	*devp = NULL;
+	if (devp)
+		*devp = NULL;
 	if (!name)
 		return -EINVAL;
 
@@ -133,7 +135,8 @@
 
 	if (parent)
 		dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
-	*devp = dev;
+	if (devp)
+		*devp = dev;
 
 	dev->flags |= DM_FLAG_BOUND;
 
@@ -284,6 +287,9 @@
 
 	dev->flags |= DM_FLAG_ACTIVATED;
 
+	/* continue regardless of the result of pinctrl */
+	pinctrl_select_state(dev, "default");
+
 	ret = uclass_pre_probe_device(dev);
 	if (ret)
 		goto fail;
@@ -574,7 +580,7 @@
 	fdt_addr_t addr;
 
 	addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
-	if (addr != FDT_ADDR_T_NONE) {
+	if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
 		if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS)
 			addr = simple_bus_translate(dev->parent, addr);
 	}
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 49b1054..17fcfbf 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -327,8 +327,7 @@
 	if (plat)
 		return 0;
 
-	base = (struct s5p_gpio_bank *)fdtdec_get_addr(gd->fdt_blob,
-						   parent->of_offset, "reg");
+	base = (struct s5p_gpio_bank *)dev_get_addr(parent);
 	for (node = fdt_first_subnode(blob, parent->of_offset), bank = base;
 	     node > 0;
 	     node = fdt_next_subnode(blob, node), bank++) {
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 57b78e5..9d8f11e 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -285,8 +285,7 @@
 		no_banks = SUNXI_GPIO_BANKS;
 	}
 
-	ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
-						   parent->of_offset, "reg");
+	ctlr = (struct sunxi_gpio_reg *)dev_get_addr(parent);
 	for (bank = 0; bank < no_banks; bank++) {
 		struct sunxi_gpio_platdata *plat;
 		struct udevice *dev;
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 8017e35..4921f0f 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -343,8 +343,7 @@
 	if (!fdt_getprop(gd->fdt_blob, parent->of_offset, "interrupts", &len))
 		return -EINVAL;
 	bank_count = len / 3 / sizeof(u32);
-	ctlr = (struct gpio_ctlr *)fdtdec_get_addr(gd->fdt_blob,
-						   parent->of_offset, "reg");
+	ctlr = (struct gpio_ctlr *)dev_get_addr(parent);
 	}
 #endif
 	for (bank = 0; bank < bank_count; bank++) {
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index ae6f436..dc9b661 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -1397,12 +1397,10 @@
 
 	if (i2c_bus->is_highspeed) {
 		flags = PINMUX_FLAG_HS_MODE;
-		i2c_bus->hsregs = (struct exynos5_hsi2c *)
-				fdtdec_get_addr(blob, node, "reg");
+		i2c_bus->hsregs = (struct exynos5_hsi2c *)dev_get_addr(dev);
 	} else {
 		flags = 0;
-		i2c_bus->regs = (struct s3c24x0_i2c *)
-				fdtdec_get_addr(blob, node, "reg");
+		i2c_bus->regs = (struct s3c24x0_i2c *)dev_get_addr(dev);
 	}
 
 	i2c_bus->id = pinmux_decode_periph_id(blob, node);
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index a428978..2fa07f9 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -339,7 +339,7 @@
 
 	i2c_bus->id = dev->seq;
 	i2c_bus->type = dev_get_driver_data(dev);
-	i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
+	i2c_bus->regs = (struct i2c_ctlr *)dev_get_addr(dev);
 
 	/*
 	 * We don't have a binding for pinmux yet. Leave it out for now. So
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
new file mode 100644
index 0000000..30b8e45
--- /dev/null
+++ b/drivers/pinctrl/Kconfig
@@ -0,0 +1,109 @@
+#
+# PINCTRL infrastructure and drivers
+#
+
+menu "Pin controllers"
+
+config PINCTRL
+	bool "Support pin controllers"
+	depends on DM
+	help
+	  This enables the basic support for pinctrl framework.  You may want
+	  to enable some more options depending on what you want to do.
+
+config PINCTRL_FULL
+	bool "Support full pin controllers"
+	depends on PINCTRL && OF_CONTROL
+	default y
+	help
+	  This provides Linux-compatible device tree interface for the pinctrl
+	  subsystem.  This feature depends on device tree configuration because
+	  it parses a device tree to look for the pinctrl device which the
+	  peripheral device is associated with.
+
+	  If this option is disabled (it is the only possible choice for non-DT
+	  boards), the pinctrl core provides no systematic mechanism for
+	  identifying peripheral devices, applying needed pinctrl settings.
+	  It is totally up to the implementation of each low-level driver.
+	  You can save memory footprint in return for some limitations.
+
+config PINCTRL_GENERIC
+	bool "Support generic pin controllers"
+	depends on PINCTRL_FULL
+	default y
+	help
+	  Say Y here if you want to use the pinctrl subsystem through the
+	  generic DT interface.  If enabled, some functions become available
+	  to parse common properties such as "pins", "groups", "functions" and
+	  some pin configuration parameters.  It would be easier if you only
+	  need the generic DT interface for pin muxing and pin configuration.
+	  If you need to handle vendor-specific DT properties, you can disable
+	  this option and implement your own set_state callback in the pinctrl
+	  operations.
+
+config PINMUX
+	bool "Support pin multiplexing controllers"
+	depends on PINCTRL_GENERIC
+	default y
+	help
+	  This option enables pin multiplexing through the generic pinctrl
+	  framework.
+
+config PINCONF
+	bool "Support pin configuration controllers"
+	depends on PINCTRL_GENERIC
+	help
+	  This option enables pin configuration through the generic pinctrl
+	  framework.
+
+config SPL_PINCTRL
+	bool "Support pin controlloers in SPL"
+	depends on SPL && SPL_DM
+	help
+	  This option is an SPL-variant of the PINCTRL option.
+	  See the help of PINCTRL for details.
+
+config SPL_PINCTRL_FULL
+	bool "Support full pin controllers in SPL"
+	depends on SPL_PINCTRL && SPL_OF_CONTROL
+	default y
+	help
+	  This option is an SPL-variant of the PINCTRL_FULL option.
+	  See the help of PINCTRL_FULL for details.
+
+config SPL_PINCTRL_GENERIC
+	bool "Support generic pin controllers in SPL"
+	depends on SPL_PINCTRL_FULL
+	default y
+	help
+	  This option is an SPL-variant of the PINCTRL_GENERIC option.
+	  See the help of PINCTRL_GENERIC for details.
+
+config SPL_PINMUX
+	bool "Support pin multiplexing controllers in SPL"
+	depends on SPL_PINCTRL_GENERIC
+	default y
+	help
+	  This option is an SPL-variant of the PINMUX option.
+	  See the help of PINMUX for details.
+
+config SPL_PINCONF
+	bool "Support pin configuration controllers in SPL"
+	depends on SPL_PINCTRL_GENERIC
+	help
+	  This option is an SPL-variant of the PINCONF option.
+	  See the help of PINCONF for details.
+
+if PINCTRL || SPL_PINCTRL
+
+config PINCTRL_SANDBOX
+	bool "Sandbox pinctrl driver"
+	depends on SANDBOX
+	help
+	  This enables pinctrl driver for sandbox.  Currently, this driver
+	  actually does nothing but print debug messages when pinctrl
+	  operations are invoked.
+
+endif
+
+endmenu
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
new file mode 100644
index 0000000..35decf4
--- /dev/null
+++ b/drivers/pinctrl/Makefile
@@ -0,0 +1,4 @@
+obj-y					+= pinctrl-uclass.o
+obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC)	+= pinctrl-generic.o
+
+obj-$(CONFIG_PINCTRL_SANDBOX)	+= pinctrl-sandbox.o
diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c
new file mode 100644
index 0000000..e86b72a
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-generic.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <dm/device.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * pinctrl_pin_name_to_selector() - return the pin selector for a pin
+ *
+ * @dev: pin controller device
+ * @pin: the pin name to look up
+ * @return: pin selector, or negative error code on failure
+ */
+static int pinctrl_pin_name_to_selector(struct udevice *dev, const char *pin)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+	unsigned npins, selector;
+
+	if (!ops->get_pins_count || !ops->get_pin_name) {
+		dev_dbg(dev, "get_pins_count or get_pin_name missing\n");
+		return -ENOSYS;
+	}
+
+	npins = ops->get_pins_count(dev);
+
+	/* See if this pctldev has this pin */
+	for (selector = 0; selector < npins; selector++) {
+		const char *pname = ops->get_pin_name(dev, selector);
+
+		if (!strcmp(pin, pname))
+			return selector;
+	}
+
+	return -ENOSYS;
+}
+
+/**
+ * pinctrl_group_name_to_selector() - return the group selector for a group
+ *
+ * @dev: pin controller device
+ * @group: the pin group name to look up
+ * @return: pin group selector, or negative error code on failure
+ */
+static int pinctrl_group_name_to_selector(struct udevice *dev,
+					  const char *group)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+	unsigned ngroups, selector;
+
+	if (!ops->get_groups_count || !ops->get_group_name) {
+		dev_dbg(dev, "get_groups_count or get_group_name missing\n");
+		return -ENOSYS;
+	}
+
+	ngroups = ops->get_groups_count(dev);
+
+	/* See if this pctldev has this group */
+	for (selector = 0; selector < ngroups; selector++) {
+		const char *gname = ops->get_group_name(dev, selector);
+
+		if (!strcmp(group, gname))
+			return selector;
+	}
+
+	return -ENOSYS;
+}
+
+#if CONFIG_IS_ENABLED(PINMUX)
+/**
+ * pinmux_func_name_to_selector() - return the function selector for a function
+ *
+ * @dev: pin controller device
+ * @function: the function name to look up
+ * @return: function selector, or negative error code on failure
+ */
+static int pinmux_func_name_to_selector(struct udevice *dev,
+					const char *function)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+	unsigned nfuncs, selector = 0;
+
+	if (!ops->get_functions_count || !ops->get_function_name) {
+		dev_dbg(dev,
+			"get_functions_count or get_function_name missing\n");
+		return -ENOSYS;
+	}
+
+	nfuncs = ops->get_functions_count(dev);
+
+	/* See if this pctldev has this function */
+	for (selector = 0; selector < nfuncs; selector++) {
+		const char *fname = ops->get_function_name(dev, selector);
+
+		if (!strcmp(function, fname))
+			return selector;
+	}
+
+	return -ENOSYS;
+}
+
+/**
+ * pinmux_enable_setting() - enable pin-mux setting for a certain pin/group
+ *
+ * @dev: pin controller device
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @func_selector: function selector
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinmux_enable_setting(struct udevice *dev, bool is_group,
+				 unsigned selector, unsigned func_selector)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+	if (is_group) {
+		if (!ops->pinmux_group_set) {
+			dev_dbg(dev, "pinmux_group_set op missing\n");
+			return -ENOSYS;
+		}
+
+		return ops->pinmux_group_set(dev, selector, func_selector);
+	} else {
+		if (!ops->pinmux_set) {
+			dev_dbg(dev, "pinmux_set op missing\n");
+			return -ENOSYS;
+		}
+		return ops->pinmux_set(dev, selector, func_selector);
+	}
+}
+#else
+static int pinmux_func_name_to_selector(struct udevice *dev,
+					const char *function)
+{
+	return 0;
+}
+
+static int pinmux_enable_setting(struct udevice *dev, bool is_group,
+				 unsigned selector, unsigned func_selector)
+{
+	return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(PINCONF)
+/**
+ * pinconf_prop_name_to_param() - return parameter ID for a property name
+ *
+ * @dev: pin controller device
+ * @property: property name in DTS, such as "bias-pull-up", "slew-rate", etc.
+ * @default_value: return default value in case no value is specified in DTS
+ * @return: return pamater ID, or negative error code on failure
+ */
+static int pinconf_prop_name_to_param(struct udevice *dev,
+				      const char *property, u32 *default_value)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+	const struct pinconf_param *p, *end;
+
+	if (!ops->pinconf_num_params || !ops->pinconf_params) {
+		dev_dbg(dev, "pinconf_num_params or pinconf_params missing\n");
+		return -ENOSYS;
+	}
+
+	p = ops->pinconf_params;
+	end = p + ops->pinconf_num_params;
+
+	/* See if this pctldev supports this parameter */
+	for (; p < end; p++) {
+		if (!strcmp(property, p->property)) {
+			*default_value = p->default_value;
+			return p->param;
+		}
+	}
+
+	return -ENOSYS;
+}
+
+/**
+ * pinconf_enable_setting() - apply pin configuration for a certain pin/group
+ *
+ * @dev: pin controller device
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @param: configuration paramter
+ * @argument: argument taken by some configuration parameters
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinconf_enable_setting(struct udevice *dev, bool is_group,
+				  unsigned selector, unsigned param,
+				  u32 argument)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+	if (is_group) {
+		if (!ops->pinconf_group_set) {
+			dev_dbg(dev, "pinconf_group_set op missing\n");
+			return -ENOSYS;
+		}
+
+		return ops->pinconf_group_set(dev, selector, param,
+					      argument);
+	} else {
+		if (!ops->pinconf_set) {
+			dev_dbg(dev, "pinconf_set op missing\n");
+			return -ENOSYS;
+		}
+		return ops->pinconf_set(dev, selector, param, argument);
+	}
+}
+#else
+static int pinconf_prop_name_to_param(struct udevice *dev,
+				      const char *property, u32 *default_value)
+{
+	return -ENOSYS;
+}
+
+static int pinconf_enable_setting(struct udevice *dev, bool is_group,
+				  unsigned selector, unsigned param,
+				  u32 argument)
+{
+	return 0;
+}
+#endif
+
+/**
+ * pinctrl_generic_set_state_one() - set state for a certain pin/group
+ * Apply all pin multiplexing and pin configurations specified by @config
+ * for a given pin or pin group.
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_generic_set_state_one(struct udevice *dev,
+					 struct udevice *config,
+					 bool is_group, unsigned selector)
+{
+	const void *fdt = gd->fdt_blob;
+	int node_offset = config->of_offset;
+	const char *propname;
+	const void *value;
+	int prop_offset, len, func_selector, param, ret;
+	u32 arg, default_val;
+
+	for (prop_offset = fdt_first_property_offset(fdt, node_offset);
+	     prop_offset > 0;
+	     prop_offset = fdt_next_property_offset(fdt, prop_offset)) {
+		value = fdt_getprop_by_offset(fdt, prop_offset,
+					      &propname, &len);
+		if (!value)
+			return -EINVAL;
+
+		if (!strcmp(propname, "function")) {
+			func_selector = pinmux_func_name_to_selector(dev,
+								     value);
+			if (func_selector < 0)
+				return func_selector;
+			ret = pinmux_enable_setting(dev, is_group,
+						    selector,
+						    func_selector);
+		} else {
+			param = pinconf_prop_name_to_param(dev, propname,
+							   &default_val);
+			if (param < 0)
+				continue; /* just skip unknown properties */
+
+			if (len >= sizeof(fdt32_t))
+				arg = fdt32_to_cpu(*(fdt32_t *)value);
+			else
+				arg = default_val;
+
+			ret = pinconf_enable_setting(dev, is_group,
+						     selector, param, arg);
+		}
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * pinctrl_generic_set_state_subnode() - apply all settings in config node
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_generic_set_state_subnode(struct udevice *dev,
+					     struct udevice *config)
+{
+	const void *fdt = gd->fdt_blob;
+	int node = config->of_offset;
+	const char *subnode_target_type = "pins";
+	bool is_group = false;
+	const char *name;
+	int strings_count, selector, i, ret;
+
+	strings_count = fdt_count_strings(fdt, node, subnode_target_type);
+	if (strings_count < 0) {
+		subnode_target_type = "groups";
+		is_group = true;
+		strings_count = fdt_count_strings(fdt, node,
+						  subnode_target_type);
+		if (strings_count < 0)
+			return -EINVAL;
+	}
+
+	for (i = 0; i < strings_count; i++) {
+		ret = fdt_get_string_index(fdt, node, subnode_target_type,
+					   i, &name);
+		if (ret < 0)
+			return -EINVAL;
+
+		if (is_group)
+			selector = pinctrl_group_name_to_selector(dev, name);
+		else
+			selector = pinctrl_pin_name_to_selector(dev, name);
+		if (selector < 0)
+			return selector;
+
+		ret = pinctrl_generic_set_state_one(dev, config,
+						    is_group, selector);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
+{
+	struct udevice *child;
+	int ret;
+
+	ret = pinctrl_generic_set_state_subnode(dev, config);
+	if (ret)
+		return ret;
+
+	for (device_find_first_child(config, &child);
+	     child;
+	     device_find_next_child(&child)) {
+		ret = pinctrl_generic_set_state_subnode(dev, child);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c
new file mode 100644
index 0000000..ab03d8b
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-sandbox.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <dm/device.h>
+#include <dm/pinctrl.h>
+
+static const char * const sandbox_pins[] = {
+	"SCL",
+	"SDA",
+	"TX",
+	"RX",
+};
+
+static const char * const sandbox_groups[] = {
+	"i2c",
+	"serial_a",
+	"serial_b",
+	"spi",
+};
+
+static const char * const sandbox_functions[] = {
+	"i2c",
+	"serial",
+	"spi",
+};
+
+static const struct pinconf_param sandbox_conf_params[] = {
+	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+	{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+	{ "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+	{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+	{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+	{ "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+	{ "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+};
+
+static int sandbox_get_pins_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(sandbox_pins);
+}
+
+static const char *sandbox_get_pin_name(struct udevice *dev, unsigned selector)
+{
+	return sandbox_pins[selector];
+}
+
+static int sandbox_get_groups_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(sandbox_groups);
+}
+
+static const char *sandbox_get_group_name(struct udevice *dev,
+					  unsigned selector)
+{
+	return sandbox_groups[selector];
+}
+
+static int sandbox_get_functions_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(sandbox_functions);
+}
+
+static const char *sandbox_get_function_name(struct udevice *dev,
+					     unsigned selector)
+{
+	return sandbox_functions[selector];
+}
+
+static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector,
+			      unsigned func_selector)
+{
+	debug("sandbox pinmux: pin = %d (%s), function = %d (%s)\n",
+	      pin_selector, sandbox_get_pin_name(dev, pin_selector),
+	      func_selector, sandbox_get_function_name(dev, func_selector));
+
+	return 0;
+}
+
+static int sandbox_pinmux_group_set(struct udevice *dev,
+				    unsigned group_selector,
+				    unsigned func_selector)
+{
+	debug("sandbox pinmux: group = %d (%s), function = %d (%s)\n",
+	      group_selector, sandbox_get_group_name(dev, group_selector),
+	      func_selector, sandbox_get_function_name(dev, func_selector));
+
+	return 0;
+}
+
+static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector,
+			       unsigned param, unsigned argument)
+{
+	debug("sandbox pinconf: pin = %d (%s), param = %d, arg = %d\n",
+	      pin_selector, sandbox_get_pin_name(dev, pin_selector),
+	      param, argument);
+
+	return 0;
+}
+
+static int sandbox_pinconf_group_set(struct udevice *dev,
+				     unsigned group_selector,
+				     unsigned param, unsigned argument)
+{
+	debug("sandbox pinconf: group = %d (%s), param = %d, arg = %d\n",
+	      group_selector, sandbox_get_group_name(dev, group_selector),
+	      param, argument);
+
+	return 0;
+}
+
+const struct pinctrl_ops sandbox_pinctrl_ops = {
+	.get_pins_count = sandbox_get_pins_count,
+	.get_pin_name = sandbox_get_pin_name,
+	.get_groups_count = sandbox_get_groups_count,
+	.get_group_name = sandbox_get_group_name,
+	.get_functions_count = sandbox_get_functions_count,
+	.get_function_name = sandbox_get_function_name,
+	.pinmux_set = sandbox_pinmux_set,
+	.pinmux_group_set = sandbox_pinmux_group_set,
+	.pinconf_num_params = ARRAY_SIZE(sandbox_conf_params),
+	.pinconf_params = sandbox_conf_params,
+	.pinconf_set = sandbox_pinconf_set,
+	.pinconf_group_set = sandbox_pinconf_group_set,
+	.set_state = pinctrl_generic_set_state,
+};
+
+static const struct udevice_id sandbox_pinctrl_match[] = {
+	{ .compatible = "sandbox,pinctrl" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_pinctrl) = {
+	.name = "sandbox_pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = sandbox_pinctrl_match,
+	.ops = &sandbox_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
new file mode 100644
index 0000000..d96c201
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <dm/device.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/uclass.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(PINCTRL_FULL)
+/**
+ * pinctrl_config_one() - apply pinctrl settings for a single node
+ *
+ * @config: pin configuration node
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_config_one(struct udevice *config)
+{
+	struct udevice *pctldev;
+	const struct pinctrl_ops *ops;
+
+	pctldev = config;
+	for (;;) {
+		pctldev = dev_get_parent(pctldev);
+		if (!pctldev) {
+			dev_err(config, "could not find pctldev\n");
+			return -EINVAL;
+		}
+		if (pctldev->uclass->uc_drv->id == UCLASS_PINCTRL)
+			break;
+	}
+
+	ops = pinctrl_get_ops(pctldev);
+	return ops->set_state(pctldev, config);
+}
+
+/**
+ * pinctrl_select_state_full() - full implementation of pinctrl_select_state
+ *
+ * @dev: peripheral device
+ * @statename: state name, like "default"
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
+{
+	const void *fdt = gd->fdt_blob;
+	int node = dev->of_offset;
+	char propname[32]; /* long enough */
+	const fdt32_t *list;
+	uint32_t phandle;
+	int config_node;
+	struct udevice *config;
+	int state, size, i, ret;
+
+	state = fdt_find_string(fdt, node, "pinctrl-names", statename);
+	if (state < 0) {
+		char *end;
+		/*
+		 * If statename is not found in "pinctrl-names",
+		 * assume statename is just the integer state ID.
+		 */
+		state = simple_strtoul(statename, &end, 10);
+		if (*end)
+			return -EINVAL;
+	}
+
+	snprintf(propname, sizeof(propname), "pinctrl-%d", state);
+	list = fdt_getprop(fdt, node, propname, &size);
+	if (!list)
+		return -EINVAL;
+
+	size /= sizeof(*list);
+	for (i = 0; i < size; i++) {
+		phandle = fdt32_to_cpu(*list++);
+
+		config_node = fdt_node_offset_by_phandle(fdt, phandle);
+		if (config_node < 0) {
+			dev_err(dev, "prop %s index %d invalid phandle\n",
+				propname, i);
+			return -EINVAL;
+		}
+		ret = uclass_get_device_by_of_offset(UCLASS_PINCONFIG,
+						     config_node, &config);
+		if (ret)
+			return ret;
+
+		ret = pinctrl_config_one(config);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * pinconfig_post-bind() - post binding for PINCONFIG uclass
+ * Recursively bind its children as pinconfig devices.
+ *
+ * @dev: pinconfig device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinconfig_post_bind(struct udevice *dev)
+{
+	const void *fdt = gd->fdt_blob;
+	int offset = dev->of_offset;
+	const char *name;
+	int ret;
+
+	for (offset = fdt_first_subnode(fdt, offset);
+	     offset > 0;
+	     offset = fdt_next_subnode(fdt, offset)) {
+		/*
+		 * If this node has "compatible" property, this is not
+		 * a pin configuration node, but a normal device. skip.
+		 */
+		fdt_get_property(fdt, offset, "compatible", &ret);
+		if (ret >= 0)
+			continue;
+
+		if (ret != -FDT_ERR_NOTFOUND)
+			return ret;
+
+		name = fdt_get_name(fdt, offset, NULL);
+		if (!name)
+			return -EINVAL;
+		ret = device_bind_driver_to_node(dev, "pinconfig", name,
+						 offset, NULL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+UCLASS_DRIVER(pinconfig) = {
+	.id = UCLASS_PINCONFIG,
+	.post_bind = pinconfig_post_bind,
+	.name = "pinconfig",
+};
+
+U_BOOT_DRIVER(pinconfig_generic) = {
+	.name = "pinconfig",
+	.id = UCLASS_PINCONFIG,
+};
+
+#else
+static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
+{
+	return -ENODEV;
+}
+
+static int pinconfig_post_bind(struct udevice *dev)
+{
+	return 0;
+}
+#endif
+
+/**
+ * pinctrl_select_state_simple() - simple implementation of pinctrl_select_state
+ *
+ * @dev: peripheral device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_select_state_simple(struct udevice *dev)
+{
+	struct udevice *pctldev;
+	struct pinctrl_ops *ops;
+	int ret;
+
+	/*
+	 * For simplicity, assume the first device of PINCTRL uclass
+	 * is the correct one.  This is most likely OK as there is
+	 * usually only one pinctrl device on the system.
+	 */
+	ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
+	if (ret)
+		return ret;
+
+	ops = pinctrl_get_ops(pctldev);
+	if (!ops->set_state_simple) {
+		dev_dbg(dev, "set_state_simple op missing\n");
+		return -ENOSYS;
+	}
+
+	return ops->set_state_simple(pctldev, dev);
+}
+
+int pinctrl_select_state(struct udevice *dev, const char *statename)
+{
+	/*
+	 * Try full-implemented pinctrl first.
+	 * If it fails or is not implemented, try simple one.
+	 */
+	if (pinctrl_select_state_full(dev, statename))
+		return pinctrl_select_state_simple(dev);
+
+	return 0;
+}
+
+/**
+ * pinconfig_post-bind() - post binding for PINCTRL uclass
+ * Recursively bind child nodes as pinconfig devices in case of full pinctrl.
+ *
+ * @dev: pinctrl device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_post_bind(struct udevice *dev)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+	if (!ops) {
+		dev_dbg(dev, "ops is not set.  Do not bind.\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * If set_state callback is set, we assume this pinctrl driver is the
+	 * full implementation.  In this case, its child nodes should be bound
+	 * so that peripheral devices can easily search in parent devices
+	 * during later DT-parsing.
+	 */
+	if (ops->set_state)
+		return pinconfig_post_bind(dev);
+
+	return 0;
+}
+
+UCLASS_DRIVER(pinctrl) = {
+	.id = UCLASS_PINCTRL,
+	.post_bind = pinctrl_post_bind,
+	.name = "pinctrl",
+};
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 2b6d1e4..6275a11 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -364,7 +364,7 @@
 	fdt_addr_t addr;
 
 	/* try Processor Local Bus device first */
-	addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+	addr = dev_get_addr(dev);
 #ifdef CONFIG_PCI
 	if (addr == FDT_ADDR_T_NONE) {
 		/* then try pci device */
diff --git a/drivers/serial/serial_arc.c b/drivers/serial/serial_arc.c
index 54e596c..7dbb49f 100644
--- a/drivers/serial/serial_arc.c
+++ b/drivers/serial/serial_arc.c
@@ -133,8 +133,7 @@
 	struct arc_serial_platdata *plat = dev_get_platdata(dev);
 	DECLARE_GLOBAL_DATA_PTR;
 
-	plat->reg = (struct arc_serial_regs *)fdtdec_get_addr(gd->fdt_blob,
-							dev->of_offset, "reg");
+	plat->reg = (struct arc_serial_regs *)dev_get_addr(dev);
 	plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
 				       "clock-frequency", 0);
 
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index 917b603..ecf3bc0 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -365,7 +365,7 @@
 	struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
 	fdt_addr_t addr;
 
-	addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+	addr = dev_get_addr(dev);
 	if (addr == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 21cb566..3f0b588 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -169,7 +169,7 @@
 	struct s5p_serial_platdata *plat = dev->platdata;
 	fdt_addr_t addr;
 
-	addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+	addr = dev_get_addr(dev);
 	if (addr == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 8f5c0fc..86ee90f 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -134,7 +134,7 @@
 	const void *blob = gd->fdt_blob;
 	int node = bus->of_offset;
 
-	plat->regs = (struct dw_spi *)fdtdec_get_addr(blob, node, "reg");
+	plat->regs = (struct dw_spi *)dev_get_addr(bus);
 
 	/* Use 500KHz as a suitable default */
 	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index 418b481..44948c3 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -255,7 +255,7 @@
 	const void *blob = gd->fdt_blob;
 	int node = bus->of_offset;
 
-	plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
+	plat->regs = (struct exynos_spi *)dev_get_addr(bus);
 	plat->periph_id = pinmux_decode_periph_id(blob, node);
 
 	if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
index 3881b2e..887edd8 100644
--- a/drivers/spi/fsl_dspi.c
+++ b/drivers/spi/fsl_dspi.c
@@ -654,7 +654,7 @@
 	plat->num_chipselect =
 		fdtdec_get_int(blob, node, "num-cs", FSL_DSPI_MAX_CHIPSELECT);
 
-	addr = fdtdec_get_addr(blob, node, "reg");
+	addr = dev_get_addr(bus);
 	if (addr == FDT_ADDR_T_NONE) {
 		debug("DSPI: Can't get base address or size\n");
 		return -ENOMEM;
diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c
index d7eecd5..a965f80 100644
--- a/drivers/spi/tegra114_spi.c
+++ b/drivers/spi/tegra114_spi.c
@@ -118,7 +118,7 @@
 	const void *blob = gd->fdt_blob;
 	int node = bus->of_offset;
 
-	plat->base = fdtdec_get_addr(blob, node, "reg");
+	plat->base = dev_get_addr(bus);
 	plat->periph_id = clock_decode_periph_id(blob, node);
 
 	if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c
index 82c1b84..afa0848 100644
--- a/drivers/spi/tegra20_sflash.c
+++ b/drivers/spi/tegra20_sflash.c
@@ -90,7 +90,7 @@
 	const void *blob = gd->fdt_blob;
 	int node = bus->of_offset;
 
-	plat->base = fdtdec_get_addr(blob, node, "reg");
+	plat->base = dev_get_addr(bus);
 	plat->periph_id = clock_decode_periph_id(blob, node);
 
 	if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index f6fb89b..fbb665b 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -106,7 +106,7 @@
 	const void *blob = gd->fdt_blob;
 	int node = bus->of_offset;
 
-	plat->base = fdtdec_get_addr(blob, node, "reg");
+	plat->base = dev_get_addr(bus);
 	plat->periph_id = clock_decode_periph_id(blob, node);
 
 	if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index 7ae1f0e..310fb69 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -72,7 +72,7 @@
 	const void *blob = gd->fdt_blob;
 	int node = bus->of_offset;
 
-	plat->regs = (struct zynq_spi_regs *)fdtdec_get_addr(blob, node, "reg");
+	plat->regs = (struct zynq_spi_regs *)dev_get_addr(bus);
 
 	/* FIXME: Use 250MHz as a suitable default */
 	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
index f408b8a..6bc8fdd 100644
--- a/drivers/tpm/Kconfig
+++ b/drivers/tpm/Kconfig
@@ -1,7 +1,76 @@
+#
+# TPM subsystem configuration
+#
+
+menu "TPM support"
+
+config DM_TPM
+	bool "Enable driver model for Trusted Platform Module drivers"
+	depends on DM && TPM
+	help
+          Enable driver model for TPMs. The TIS interface (tis_open(),
+	  tis_sendrecv(), etc.) is then implemented by the TPM uclass. Note
+	  that even with driver model only a single TPM is currently
+	  supported, since the tpm library assumes this.
+
 config TPM_TIS_SANDBOX
 	bool "Enable sandbox TPM driver"
+	depends on SANDBOX
 	help
 	  This driver emulates a TPM, providing access to base functions
 	  such as reading and writing TPM private data. This is enough to
 	  support Chrome OS verified boot. Extend functionality is not
 	  implemented.
+
+config TPM_ATMEL_TWI
+	bool "Enable Atmel TWI TPM device driver"
+	depends on TPM
+	help
+	  This driver supports an Atmel TPM device connected on the I2C bus.
+	  The usual tpm operations and the 'tpm' command can be used to talk
+	  to the device using the standard TPM Interface Specification (TIS)
+	  protocol
+
+config TPM_TIS_I2C
+	bool "Enable support for Infineon SLB9635/45 TPMs on I2C"
+	depends on TPM && DM_I2C
+	help
+	  This driver supports Infineon TPM devices connected on the I2C bus.
+	  The usual tpm operations and the 'tpm' command can be used to talk
+	  to the device using the standard TPM Interface Specification (TIS)
+	  protocol
+
+config TPM_TIS_I2C_BURST_LIMITATION
+	bool "Enable I2C burst length limitation"
+	depends on TPM_TIS_I2C
+	help
+	  Some broken TPMs have a limitation on the number of bytes they can
+	  receive in one message. Enable this option to allow you to set this
+	  option. The can allow a broken TPM to be used by splitting messages
+	  into separate pieces.
+
+config TPM_TIS_I2C_BURST_LIMITATION_LEN
+	int "Length"
+	depends on TPM_TIS_I2C_BURST_LIMITATION
+	help
+	  Use this to set the burst limitation length
+
+config TPM_TIS_LPC
+	bool "Enable support for Infineon SLB9635/45 TPMs on LPC"
+	depends on TPM && X86
+	help
+	  This driver supports Infineon TPM devices connected on the I2C bus.
+	  The usual tpm operations and the 'tpm' command can be used to talk
+	  to the device using the standard TPM Interface Specification (TIS)
+	  protocol
+
+config TPM_AUTH_SESSIONS
+	bool "Enable TPM authentication session support"
+	depends on TPM
+	help
+	  Enable support for authorised (AUTH1) commands as specified in the
+	  TCG Main Specification 1.2. OIAP-authorised versions of the commands
+	  TPM_LoadKey2 and TPM_GetPubKey are provided. Both features are
+	  available using the 'tpm' command, too.
+
+endmenu
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 150570e..0d328f8 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -3,9 +3,9 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-# TODO: Merge tpm_tis_lpc.c with tpm.c
+obj-$(CONFIG_DM_TPM) += tpm-uclass.o
+
 obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
-obj-$(CONFIG_TPM_TIS_I2C) += tpm.o
 obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o
 obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
 obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
new file mode 100644
index 0000000..b6e1fc5
--- /dev/null
+++ b/drivers/tpm/tpm-uclass.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <tpm.h>
+#include <linux/unaligned/be_byteshift.h>
+#include "tpm_internal.h"
+
+int tpm_open(struct udevice *dev)
+{
+	struct tpm_ops *ops = tpm_get_ops(dev);
+
+	if (!ops->open)
+		return -ENOSYS;
+
+	return ops->open(dev);
+}
+
+int tpm_close(struct udevice *dev)
+{
+	struct tpm_ops *ops = tpm_get_ops(dev);
+
+	if (!ops->close)
+		return -ENOSYS;
+
+	return ops->close(dev);
+}
+
+int tpm_get_desc(struct udevice *dev, char *buf, int size)
+{
+	struct tpm_ops *ops = tpm_get_ops(dev);
+
+	if (!ops->get_desc)
+		return -ENOSYS;
+
+	return ops->get_desc(dev, buf, size);
+}
+
+/* Returns max number of milliseconds to wait */
+static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv,
+					       u32 ordinal)
+{
+	int duration_idx = TPM_UNDEFINED;
+	int duration = 0;
+
+	if (ordinal < TPM_MAX_ORDINAL) {
+		duration_idx = tpm_ordinal_duration[ordinal];
+	} else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
+			TPM_MAX_PROTECTED_ORDINAL) {
+		duration_idx = tpm_protected_ordinal_duration[
+				ordinal & TPM_PROTECTED_ORDINAL_MASK];
+	}
+
+	if (duration_idx != TPM_UNDEFINED)
+		duration = priv->duration_ms[duration_idx];
+
+	if (duration <= 0)
+		return 2 * 60 * 1000; /* Two minutes timeout */
+	else
+		return duration;
+}
+
+int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
+	uint8_t *recvbuf, size_t *recv_size)
+{
+	struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+	struct tpm_ops *ops = tpm_get_ops(dev);
+	ulong start, stop;
+	uint count, ordinal;
+	int ret, ret2;
+
+	if (ops->xfer)
+		return ops->xfer(dev, sendbuf, send_size, recvbuf, recv_size);
+
+	if (!ops->send || !ops->recv)
+		return -ENOSYS;
+
+	/* switch endianess: big->little */
+	count = get_unaligned_be32(sendbuf + TPM_CMD_COUNT_BYTE);
+	ordinal = get_unaligned_be32(sendbuf + TPM_CMD_ORDINAL_BYTE);
+
+	if (count == 0) {
+		debug("no data\n");
+		return -ENODATA;
+	}
+	if (count > send_size) {
+		debug("invalid count value %x %zx\n", count, send_size);
+		return -E2BIG;
+	}
+
+	debug("%s: Calling send\n", __func__);
+	ret = ops->send(dev, sendbuf, send_size);
+	if (ret < 0)
+		return ret;
+
+	start = get_timer(0);
+	stop = tpm_tis_i2c_calc_ordinal_duration(priv, ordinal);
+	do {
+		ret = ops->recv(dev, priv->buf, sizeof(priv->buf));
+		if (ret >= 0) {
+			if (ret > *recv_size)
+				return -ENOSPC;
+			memcpy(recvbuf, priv->buf, ret);
+			*recv_size = ret;
+			ret = 0;
+			break;
+		} else if (ret != -EAGAIN) {
+			return ret;
+		}
+
+		mdelay(priv->retry_time_ms);
+		if (get_timer(start) > stop) {
+			ret = -ETIMEDOUT;
+			break;
+		}
+	} while (ret);
+
+	ret2 = ops->cleanup ? ops->cleanup(dev) : 0;
+
+	return ret2 ? ret2 : ret;
+}
+
+UCLASS_DRIVER(tpm) = {
+	.id             = UCLASS_TPM,
+	.name           = "tpm",
+	.flags          = DM_UC_FLAG_SEQ_ALIAS,
+	.per_device_auto_alloc_size	= sizeof(struct tpm_chip_priv),
+};
diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c
deleted file mode 100644
index a650892..0000000
--- a/drivers/tpm/tpm.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * Copyright (C) 2011 Infineon Technologies
- *
- * Authors:
- * Peter Huewe <huewe.external@infineon.com>
- *
- * Description:
- * Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
- *
- * It is based on the Linux kernel driver tpm.c from Leendert van
- * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
- *
- * Version: 2.1.1
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <config.h>
-#include <common.h>
-#include <dm.h>
-#include <linux/compiler.h>
-#include <fdtdec.h>
-#include <i2c.h>
-#include <tpm.h>
-#include <asm-generic/errno.h>
-#include <linux/types.h>
-#include <linux/unaligned/be_byteshift.h>
-
-#include "tpm_private.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-/* TPM configuration */
-struct tpm {
-#ifdef CONFIG_DM_I2C
-	struct udevice *dev;
-#else
-	int i2c_bus;
-	int slave_addr;
-	int old_bus;
-#endif
-	char inited;
-} tpm;
-
-/* Global structure for tpm chip data */
-static struct tpm_chip g_chip;
-
-enum tpm_duration {
-	TPM_SHORT = 0,
-	TPM_MEDIUM = 1,
-	TPM_LONG = 2,
-	TPM_UNDEFINED,
-};
-
-/* Extended error numbers from linux (see errno.h) */
-#define ECANCELED	125	/* Operation Canceled */
-
-/* Timer frequency. Corresponds to msec timer resolution*/
-#define HZ		1000
-
-#define TPM_MAX_ORDINAL			243
-#define TPM_MAX_PROTECTED_ORDINAL	12
-#define TPM_PROTECTED_ORDINAL_MASK	0xFF
-
-#define TPM_CMD_COUNT_BYTE	2
-#define TPM_CMD_ORDINAL_BYTE	6
-
-/*
- * Array with one entry per ordinal defining the maximum amount
- * of time the chip could take to return the result.  The ordinal
- * designation of short, medium or long is defined in a table in
- * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
- * values of the SHORT, MEDIUM, and LONG durations are retrieved
- * from the chip during initialization with a call to tpm_get_timeouts.
- */
-static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
-	TPM_UNDEFINED,		/* 0 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 5 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 10 */
-	TPM_SHORT,
-};
-
-static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
-	TPM_UNDEFINED,		/* 0 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 5 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 10 */
-	TPM_SHORT,
-	TPM_MEDIUM,
-	TPM_LONG,
-	TPM_LONG,
-	TPM_MEDIUM,		/* 15 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_MEDIUM,
-	TPM_LONG,
-	TPM_SHORT,		/* 20 */
-	TPM_SHORT,
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_SHORT,		/* 25 */
-	TPM_SHORT,
-	TPM_MEDIUM,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_MEDIUM,		/* 30 */
-	TPM_LONG,
-	TPM_MEDIUM,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,		/* 35 */
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_MEDIUM,		/* 40 */
-	TPM_LONG,
-	TPM_MEDIUM,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,		/* 45 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_LONG,
-	TPM_MEDIUM,		/* 50 */
-	TPM_MEDIUM,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 55 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_MEDIUM,		/* 60 */
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_MEDIUM,		/* 65 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 70 */
-	TPM_SHORT,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 75 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_LONG,		/* 80 */
-	TPM_UNDEFINED,
-	TPM_MEDIUM,
-	TPM_LONG,
-	TPM_SHORT,
-	TPM_UNDEFINED,		/* 85 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 90 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_UNDEFINED,		/* 95 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_MEDIUM,		/* 100 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 105 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 110 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,		/* 115 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_LONG,		/* 120 */
-	TPM_LONG,
-	TPM_MEDIUM,
-	TPM_UNDEFINED,
-	TPM_SHORT,
-	TPM_SHORT,		/* 125 */
-	TPM_SHORT,
-	TPM_LONG,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,		/* 130 */
-	TPM_MEDIUM,
-	TPM_UNDEFINED,
-	TPM_SHORT,
-	TPM_MEDIUM,
-	TPM_UNDEFINED,		/* 135 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 140 */
-	TPM_SHORT,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 145 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 150 */
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_UNDEFINED,		/* 155 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 160 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 165 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_LONG,		/* 170 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 175 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_MEDIUM,		/* 180 */
-	TPM_SHORT,
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_MEDIUM,		/* 185 */
-	TPM_SHORT,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 190 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 195 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 200 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,
-	TPM_SHORT,		/* 205 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_MEDIUM,		/* 210 */
-	TPM_UNDEFINED,
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_MEDIUM,
-	TPM_UNDEFINED,		/* 215 */
-	TPM_MEDIUM,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,
-	TPM_SHORT,		/* 220 */
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_SHORT,
-	TPM_UNDEFINED,		/* 225 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 230 */
-	TPM_LONG,
-	TPM_MEDIUM,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,		/* 235 */
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_UNDEFINED,
-	TPM_SHORT,		/* 240 */
-	TPM_UNDEFINED,
-	TPM_MEDIUM,
-};
-
-/* Returns max number of milliseconds to wait */
-static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
-		u32 ordinal)
-{
-	int duration_idx = TPM_UNDEFINED;
-	int duration = 0;
-
-	if (ordinal < TPM_MAX_ORDINAL) {
-		duration_idx = tpm_ordinal_duration[ordinal];
-	} else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
-			TPM_MAX_PROTECTED_ORDINAL) {
-		duration_idx = tpm_protected_ordinal_duration[
-				ordinal & TPM_PROTECTED_ORDINAL_MASK];
-	}
-
-	if (duration_idx != TPM_UNDEFINED)
-		duration = chip->vendor.duration[duration_idx];
-
-	if (duration <= 0)
-		return 2 * 60 * HZ; /* Two minutes timeout */
-	else
-		return duration;
-}
-
-static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz)
-{
-	int rc;
-	u32 count, ordinal;
-	unsigned long start, stop;
-
-	struct tpm_chip *chip = &g_chip;
-
-	/* switch endianess: big->little */
-	count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE);
-	ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE);
-
-	if (count == 0) {
-		error("no data\n");
-		return -ENODATA;
-	}
-	if (count > bufsiz) {
-		error("invalid count value %x %zx\n", count, bufsiz);
-		return -E2BIG;
-	}
-
-	debug("Calling send\n");
-	rc = chip->vendor.send(chip, (u8 *)buf, count);
-	debug("   ... done calling send\n");
-	if (rc < 0) {
-		error("tpm_transmit: tpm_send: error %d\n", rc);
-		goto out;
-	}
-
-	if (chip->vendor.irq)
-		goto out_recv;
-
-	start = get_timer(0);
-	stop = tpm_calc_ordinal_duration(chip, ordinal);
-	do {
-		debug("waiting for status... %ld %ld\n", start, stop);
-		u8 status = chip->vendor.status(chip);
-		if ((status & chip->vendor.req_complete_mask) ==
-		    chip->vendor.req_complete_val) {
-			debug("...got it;\n");
-			goto out_recv;
-		}
-
-		if (status == chip->vendor.req_canceled) {
-			error("Operation Canceled\n");
-			rc = -ECANCELED;
-			goto out;
-		}
-		udelay(TPM_TIMEOUT * 1000);
-	} while (get_timer(start) < stop);
-
-	chip->vendor.cancel(chip);
-	error("Operation Timed out\n");
-	rc = -ETIME;
-	goto out;
-
-out_recv:
-	debug("out_recv: reading response...\n");
-	rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE);
-	if (rc < 0)
-		error("tpm_transmit: tpm_recv: error %d\n", rc);
-
-out:
-	return rc;
-}
-
-#ifdef CONFIG_DM_I2C
-static int tpm_open_dev(struct udevice *dev)
-{
-	int rc;
-
-	debug("%s: start\n", __func__);
-	if (g_chip.is_open)
-		return -EBUSY;
-	rc = tpm_vendor_init_dev(dev);
-	if (rc < 0)
-		g_chip.is_open = 0;
-	return rc;
-}
-#else
-static int tpm_open(uint32_t dev_addr)
-{
-	int rc;
-
-	if (g_chip.is_open)
-		return -EBUSY;
-	rc = tpm_vendor_init(dev_addr);
-	if (rc < 0)
-		g_chip.is_open = 0;
-	return rc;
-}
-#endif
-static void tpm_close(void)
-{
-	if (g_chip.is_open) {
-		tpm_vendor_cleanup(&g_chip);
-		g_chip.is_open = 0;
-	}
-}
-
-static int tpm_select(void)
-{
-#ifndef CONFIG_DM_I2C
-	int ret;
-
-	tpm.old_bus = i2c_get_bus_num();
-	if (tpm.old_bus != tpm.i2c_bus) {
-		ret = i2c_set_bus_num(tpm.i2c_bus);
-		if (ret) {
-			debug("%s: Fail to set i2c bus %d\n", __func__,
-			      tpm.i2c_bus);
-			return -1;
-		}
-	}
-#endif
-	return 0;
-}
-
-static int tpm_deselect(void)
-{
-#ifndef CONFIG_DM_I2C
-	int ret;
-
-	if (tpm.old_bus != i2c_get_bus_num()) {
-		ret = i2c_set_bus_num(tpm.old_bus);
-		if (ret) {
-			debug("%s: Fail to restore i2c bus %d\n",
-			      __func__, tpm.old_bus);
-			return -1;
-		}
-	}
-	tpm.old_bus = -1;
-#endif
-	return 0;
-}
-
-/**
- * Decode TPM configuration.
- *
- * @param dev	Returns a configuration of TPM device
- * @return 0 if ok, -1 on error
- */
-static int tpm_decode_config(struct tpm *dev)
-{
-	const void *blob = gd->fdt_blob;
-	int parent;
-	int node;
-
-	node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
-	if (node < 0) {
-		node = fdtdec_next_compatible(blob, 0,
-				COMPAT_INFINEON_SLB9645_TPM);
-	}
-	if (node < 0) {
-		debug("%s: Node not found\n", __func__);
-		return -1;
-	}
-	parent = fdt_parent_offset(blob, node);
-	if (parent < 0) {
-		debug("%s: Cannot find node parent\n", __func__);
-		return -1;
-	}
-#ifdef CONFIG_DM_I2C
-	struct udevice *bus;
-	int chip_addr;
-	int ret;
-
-	/*
-	 * TODO(sjg@chromium.org): Remove this when driver model supports
-	 * TPMs
-	 */
-	ret = uclass_get_device_by_of_offset(UCLASS_I2C, parent, &bus);
-	if (ret) {
-		debug("Cannot find bus for node '%s: ret=%d'\n",
-		      fdt_get_name(blob, parent, NULL), ret);
-		return ret;
-	}
-
-	chip_addr = fdtdec_get_int(blob, node, "reg", -1);
-	if (chip_addr == -1) {
-		debug("Cannot find reg property for node '%s: ret=%d'\n",
-		      fdt_get_name(blob, node, NULL), ret);
-		return ret;
-	}
-	/*
-	 * TODO(sjg@chromium.org): Older TPMs will need to use the older method
-	 * in iic_tpm_read() so the offset length needs to be 0 here.
-	 */
-	ret = i2c_get_chip(bus, chip_addr, 1, &dev->dev);
-	if (ret) {
-		debug("Cannot find device for node '%s: ret=%d'\n",
-		      fdt_get_name(blob, node, NULL), ret);
-		return ret;
-	}
-#else
-	int i2c_bus;
-
-	i2c_bus = i2c_get_bus_num_fdt(parent);
-	if (i2c_bus < 0)
-		return -1;
-	dev->i2c_bus = i2c_bus;
-	dev->slave_addr = fdtdec_get_addr(blob, node, "reg");
-#endif
-
-	return 0;
-}
-
-struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry)
-{
-	struct tpm_chip *chip;
-
-	/* Driver specific per-device data */
-	chip = &g_chip;
-	memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
-	chip->is_open = 1;
-
-	return chip;
-}
-
-int tis_init(void)
-{
-	if (tpm.inited)
-		return 0;
-
-	if (tpm_decode_config(&tpm))
-		return -1;
-
-	if (tpm_select())
-		return -1;
-
-#ifndef CONFIG_DM_I2C
-	/*
-	 * Probe TPM twice; the first probing might fail because TPM is asleep,
-	 * and the probing can wake up TPM.
-	 */
-	if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) {
-		debug("%s: fail to probe i2c addr 0x%x\n", __func__,
-		      tpm.slave_addr);
-		return -1;
-	}
-#endif
-
-	tpm_deselect();
-	debug("%s: done\n", __func__);
-
-	tpm.inited = 1;
-
-	return 0;
-}
-
-int tis_open(void)
-{
-	int rc;
-
-	if (!tpm.inited)
-		return -1;
-
-	if (tpm_select())
-		return -1;
-
-#ifdef CONFIG_DM_I2C
-	rc = tpm_open_dev(tpm.dev);
-#else
-	rc = tpm_open(tpm.slave_addr);
-#endif
-
-	tpm_deselect();
-
-	return rc;
-}
-
-int tis_close(void)
-{
-	if (!tpm.inited)
-		return -1;
-
-	if (tpm_select())
-		return -1;
-
-	tpm_close();
-
-	tpm_deselect();
-
-	return 0;
-}
-
-int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
-		uint8_t *recvbuf, size_t *rbuf_len)
-{
-	int len;
-	uint8_t buf[4096];
-
-	if (!tpm.inited)
-		return -1;
-
-	if (sizeof(buf) < sbuf_size)
-		return -1;
-
-	memcpy(buf, sendbuf, sbuf_size);
-
-	if (tpm_select())
-		return -1;
-
-	len = tpm_transmit(buf, sbuf_size);
-
-	tpm_deselect();
-
-	if (len < 10) {
-		*rbuf_len = 0;
-		return -1;
-	}
-
-	memcpy(recvbuf, buf, len);
-	*rbuf_len = len;
-
-	return 0;
-}
diff --git a/drivers/tpm/tpm_atmel_twi.c b/drivers/tpm/tpm_atmel_twi.c
index 361a772..205d7a5 100644
--- a/drivers/tpm/tpm_atmel_twi.c
+++ b/drivers/tpm/tpm_atmel_twi.c
@@ -1,18 +1,9 @@
 /*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * Copyright (C) 2013 Guntermann & Drunck, GmbH
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Written by Dirk Eibach <eibach@gdsys.de>
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0+
  */
 
 #include <common.h>
diff --git a/drivers/tpm/tpm_internal.h b/drivers/tpm/tpm_internal.h
new file mode 100644
index 0000000..cd29dba
--- /dev/null
+++ b/drivers/tpm/tpm_internal.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __tpm_internal_h
+#define __tpm_internal_h
+
+enum {
+	TPM_MAX_ORDINAL			= 243,
+	TPM_MAX_PROTECTED_ORDINAL	= 12,
+	TPM_PROTECTED_ORDINAL_MASK	= 0xff,
+	TPM_CMD_COUNT_BYTE		= 2,
+	TPM_CMD_ORDINAL_BYTE		= 6,
+};
+
+/*
+ * Array with one entry per ordinal defining the maximum amount
+ * of time the chip could take to return the result.  The ordinal
+ * designation of short, medium or long is defined in a table in
+ * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
+ * values of the SHORT, MEDIUM, and LONG durations are retrieved
+ * from the chip during initialization with a call to tpm_get_timeouts.
+ */
+static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
+	TPM_UNDEFINED,		/* 0 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 5 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 10 */
+	TPM_SHORT,
+};
+
+static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
+	TPM_UNDEFINED,		/* 0 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 5 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 10 */
+	TPM_SHORT,
+	TPM_MEDIUM,
+	TPM_LONG,
+	TPM_LONG,
+	TPM_MEDIUM,		/* 15 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_MEDIUM,
+	TPM_LONG,
+	TPM_SHORT,		/* 20 */
+	TPM_SHORT,
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_SHORT,		/* 25 */
+	TPM_SHORT,
+	TPM_MEDIUM,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_MEDIUM,		/* 30 */
+	TPM_LONG,
+	TPM_MEDIUM,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,		/* 35 */
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_MEDIUM,		/* 40 */
+	TPM_LONG,
+	TPM_MEDIUM,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,		/* 45 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_LONG,
+	TPM_MEDIUM,		/* 50 */
+	TPM_MEDIUM,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 55 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_MEDIUM,		/* 60 */
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_MEDIUM,		/* 65 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 70 */
+	TPM_SHORT,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 75 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_LONG,		/* 80 */
+	TPM_UNDEFINED,
+	TPM_MEDIUM,
+	TPM_LONG,
+	TPM_SHORT,
+	TPM_UNDEFINED,		/* 85 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 90 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_UNDEFINED,		/* 95 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_MEDIUM,		/* 100 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 105 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 110 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,		/* 115 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_LONG,		/* 120 */
+	TPM_LONG,
+	TPM_MEDIUM,
+	TPM_UNDEFINED,
+	TPM_SHORT,
+	TPM_SHORT,		/* 125 */
+	TPM_SHORT,
+	TPM_LONG,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,		/* 130 */
+	TPM_MEDIUM,
+	TPM_UNDEFINED,
+	TPM_SHORT,
+	TPM_MEDIUM,
+	TPM_UNDEFINED,		/* 135 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 140 */
+	TPM_SHORT,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 145 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 150 */
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_UNDEFINED,		/* 155 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 160 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 165 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_LONG,		/* 170 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 175 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_MEDIUM,		/* 180 */
+	TPM_SHORT,
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_MEDIUM,		/* 185 */
+	TPM_SHORT,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 190 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 195 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 200 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,
+	TPM_SHORT,		/* 205 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_MEDIUM,		/* 210 */
+	TPM_UNDEFINED,
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_MEDIUM,
+	TPM_UNDEFINED,		/* 215 */
+	TPM_MEDIUM,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,
+	TPM_SHORT,		/* 220 */
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_SHORT,
+	TPM_UNDEFINED,		/* 225 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 230 */
+	TPM_LONG,
+	TPM_MEDIUM,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,		/* 235 */
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_UNDEFINED,
+	TPM_SHORT,		/* 240 */
+	TPM_UNDEFINED,
+	TPM_MEDIUM,
+};
+
+#endif
diff --git a/drivers/tpm/tpm_private.h b/drivers/tpm/tpm_private.h
deleted file mode 100644
index 8894c98..0000000
--- a/drivers/tpm/tpm_private.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2011 Infineon Technologies
- *
- * Authors:
- * Peter Huewe <huewe.external@infineon.com>
- *
- * Version: 2.1.1
- *
- * Description:
- * Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
- *
- * It is based on the Linux kernel driver tpm.c from Leendert van
- * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
- *
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _TPM_PRIVATE_H_
-#define _TPM_PRIVATE_H_
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-
-enum tpm_timeout {
-	TPM_TIMEOUT = 5,	/* msecs */
-};
-
-/* Size of external transmit buffer (used in tpm_transmit)*/
-#define TPM_BUFSIZE 4096
-
-/* Index of Count field in TPM response buffer */
-#define TPM_RSP_SIZE_BYTE	2
-#define TPM_RSP_RC_BYTE		6
-
-struct tpm_chip;
-
-struct tpm_vendor_specific {
-	const u8 req_complete_mask;
-	const u8 req_complete_val;
-	const u8 req_canceled;
-	int irq;
-	int (*recv) (struct tpm_chip *, u8 *, size_t);
-	int (*send) (struct tpm_chip *, u8 *, size_t);
-	void (*cancel) (struct tpm_chip *);
-	u8(*status) (struct tpm_chip *);
-	int locality;
-	unsigned long timeout_a, timeout_b, timeout_c, timeout_d;  /* msec */
-	unsigned long duration[3];  /* msec */
-};
-
-struct tpm_chip {
-	int is_open;
-	struct tpm_vendor_specific vendor;
-};
-
-struct tpm_input_header {
-	__be16 tag;
-	__be32 length;
-	__be32 ordinal;
-} __packed;
-
-struct tpm_output_header {
-	__be16 tag;
-	__be32 length;
-	__be32 return_code;
-} __packed;
-
-struct timeout_t {
-	__be32 a;
-	__be32 b;
-	__be32 c;
-	__be32 d;
-} __packed;
-
-struct duration_t {
-	__be32 tpm_short;
-	__be32 tpm_medium;
-	__be32 tpm_long;
-} __packed;
-
-union cap_t {
-	struct timeout_t timeout;
-	struct duration_t duration;
-};
-
-struct tpm_getcap_params_in {
-	__be32 cap;
-	__be32 subcap_size;
-	__be32 subcap;
-} __packed;
-
-struct tpm_getcap_params_out {
-	__be32 cap_size;
-	union cap_t cap;
-} __packed;
-
-union tpm_cmd_header {
-	struct tpm_input_header in;
-	struct tpm_output_header out;
-};
-
-union tpm_cmd_params {
-	struct tpm_getcap_params_out getcap_out;
-	struct tpm_getcap_params_in getcap_in;
-};
-
-struct tpm_cmd_t {
-	union tpm_cmd_header header;
-	union tpm_cmd_params params;
-} __packed;
-
-struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *);
-
-int tpm_vendor_init(uint32_t dev_addr);
-
-struct udevice;
-int tpm_vendor_init_dev(struct udevice *dev);
-
-void tpm_vendor_cleanup(struct tpm_chip *chip);
-
-
-#endif
diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c
index cc740e9..9afe46c 100644
--- a/drivers/tpm/tpm_tis_i2c.c
+++ b/drivers/tpm/tpm_tis_i2c.c
@@ -17,131 +17,33 @@
  *
  * Version: 2.1.1
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #include <common.h>
 #include <dm.h>
 #include <fdtdec.h>
-#include <linux/compiler.h>
 #include <i2c.h>
+#include <tis.h>
 #include <tpm.h>
 #include <asm-generic/errno.h>
+#include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/unaligned/be_byteshift.h>
 
-#include "tpm_private.h"
+#include "tpm_tis_i2c.h"
+#include "tpm_internal.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Address of the TPM on the I2C bus */
-#define TPM_I2C_ADDR		0x20
-
-/* Max buffer size supported by our tpm */
-#define TPM_DEV_BUFSIZE		1260
-
-/* Max number of iterations after i2c NAK */
-#define MAX_COUNT		3
-
-/*
- * Max number of iterations after i2c NAK for 'long' commands
- *
- * We need this especially for sending TPM_READY, since the cleanup after the
- * transtion to the ready state may take some time, but it is unpredictable
- * how long it will take.
- */
-#define MAX_COUNT_LONG		50
-
-#define SLEEP_DURATION		60	/* in usec */
-#define SLEEP_DURATION_LONG	210	/* in usec */
-
-#define TPM_HEADER_SIZE		10
-
-/*
- * Expected value for DIDVID register
- *
- * The only device the system knows about at this moment is Infineon slb9635.
- */
-#define TPM_TIS_I2C_DID_VID	0x000b15d1L
-
-enum tis_access {
-	TPM_ACCESS_VALID		= 0x80,
-	TPM_ACCESS_ACTIVE_LOCALITY	= 0x20,
-	TPM_ACCESS_REQUEST_PENDING	= 0x04,
-	TPM_ACCESS_REQUEST_USE		= 0x02,
-};
-
-enum tis_status {
-	TPM_STS_VALID			= 0x80,
-	TPM_STS_COMMAND_READY		= 0x40,
-	TPM_STS_GO			= 0x20,
-	TPM_STS_DATA_AVAIL		= 0x10,
-	TPM_STS_DATA_EXPECT		= 0x08,
-};
-
-enum tis_defaults {
-	TIS_SHORT_TIMEOUT		= 750,	/* ms */
-	TIS_LONG_TIMEOUT		= 2000,	/* ms */
-};
-
-/* expected value for DIDVID register */
-#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
-#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
-
-enum i2c_chip_type {
-	SLB9635,
-	SLB9645,
-	UNKNOWN,
-};
-
 static const char * const chip_name[] = {
 	[SLB9635] = "slb9635tt",
 	[SLB9645] = "slb9645tt",
 	[UNKNOWN] = "unknown/fallback to slb9635",
 };
 
-#define	TPM_ACCESS(l)			(0x0000 | ((l) << 4))
-#define	TPM_STS(l)			(0x0001 | ((l) << 4))
-#define	TPM_DATA_FIFO(l)		(0x0005 | ((l) << 4))
-#define	TPM_DID_VID(l)			(0x0006 | ((l) << 4))
-
-/* Structure to store I2C TPM specific stuff */
-struct tpm_dev {
-#ifdef CONFIG_DM_I2C
-	struct udevice *dev;
-#else
-	uint addr;
-#endif
-	u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)];  /* Max buffer size + addr */
-	enum i2c_chip_type chip_type;
-};
-
-static struct tpm_dev tpm_dev = {
-#ifndef CONFIG_DM_I2C
-	.addr = TPM_I2C_ADDR
-#endif
-};
-
-static struct tpm_dev tpm_dev;
-
 /*
- * iic_tpm_read() - read from TPM register
+ * tpm_tis_i2c_read() - read from TPM register
  * @addr: register address to read from
  * @buffer: provided by caller
  * @len: number of bytes to read
@@ -154,39 +56,32 @@
  *
  * Return -EIO on error, 0 on success.
  */
-static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_read(struct udevice *dev, u8 addr, u8 *buffer,
+			    size_t len)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	int rc;
 	int count;
 	uint32_t addrbuf = addr;
 
-	if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) {
+	if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) {
 		/* slb9635 protocol should work in both cases */
 		for (count = 0; count < MAX_COUNT; count++) {
-#ifdef CONFIG_DM_I2C
-			rc = dm_i2c_write(tpm_dev.dev, 0, (uchar *)&addrbuf, 1);
-#else
-			rc = i2c_write(tpm_dev.addr, 0, 0,
-				       (uchar *)&addrbuf, 1);
-#endif
+			rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1);
 			if (rc == 0)
 				break;  /* Success, break to skip sleep */
-			udelay(SLEEP_DURATION);
+			udelay(SLEEP_DURATION_US);
 		}
 		if (rc)
-			return -rc;
+			return rc;
 
 		/* After the TPM has successfully received the register address
 		 * it needs some time, thus we're sleeping here again, before
 		 * retrieving the data
 		 */
 		for (count = 0; count < MAX_COUNT; count++) {
-			udelay(SLEEP_DURATION);
-#ifdef CONFIG_DM_I2C
-			rc = dm_i2c_read(tpm_dev.dev, 0, buffer, len);
-#else
-			rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len);
-#endif
+			udelay(SLEEP_DURATION_US);
+			rc = dm_i2c_read(dev, 0, buffer, len);
 			if (rc == 0)
 				break;  /* success, break to skip sleep */
 		}
@@ -199,60 +94,56 @@
 		 * be safe on the safe side.
 		 */
 		for (count = 0; count < MAX_COUNT; count++) {
-#ifdef CONFIG_DM_I2C
-			rc = dm_i2c_read(tpm_dev.dev, addr, buffer, len);
-#else
-			rc = i2c_read(tpm_dev.addr, addr, 1, buffer, len);
-#endif
+			rc = dm_i2c_read(dev, addr, buffer, len);
 			if (rc == 0)
 				break;  /* break here to skip sleep */
-			udelay(SLEEP_DURATION);
+			udelay(SLEEP_DURATION_US);
 		}
 	}
 
 	/* Take care of 'guard time' */
-	udelay(SLEEP_DURATION);
+	udelay(SLEEP_DURATION_US);
 	if (rc)
-		return -rc;
+		return rc;
 
 	return 0;
 }
 
-static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
-		unsigned int sleep_time, u8 max_count)
+static int tpm_tis_i2c_write_generic(struct udevice *dev, u8 addr,
+				     const u8 *buffer, size_t len,
+				     unsigned int sleep_time_us, u8 max_count)
 {
+	struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+	struct tpm_chip *chip = dev_get_priv(dev);
 	int rc = 0;
 	int count;
 
-	/* Prepare send buffer */
-#ifndef CONFIG_DM_I2C
-	tpm_dev.buf[0] = addr;
-	memcpy(&(tpm_dev.buf[1]), buffer, len);
-	buffer = tpm_dev.buf;
-	len++;
-#endif
+	if (chip->chip_type == SLB9635) {
+		/* Prepare send buffer to include the address */
+		priv->buf[0] = addr;
+		memcpy(&(priv->buf[1]), buffer, len);
+		buffer = priv->buf;
+		len++;
+		addr = 0;
+	}
 
 	for (count = 0; count < max_count; count++) {
-#ifdef CONFIG_DM_I2C
-		rc = dm_i2c_write(tpm_dev.dev, addr, buffer, len);
-#else
-		rc = i2c_write(tpm_dev.addr, 0, 0, buffer, len);
-#endif
+		rc = dm_i2c_write(dev, addr, buffer, len);
 		if (rc == 0)
 			break;  /* Success, break to skip sleep */
-		udelay(sleep_time);
+		udelay(sleep_time_us);
 	}
 
 	/* take care of 'guard time' */
-	udelay(sleep_time);
+	udelay(sleep_time_us);
 	if (rc)
-		return -rc;
+		return rc;
 
 	return 0;
 }
 
 /*
- * iic_tpm_write() - write to TPM register
+ * tpm_tis_i2c_write() - write to TPM register
  * @addr: register address to write to
  * @buffer: containing data to be written
  * @len: number of bytes to write
@@ -263,109 +154,135 @@
  * NOTE: TPM is big-endian for multi-byte values. Multi-byte
  * values have to be swapped.
  *
- * NOTE: use this function instead of the iic_tpm_write_generic function.
+ * NOTE: use this function instead of the tpm_tis_i2c_write_generic function.
  *
  * Return -EIO on error, 0 on success
  */
-static int iic_tpm_write(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer,
+			     size_t len)
 {
-	return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION,
-			MAX_COUNT);
+	return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
+					 SLEEP_DURATION_US, MAX_COUNT);
 }
 
 /*
  * This function is needed especially for the cleanup situation after
  * sending TPM_READY
  */
-static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_write_long(struct udevice *dev, u8 addr, u8 *buffer,
+				  size_t len)
 {
-	return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG,
-			MAX_COUNT_LONG);
+	return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
+					 SLEEP_DURATION_LONG_US,
+					 MAX_COUNT_LONG);
 }
 
-static int check_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_check_locality(struct udevice *dev, int loc)
 {
 	const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID;
+	struct tpm_chip *chip = dev_get_priv(dev);
 	u8 buf;
 	int rc;
 
-	rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1);
+	rc = tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1);
 	if (rc < 0)
 		return rc;
 
 	if ((buf & mask) == mask) {
-		chip->vendor.locality = loc;
+		chip->locality = loc;
 		return loc;
 	}
 
-	return -1;
+	return -ENOENT;
 }
 
-static void release_locality(struct tpm_chip *chip, int loc, int force)
+static void tpm_tis_i2c_release_locality(struct udevice *dev, int loc,
+					 int force)
 {
 	const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID;
 	u8 buf;
 
-	if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0)
+	if (tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1) < 0)
 		return;
 
 	if (force || (buf & mask) == mask) {
 		buf = TPM_ACCESS_ACTIVE_LOCALITY;
-		iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
+		tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
 	}
 }
 
-static int request_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_request_locality(struct udevice *dev, int loc)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	unsigned long start, stop;
 	u8 buf = TPM_ACCESS_REQUEST_USE;
 	int rc;
 
-	if (check_locality(chip, loc) >= 0)
+	rc = tpm_tis_i2c_check_locality(dev, loc);
+	if (rc >= 0) {
+		debug("%s: Already have locality\n", __func__);
 		return loc;  /* We already have the locality */
-
-	rc = iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
-	if (rc)
+	} else if (rc != -ENOENT) {
+		debug("%s: Failed to get locality: %d\n", __func__, rc);
 		return rc;
+	}
+
+	rc = tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
+	if (rc) {
+		debug("%s: Failed to write to TPM: %d\n", __func__, rc);
+		return rc;
+	}
 
 	/* Wait for burstcount */
 	start = get_timer(0);
-	stop = chip->vendor.timeout_a;
+	stop = chip->timeout_a;
 	do {
-		if (check_locality(chip, loc) >= 0)
+		rc = tpm_tis_i2c_check_locality(dev, loc);
+		if (rc >= 0) {
+			debug("%s: Have locality\n", __func__);
 			return loc;
-		udelay(TPM_TIMEOUT * 1000);
+		} else if (rc != -ENOENT) {
+			debug("%s: Failed to get locality: %d\n", __func__, rc);
+			return rc;
+		}
+		mdelay(TPM_TIMEOUT_MS);
 	} while (get_timer(start) < stop);
+	debug("%s: Timeout getting locality: %d\n", __func__, rc);
 
-	return -1;
+	return rc;
 }
 
-static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
+static u8 tpm_tis_i2c_status(struct udevice *dev)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	/* NOTE: Since i2c read may fail, return 0 in this case --> time-out */
 	u8 buf;
 
-	if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
+	if (tpm_tis_i2c_read(dev, TPM_STS(chip->locality), &buf, 1) < 0)
 		return 0;
 	else
 		return buf;
 }
 
-static void tpm_tis_i2c_ready(struct tpm_chip *chip)
+static int tpm_tis_i2c_ready(struct udevice *dev)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	int rc;
 
 	/* This causes the current command to be aborted */
 	u8 buf = TPM_STS_COMMAND_READY;
 
 	debug("%s\n", __func__);
-	rc = iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1);
+	rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1);
 	if (rc)
 		debug("%s: rc=%d\n", __func__, rc);
+
+	return rc;
 }
 
-static ssize_t get_burstcount(struct tpm_chip *chip)
+static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	unsigned long start, stop;
 	ssize_t burstcnt;
 	u8 addr, buf[3];
@@ -373,53 +290,54 @@
 	/* Wait for burstcount */
 	/* XXX: Which timeout value? Spec has 2 answers (c & d) */
 	start = get_timer(0);
-	stop = chip->vendor.timeout_d;
+	stop = chip->timeout_d;
 	do {
 		/* Note: STS is little endian */
-		addr = TPM_STS(chip->vendor.locality) + 1;
-		if (iic_tpm_read(addr, buf, 3) < 0)
+		addr = TPM_STS(chip->locality) + 1;
+		if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0)
 			burstcnt = 0;
 		else
 			burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
 
 		if (burstcnt)
 			return burstcnt;
-		udelay(TPM_TIMEOUT * 1000);
+		mdelay(TPM_TIMEOUT_MS);
 	} while (get_timer(start) < stop);
 
 	return -EBUSY;
 }
 
-static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
-		int *status)
+static int tpm_tis_i2c_wait_for_stat(struct udevice *dev, u8 mask,
+				     unsigned long timeout, int *status)
 {
 	unsigned long start, stop;
 
 	/* Check current status */
-	*status = tpm_tis_i2c_status(chip);
+	*status = tpm_tis_i2c_status(dev);
 	if ((*status & mask) == mask)
 		return 0;
 
 	start = get_timer(0);
 	stop = timeout;
 	do {
-		udelay(TPM_TIMEOUT * 1000);
-		*status = tpm_tis_i2c_status(chip);
+		mdelay(TPM_TIMEOUT_MS);
+		*status = tpm_tis_i2c_status(dev);
 		if ((*status & mask) == mask)
 			return 0;
 	} while (get_timer(start) < stop);
 
-	return -ETIME;
+	return -ETIMEDOUT;
 }
 
-static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	size_t size = 0;
 	ssize_t burstcnt;
 	int rc;
 
 	while (size < count) {
-		burstcnt = get_burstcount(chip);
+		burstcnt = tpm_tis_i2c_get_burstcount(dev);
 
 		/* burstcount < 0 -> tpm is busy */
 		if (burstcnt < 0)
@@ -429,8 +347,8 @@
 		if (burstcnt > (count - size))
 			burstcnt = count - size;
 
-		rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality),
-				&(buf[size]), burstcnt);
+		rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality),
+				      &(buf[size]), burstcnt);
 		if (rc == 0)
 			size += burstcnt;
 	}
@@ -438,60 +356,58 @@
 	return size;
 }
 
-static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	int size = 0;
 	int expected, status;
+	int rc;
 
-	if (count < TPM_HEADER_SIZE) {
-		size = -EIO;
-		goto out;
-	}
+	status = tpm_tis_i2c_status(dev);
+	if (status == TPM_STS_COMMAND_READY)
+		return -EINTR;
+	if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) !=
+	    (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
+		return -EAGAIN;
+
+	debug("...got it;\n");
 
 	/* Read first 10 bytes, including tag, paramsize, and result */
-	size = recv_data(chip, buf, TPM_HEADER_SIZE);
+	size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE);
 	if (size < TPM_HEADER_SIZE) {
-		error("Unable to read header\n");
-		goto out;
+		debug("Unable to read header\n");
+		return size < 0 ? size : -EIO;
 	}
 
 	expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE);
 	if ((size_t)expected > count) {
-		error("Error size=%x, expected=%x, count=%x\n", size, expected,
+		debug("Error size=%x, expected=%x, count=%x\n", size, expected,
 		      count);
-		size = -EIO;
-		goto out;
+		return -ENOSPC;
 	}
 
-	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
-			expected - TPM_HEADER_SIZE);
+	size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE],
+				      expected - TPM_HEADER_SIZE);
 	if (size < expected) {
-		error("Unable to read remainder of result\n");
-		size = -ETIME;
-		goto out;
+		debug("Unable to read remainder of result\n");
+		return -ETIMEDOUT;
 	}
 
-	wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
+	rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c,
+				       &status);
+	if (rc)
+		return rc;
 	if (status & TPM_STS_DATA_AVAIL) {  /* Retry? */
-		error("Error left over data\n");
-		size = -EIO;
-		goto out;
+		debug("Error left over data\n");
+		return -EIO;
 	}
 
-out:
-	tpm_tis_i2c_ready(chip);
-	/*
-	 * The TPM needs some time to clean up here,
-	 * so we sleep rather than keeping the bus busy
-	 */
-	udelay(2000);
-	release_locality(chip, chip->vendor.locality, 0);
-
 	return size;
 }
 
-static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
+static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
 {
+	struct tpm_chip *chip = dev_get_priv(dev);
 	int rc, status;
 	size_t burstcnt;
 	size_t count = 0;
@@ -502,20 +418,21 @@
 	if (len > TPM_DEV_BUFSIZE)
 		return -E2BIG;  /* Command is too long for our tpm, sorry */
 
-	if (request_locality(chip, 0) < 0)
+	if (tpm_tis_i2c_request_locality(dev, 0) < 0)
 		return -EBUSY;
 
-	status = tpm_tis_i2c_status(chip);
+	status = tpm_tis_i2c_status(dev);
 	if ((status & TPM_STS_COMMAND_READY) == 0) {
-		tpm_tis_i2c_ready(chip);
-		if (wait_for_stat(chip, TPM_STS_COMMAND_READY,
-				  chip->vendor.timeout_b, &status) < 0) {
-			rc = -ETIME;
-			goto out_err;
-		}
+		rc = tpm_tis_i2c_ready(dev);
+		if (rc)
+			return rc;
+		rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY,
+					       chip->timeout_b, &status);
+		if (rc)
+			return rc;
 	}
 
-	burstcnt = get_burstcount(chip);
+	burstcnt = tpm_tis_i2c_get_burstcount(dev);
 
 	/* burstcount < 0 -> tpm is busy */
 	if (burstcnt < 0)
@@ -527,107 +444,79 @@
 			burstcnt = len - count;
 
 #ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION
-		if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION)
-			burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION;
+		if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN)
+			burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN;
 #endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */
 
-		rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality),
-				&(buf[count]), burstcnt);
+		rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality),
+				       &(buf[count]), burstcnt);
 		if (rc == 0)
 			count += burstcnt;
 		else {
 			debug("%s: error\n", __func__);
-			if (retry++ > 10) {
-				rc = -EIO;
-				goto out_err;
-			}
-			rc = wait_for_stat(chip, TPM_STS_VALID,
-					   chip->vendor.timeout_c, &status);
+			if (retry++ > 10)
+				return -EIO;
+			rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID,
+						       chip->timeout_c,
+						       &status);
 			if (rc)
-				goto out_err;
+				return rc;
 
-			if ((status & TPM_STS_DATA_EXPECT) == 0) {
-				rc = -EIO;
-				goto out_err;
-			}
+			if ((status & TPM_STS_DATA_EXPECT) == 0)
+				return -EIO;
 		}
 	}
 
 	/* Go and do it */
-	iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1);
-	debug("done\n");
+	rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1);
+	if (rc < 0)
+		return rc;
+	debug("%s: done, rc=%d\n", __func__, rc);
 
 	return len;
+}
 
-out_err:
-	debug("%s: out_err\n", __func__);
-	tpm_tis_i2c_ready(chip);
+static int tpm_tis_i2c_cleanup(struct udevice *dev)
+{
+	struct tpm_chip *chip = dev_get_priv(dev);
+
+	tpm_tis_i2c_ready(dev);
 	/*
 	 * The TPM needs some time to clean up here,
 	 * so we sleep rather than keeping the bus busy
 	 */
-	udelay(2000);
-	release_locality(chip, chip->vendor.locality, 0);
+	mdelay(2);
+	tpm_tis_i2c_release_locality(dev, chip->locality, 0);
 
-	return rc;
+	return 0;
 }
 
-static struct tpm_vendor_specific tpm_tis_i2c = {
-	.status = tpm_tis_i2c_status,
-	.recv = tpm_tis_i2c_recv,
-	.send = tpm_tis_i2c_send,
-	.cancel = tpm_tis_i2c_ready,
-	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-	.req_canceled = TPM_STS_COMMAND_READY,
-};
-
-
-static enum i2c_chip_type tpm_vendor_chip_type(void)
+static int tpm_tis_i2c_init(struct udevice *dev)
 {
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-	const void *blob = gd->fdt_blob;
-
-	if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9645_TPM) >= 0)
-		return SLB9645;
-
-	if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM) >= 0)
-		return SLB9635;
-#endif
-	return UNKNOWN;
-}
-
-static int tpm_vendor_init_common(void)
-{
-	struct tpm_chip *chip;
+	struct tpm_chip *chip = dev_get_priv(dev);
 	u32 vendor;
 	u32 expected_did_vid;
+	int rc;
 
-	tpm_dev.chip_type = tpm_vendor_chip_type();
+	chip->is_open = 1;
 
-	chip = tpm_register_hardware(&tpm_tis_i2c);
-	if (chip < 0)
-		return -ENODEV;
+	/* Default timeouts - these could move to the device tree */
+	chip->timeout_a = TIS_SHORT_TIMEOUT_MS;
+	chip->timeout_b = TIS_LONG_TIMEOUT_MS;
+	chip->timeout_c = TIS_SHORT_TIMEOUT_MS;
+	chip->timeout_d = TIS_SHORT_TIMEOUT_MS;
 
-	/* Disable interrupts (not supported) */
-	chip->vendor.irq = 0;
-
-	/* Default timeouts */
-	chip->vendor.timeout_a = TIS_SHORT_TIMEOUT;
-	chip->vendor.timeout_b = TIS_LONG_TIMEOUT;
-	chip->vendor.timeout_c = TIS_SHORT_TIMEOUT;
-	chip->vendor.timeout_d = TIS_SHORT_TIMEOUT;
-
-	if (request_locality(chip, 0) < 0)
-		return  -ENODEV;
+	rc = tpm_tis_i2c_request_locality(dev, 0);
+	if (rc < 0)
+		return rc;
 
 	/* Read four bytes from DID_VID register */
-	if (iic_tpm_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
-		release_locality(chip, 0, 1);
+	if (tpm_tis_i2c_read(dev, TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
+		tpm_tis_i2c_release_locality(dev, 0, 1);
 		return -EIO;
 	}
 
-	if (tpm_dev.chip_type == SLB9635) {
+	if (chip->chip_type == SLB9635) {
 		vendor = be32_to_cpu(vendor);
 		expected_did_vid = TPM_TIS_I2C_DID_VID_9635;
 	} else {
@@ -635,13 +524,14 @@
 		expected_did_vid = TPM_TIS_I2C_DID_VID_9645;
 	}
 
-	if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) {
+	if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) {
 		error("Vendor id did not match! ID was %08x\n", vendor);
 		return -ENODEV;
 	}
 
+	chip->vend_dev = vendor;
 	debug("1.2 TPM (chip type %s device-id 0x%X)\n",
-	      chip_name[tpm_dev.chip_type], vendor >> 16);
+	      chip_name[chip->chip_type], vendor >> 16);
 
 	/*
 	 * A timeout query to TPM can be placed here.
@@ -651,33 +541,83 @@
 	return 0;
 }
 
-#ifdef CONFIG_DM_I2C
-/* Initialisation of i2c tpm */
-int tpm_vendor_init_dev(struct udevice *dev)
+static int tpm_tis_i2c_open(struct udevice *dev)
 {
-	tpm_dev.dev = dev;
-	return tpm_vendor_init_common();
-}
-#else
-/* Initialisation of i2c tpm */
-int tpm_vendor_init(uint32_t dev_addr)
-{
-	uint old_addr;
-	int rc = 0;
+	struct tpm_chip *chip = dev_get_priv(dev);
+	int rc;
 
-	old_addr = tpm_dev.addr;
-	if (dev_addr != 0)
-		tpm_dev.addr = dev_addr;
-
-	rc = tpm_vendor_init_common();
-	if (rc)
-		tpm_dev.addr = old_addr;
+	debug("%s: start\n", __func__);
+	if (chip->is_open)
+		return -EBUSY;
+	rc = tpm_tis_i2c_init(dev);
+	if (rc < 0)
+		chip->is_open = 0;
 
 	return rc;
 }
-#endif
 
-void tpm_vendor_cleanup(struct tpm_chip *chip)
+static int tpm_tis_i2c_close(struct udevice *dev)
 {
-	release_locality(chip, chip->vendor.locality, 1);
+	struct tpm_chip *chip = dev_get_priv(dev);
+
+	if (chip->is_open) {
+		tpm_tis_i2c_release_locality(dev, chip->locality, 1);
+		chip->is_open = 0;
+		chip->vend_dev = 0;
+	}
+
+	return 0;
 }
+
+static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
+{
+	struct tpm_chip *chip = dev_get_priv(dev);
+
+	if (size < 50)
+		return -ENOSPC;
+
+	return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)",
+			chip->is_open ? "open" : "closed",
+			chip_name[chip->chip_type],
+			chip->vend_dev >> 16);
+}
+
+static int tpm_tis_i2c_probe(struct udevice *dev)
+{
+	struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct tpm_chip *chip = dev_get_priv(dev);
+
+	chip->chip_type = dev_get_driver_data(dev);
+
+	/* TODO: These need to be checked and tuned */
+	uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS;
+	uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS;
+	uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS;
+	uc_priv->retry_time_ms = TPM_TIMEOUT_MS;
+
+	return 0;
+}
+
+static const struct tpm_ops tpm_tis_i2c_ops = {
+	.open		= tpm_tis_i2c_open,
+	.close		= tpm_tis_i2c_close,
+	.get_desc	= tpm_tis_get_desc,
+	.send		= tpm_tis_i2c_send,
+	.recv		= tpm_tis_i2c_recv,
+	.cleanup	= tpm_tis_i2c_cleanup,
+};
+
+static const struct udevice_id tpm_tis_i2c_ids[] = {
+	{ .compatible = "infineon,slb9635tt", .data = SLB9635 },
+	{ .compatible = "infineon,slb9645tt", .data = SLB9645 },
+	{ }
+};
+
+U_BOOT_DRIVER(tpm_tis_i2c) = {
+	.name   = "tpm_tis_i2c",
+	.id     = UCLASS_TPM,
+	.of_match = tpm_tis_i2c_ids,
+	.ops    = &tpm_tis_i2c_ops,
+	.probe	= tpm_tis_i2c_probe,
+	.priv_auto_alloc_size = sizeof(struct tpm_chip),
+};
diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h
new file mode 100644
index 0000000..3b510d1
--- /dev/null
+++ b/drivers/tpm/tpm_tis_i2c.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 Infineon Technologies
+ *
+ * Authors:
+ * Peter Huewe <huewe.external@infineon.com>
+ *
+ * Version: 2.1.1
+ *
+ * Description:
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * It is based on the Linux kernel driver tpm.c from Leendert van
+ * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _TPM_TIS_I2C_H
+#define _TPM_TIS_I2C_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+enum tpm_timeout {
+	TPM_TIMEOUT_MS			= 5,
+	TIS_SHORT_TIMEOUT_MS		= 750,
+	TIS_LONG_TIMEOUT_MS		= 2000,
+	SLEEP_DURATION_US		= 60,
+	SLEEP_DURATION_LONG_US		= 210,
+};
+
+/* Size of external transmit buffer (used in tpm_transmit)*/
+#define TPM_BUFSIZE 4096
+
+/* Index of Count field in TPM response buffer */
+#define TPM_RSP_SIZE_BYTE	2
+#define TPM_RSP_RC_BYTE		6
+
+enum i2c_chip_type {
+	SLB9635,
+	SLB9645,
+	UNKNOWN,
+};
+
+struct tpm_chip {
+	int is_open;
+	int locality;
+	u32 vend_dev;
+	unsigned long timeout_a, timeout_b, timeout_c, timeout_d;  /* msec */
+	enum i2c_chip_type chip_type;
+};
+
+struct tpm_input_header {
+	__be16 tag;
+	__be32 length;
+	__be32 ordinal;
+} __packed;
+
+struct tpm_output_header {
+	__be16 tag;
+	__be32 length;
+	__be32 return_code;
+} __packed;
+
+struct timeout_t {
+	__be32 a;
+	__be32 b;
+	__be32 c;
+	__be32 d;
+} __packed;
+
+struct duration_t {
+	__be32 tpm_short;
+	__be32 tpm_medium;
+	__be32 tpm_long;
+} __packed;
+
+union cap_t {
+	struct timeout_t timeout;
+	struct duration_t duration;
+};
+
+struct tpm_getcap_params_in {
+	__be32 cap;
+	__be32 subcap_size;
+	__be32 subcap;
+} __packed;
+
+struct tpm_getcap_params_out {
+	__be32 cap_size;
+	union cap_t cap;
+} __packed;
+
+union tpm_cmd_header {
+	struct tpm_input_header in;
+	struct tpm_output_header out;
+};
+
+union tpm_cmd_params {
+	struct tpm_getcap_params_out getcap_out;
+	struct tpm_getcap_params_in getcap_in;
+};
+
+struct tpm_cmd_t {
+	union tpm_cmd_header header;
+	union tpm_cmd_params params;
+} __packed;
+
+/* Max number of iterations after i2c NAK */
+#define MAX_COUNT		3
+
+/*
+ * Max number of iterations after i2c NAK for 'long' commands
+ *
+ * We need this especially for sending TPM_READY, since the cleanup after the
+ * transtion to the ready state may take some time, but it is unpredictable
+ * how long it will take.
+ */
+#define MAX_COUNT_LONG		50
+
+enum tis_access {
+	TPM_ACCESS_VALID		= 0x80,
+	TPM_ACCESS_ACTIVE_LOCALITY	= 0x20,
+	TPM_ACCESS_REQUEST_PENDING	= 0x04,
+	TPM_ACCESS_REQUEST_USE		= 0x02,
+};
+
+enum tis_status {
+	TPM_STS_VALID			= 0x80,
+	TPM_STS_COMMAND_READY		= 0x40,
+	TPM_STS_GO			= 0x20,
+	TPM_STS_DATA_AVAIL		= 0x10,
+	TPM_STS_DATA_EXPECT		= 0x08,
+};
+
+/* expected value for DIDVID register */
+#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
+#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
+
+#define	TPM_ACCESS(l)			(0x0000 | ((l) << 4))
+#define	TPM_STS(l)			(0x0001 | ((l) << 4))
+#define	TPM_DATA_FIFO(l)		(0x0005 | ((l) << 4))
+#define	TPM_DID_VID(l)			(0x0006 | ((l) << 4))
+
+#endif
diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c
index d09f8ce..b41c3ce 100644
--- a/drivers/tpm/tpm_tis_lpc.c
+++ b/drivers/tpm/tpm_tis_lpc.c
@@ -14,8 +14,11 @@
  */
 
 #include <common.h>
-#include <asm/io.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <tis.h>
 #include <tpm.h>
+#include <asm/io.h>
 
 #define PREFIX "lpc_tpm: "
 
@@ -36,13 +39,15 @@
 	u8 padding4[251];
 };
 
+struct tpm_tis_lpc_priv {
+	struct tpm_locality *regs;
+};
+
 /*
  * This pointer refers to the TPM chip, 5 of its localities are mapped as an
  * array.
  */
 #define TPM_TOTAL_LOCALITIES	5
-static struct tpm_locality *lpc_tpm_dev =
-	(struct tpm_locality *)CONFIG_TPM_TIS_BASE_ADDRESS;
 
 /* Some registers' bit field definitions */
 #define TIS_STS_VALID                  (1 << 7) /* 0x80 */
@@ -63,85 +68,45 @@
 #define TIS_STS_BURST_COUNT_MASK       (0xffff)
 #define TIS_STS_BURST_COUNT_SHIFT      (8)
 
-/*
- * Error value returned if a tpm register does not enter the expected state
- * after continuous polling. No actual TPM register reading ever returns -1,
- * so this value is a safe error indication to be mixed with possible status
- * register values.
- */
-#define TPM_TIMEOUT_ERR			(-1)
-
-/* Error value returned on various TPM driver errors. */
-#define TPM_DRIVER_ERR		(1)
-
  /* 1 second is plenty for anything TPM does. */
 #define MAX_DELAY_US	(1000 * 1000)
 
 /* Retrieve burst count value out of the status register contents. */
 static u16 burst_count(u32 status)
 {
-	return (status >> TIS_STS_BURST_COUNT_SHIFT) & TIS_STS_BURST_COUNT_MASK;
+	return (status >> TIS_STS_BURST_COUNT_SHIFT) &
+			TIS_STS_BURST_COUNT_MASK;
 }
 
-/*
- * Structures defined below allow creating descriptions of TPM vendor/device
- * ID information for run time discovery. The only device the system knows
- * about at this time is Infineon slb9635.
- */
-struct device_name {
-	u16 dev_id;
-	const char * const dev_name;
-};
-
-struct vendor_name {
-	u16 vendor_id;
-	const char *vendor_name;
-	const struct device_name *dev_names;
-};
-
-static const struct device_name infineon_devices[] = {
-	{0xb, "SLB9635 TT 1.2"},
-	{0}
-};
-
-static const struct vendor_name vendor_names[] = {
-	{0x15d1, "Infineon", infineon_devices},
-};
-
-/*
- * Cached vendor/device ID pair to indicate that the device has been already
- * discovered.
- */
-static u32 vendor_dev_id;
-
 /* TPM access wrappers to support tracing */
-static u8 tpm_read_byte(const u8 *ptr)
+static u8 tpm_read_byte(struct tpm_tis_lpc_priv *priv, const u8 *ptr)
 {
 	u8  ret = readb(ptr);
 	debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n",
-	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
+	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
 	return ret;
 }
 
-static u32 tpm_read_word(const u32 *ptr)
+static u32 tpm_read_word(struct tpm_tis_lpc_priv *priv, const u32 *ptr)
 {
 	u32  ret = readl(ptr);
 	debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n",
-	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
+	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
 	return ret;
 }
 
-static void tpm_write_byte(u8 value, u8 *ptr)
+static void tpm_write_byte(struct tpm_tis_lpc_priv *priv, u8 value, u8 *ptr)
 {
 	debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n",
-	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
+	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
 	writeb(value, ptr);
 }
 
-static void tpm_write_word(u32 value, u32 *ptr)
+static void tpm_write_word(struct tpm_tis_lpc_priv *priv, u32 value,
+			   u32 *ptr)
 {
 	debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n",
-	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
+	      (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
 	writel(value, ptr);
 }
 
@@ -156,67 +121,51 @@
  * @expected - value the field(s) are supposed to be set to
  *
  * Returns the register contents in case the expected value was found in the
- * appropriate register bits, or TPM_TIMEOUT_ERR on timeout.
+ * appropriate register bits, or -ETIMEDOUT on timeout.
  */
-static u32 tis_wait_reg(u32 *reg, u8 mask, u8 expected)
+static int tis_wait_reg(struct tpm_tis_lpc_priv *priv, u32 *reg, u8 mask,
+			u8 expected)
 {
 	u32 time_us = MAX_DELAY_US;
 
 	while (time_us > 0) {
-		u32 value = tpm_read_word(reg);
+		u32 value = tpm_read_word(priv, reg);
 		if ((value & mask) == expected)
 			return value;
 		udelay(1); /* 1 us */
 		time_us--;
 	}
-	return TPM_TIMEOUT_ERR;
+
+	return -ETIMEDOUT;
 }
 
 /*
  * Probe the TPM device and try determining its manufacturer/device name.
  *
- * Returns 0 on success (the device is found or was found during an earlier
- * invocation) or TPM_DRIVER_ERR if the device is not found.
+ * Returns 0 on success, -ve on error
  */
-int tis_init(void)
+static int tpm_tis_lpc_probe(struct udevice *dev)
 {
-	u32 didvid = tpm_read_word(&lpc_tpm_dev[0].did_vid);
-	int i;
-	const char *device_name = "unknown";
-	const char *vendor_name = device_name;
-	u16 vid, did;
+	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+	u32 vid, did;
+	fdt_addr_t addr;
+	u32 didvid;
 
-	if (vendor_dev_id)
-		return 0;  /* Already probed. */
-
-	if (!didvid || (didvid == 0xffffffff)) {
-		printf("%s: No TPM device found\n", __func__);
-		return TPM_DRIVER_ERR;
-	}
-
-	vendor_dev_id = didvid;
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->regs = map_sysmem(addr, 0);
+	didvid = tpm_read_word(priv, &priv->regs[0].did_vid);
 
 	vid = didvid & 0xffff;
 	did = (didvid >> 16) & 0xffff;
-	for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
-		int j = 0;
-		u16 known_did;
-
-		if (vid == vendor_names[i].vendor_id)
-			vendor_name = vendor_names[i].vendor_name;
-
-		while ((known_did = vendor_names[i].dev_names[j].dev_id) != 0) {
-			if (known_did == did) {
-				device_name =
-					vendor_names[i].dev_names[j].dev_name;
-				break;
-			}
-			j++;
-		}
-		break;
+	if (vid != 0x15d1 || did != 0xb) {
+		debug("Invalid vendor/device ID %04x/%04x\n", vid, did);
+		return -ENOSYS;
 	}
 
-	printf("Found TPM %s by %s\n", device_name, vendor_name);
+	debug("Found TPM %s by %s\n", "SLB9635 TT 1.2", "Infineon");
+
 	return 0;
 }
 
@@ -228,23 +177,25 @@
  * @data - address of the data to send, byte by byte
  * @len - length of the data to send
  *
- * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
- * not accept the entire command).
+ * Returns 0 on success, -ve on error (in case the device does not accept
+ * the entire command).
  */
-static u32 tis_senddata(const u8 * const data, u32 len)
+static int tis_senddata(struct udevice *dev, const u8 *data, size_t len)
 {
+	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+	struct tpm_locality *regs = priv->regs;
 	u32 offset = 0;
 	u16 burst = 0;
 	u32 max_cycles = 0;
 	u8 locality = 0;
 	u32 value;
 
-	value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+	value = tis_wait_reg(priv, &regs[locality].tpm_status,
 			     TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
-	if (value == TPM_TIMEOUT_ERR) {
+	if (value == -ETIMEDOUT) {
 		printf("%s:%d - failed to get 'command_ready' status\n",
 		       __FILE__, __LINE__);
-		return TPM_DRIVER_ERR;
+		return value;
 	}
 	burst = burst_count(value);
 
@@ -256,11 +207,11 @@
 			if (max_cycles++ == MAX_DELAY_US) {
 				printf("%s:%d failed to feed %d bytes of %d\n",
 				       __FILE__, __LINE__, len - offset, len);
-				return TPM_DRIVER_ERR;
+				return -ETIMEDOUT;
 			}
 			udelay(1);
-			burst = burst_count(tpm_read_word(&lpc_tpm_dev
-						     [locality].tpm_status));
+			burst = burst_count(tpm_read_word(priv,
+					&regs[locality].tpm_status));
 		}
 
 		max_cycles = 0;
@@ -276,16 +227,16 @@
 		 */
 		count = min((u32)burst, len - offset - 1);
 		while (count--)
-			tpm_write_byte(data[offset++],
-				  &lpc_tpm_dev[locality].data);
+			tpm_write_byte(priv, data[offset++],
+				       &regs[locality].data);
 
-		value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+		value = tis_wait_reg(priv, &regs[locality].tpm_status,
 				     TIS_STS_VALID, TIS_STS_VALID);
 
-		if ((value == TPM_TIMEOUT_ERR) || !(value & TIS_STS_EXPECT)) {
+		if ((value == -ETIMEDOUT) || !(value & TIS_STS_EXPECT)) {
 			printf("%s:%d TPM command feed overflow\n",
 			       __FILE__, __LINE__);
-			return TPM_DRIVER_ERR;
+			return value == -ETIMEDOUT ? value : -EIO;
 		}
 
 		burst = burst_count(value);
@@ -300,21 +251,21 @@
 	}
 
 	/* Send the last byte. */
-	tpm_write_byte(data[offset++], &lpc_tpm_dev[locality].data);
+	tpm_write_byte(priv, data[offset++], &regs[locality].data);
 	/*
 	 * Verify that TPM does not expect any more data as part of this
 	 * command.
 	 */
-	value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+	value = tis_wait_reg(priv, &regs[locality].tpm_status,
 			     TIS_STS_VALID, TIS_STS_VALID);
-	if ((value == TPM_TIMEOUT_ERR) || (value & TIS_STS_EXPECT)) {
+	if ((value == -ETIMEDOUT) || (value & TIS_STS_EXPECT)) {
 		printf("%s:%d unexpected TPM status 0x%x\n",
 		       __FILE__, __LINE__, value);
-		return TPM_DRIVER_ERR;
+		return value == -ETIMEDOUT ? value : -EIO;
 	}
 
 	/* OK, sitting pretty, let's start the command execution. */
-	tpm_write_word(TIS_STS_TPM_GO, &lpc_tpm_dev[locality].tpm_status);
+	tpm_write_word(priv, TIS_STS_TPM_GO, &regs[locality].tpm_status);
 	return 0;
 }
 
@@ -328,25 +279,27 @@
  *
  * On success stores the number of received bytes to len and returns 0. On
  * errors (misformatted TPM data or synchronization problems) returns
- * TPM_DRIVER_ERR.
+ * -ve value.
  */
-static u32 tis_readresponse(u8 *buffer, u32 *len)
+static int tis_readresponse(struct udevice *dev, u8 *buffer, size_t len)
 {
+	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+	struct tpm_locality *regs = priv->regs;
 	u16 burst;
 	u32 value;
 	u32 offset = 0;
 	u8 locality = 0;
 	const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
-	u32 expected_count = *len;
+	u32 expected_count = len;
 	int max_cycles = 0;
 
 	/* Wait for the TPM to process the command. */
-	value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+	value = tis_wait_reg(priv, &regs[locality].tpm_status,
 			      has_data, has_data);
-	if (value == TPM_TIMEOUT_ERR) {
+	if (value == -ETIMEDOUT) {
 		printf("%s:%d failed processing command\n",
 		       __FILE__, __LINE__);
-		return TPM_DRIVER_ERR;
+		return value;
 	}
 
 	do {
@@ -354,18 +307,17 @@
 			if (max_cycles++ == MAX_DELAY_US) {
 				printf("%s:%d TPM stuck on read\n",
 				       __FILE__, __LINE__);
-				return TPM_DRIVER_ERR;
+				return -EIO;
 			}
 			udelay(1);
-			value = tpm_read_word(&lpc_tpm_dev
-					      [locality].tpm_status);
+			value = tpm_read_word(priv, &regs[locality].tpm_status);
 		}
 
 		max_cycles = 0;
 
 		while (burst-- && (offset < expected_count)) {
-			buffer[offset++] = tpm_read_byte(&lpc_tpm_dev
-							 [locality].data);
+			buffer[offset++] = tpm_read_byte(priv,
+						&regs[locality].data);
 
 			if (offset == 6) {
 				/*
@@ -382,22 +334,22 @@
 				expected_count = be32_to_cpu(real_length);
 
 				if ((expected_count < offset) ||
-				    (expected_count > *len)) {
+				    (expected_count > len)) {
 					printf("%s:%d bad response size %d\n",
 					       __FILE__, __LINE__,
 					       expected_count);
-					return TPM_DRIVER_ERR;
+					return -ENOSPC;
 				}
 			}
 		}
 
 		/* Wait for the next portion. */
-		value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+		value = tis_wait_reg(priv, &regs[locality].tpm_status,
 				     TIS_STS_VALID, TIS_STS_VALID);
-		if (value == TPM_TIMEOUT_ERR) {
+		if (value == -ETIMEDOUT) {
 			printf("%s:%d failed to read response\n",
 			       __FILE__, __LINE__);
-			return TPM_DRIVER_ERR;
+			return value;
 		}
 
 		if (offset == expected_count)
@@ -412,68 +364,90 @@
 	if (value & TIS_STS_DATA_AVAILABLE) {
 		printf("%s:%d wrong receive status %x\n",
 		       __FILE__, __LINE__, value);
-		return TPM_DRIVER_ERR;
+		return -EBADMSG;
 	}
 
 	/* Tell the TPM that we are done. */
-	tpm_write_word(TIS_STS_COMMAND_READY, &lpc_tpm_dev
-		  [locality].tpm_status);
-	*len = offset;
-	return 0;
+	tpm_write_word(priv, TIS_STS_COMMAND_READY,
+		       &regs[locality].tpm_status);
+
+	return offset;
 }
 
-int tis_open(void)
+static int tpm_tis_lpc_open(struct udevice *dev)
 {
+	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+	struct tpm_locality *regs = priv->regs;
 	u8 locality = 0; /* we use locality zero for everything. */
-
-	if (tis_close())
-		return TPM_DRIVER_ERR;
+	int ret;
 
 	/* now request access to locality. */
-	tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access);
+	tpm_write_word(priv, TIS_ACCESS_REQUEST_USE, &regs[locality].access);
 
 	/* did we get a lock? */
-	if (tis_wait_reg(&lpc_tpm_dev[locality].access,
+	ret = tis_wait_reg(priv, &regs[locality].access,
 			 TIS_ACCESS_ACTIVE_LOCALITY,
-			 TIS_ACCESS_ACTIVE_LOCALITY) == TPM_TIMEOUT_ERR) {
+			 TIS_ACCESS_ACTIVE_LOCALITY);
+	if (ret == -ETIMEDOUT) {
 		printf("%s:%d - failed to lock locality %d\n",
 		       __FILE__, __LINE__, locality);
-		return TPM_DRIVER_ERR;
+		return ret;
 	}
 
-	tpm_write_word(TIS_STS_COMMAND_READY,
-		       &lpc_tpm_dev[locality].tpm_status);
+	tpm_write_word(priv, TIS_STS_COMMAND_READY,
+		       &regs[locality].tpm_status);
 	return 0;
 }
 
-int tis_close(void)
+static int tpm_tis_lpc_close(struct udevice *dev)
 {
+	struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+	struct tpm_locality *regs = priv->regs;
 	u8 locality = 0;
 
-	if (tpm_read_word(&lpc_tpm_dev[locality].access) &
+	if (tpm_read_word(priv, &regs[locality].access) &
 	    TIS_ACCESS_ACTIVE_LOCALITY) {
-		tpm_write_word(TIS_ACCESS_ACTIVE_LOCALITY,
-			       &lpc_tpm_dev[locality].access);
+		tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY,
+			       &regs[locality].access);
 
-		if (tis_wait_reg(&lpc_tpm_dev[locality].access,
-				 TIS_ACCESS_ACTIVE_LOCALITY, 0) ==
-		    TPM_TIMEOUT_ERR) {
+		if (tis_wait_reg(priv, &regs[locality].access,
+				 TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) {
 			printf("%s:%d - failed to release locality %d\n",
 			       __FILE__, __LINE__, locality);
-			return TPM_DRIVER_ERR;
+			return -ETIMEDOUT;
 		}
 	}
 	return 0;
 }
 
-int tis_sendrecv(const u8 *sendbuf, size_t send_size,
-		 u8 *recvbuf, size_t *recv_len)
+static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
 {
-	if (tis_senddata(sendbuf, send_size)) {
-		printf("%s:%d failed sending data to TPM\n",
-		       __FILE__, __LINE__);
-		return TPM_DRIVER_ERR;
-	}
+	if (size < 50)
+		return -ENOSPC;
 
-	return tis_readresponse(recvbuf, (u32 *)recv_len);
+	return snprintf(buf, size, "1.2 TPM (vendor %s, chip %s)",
+			"Infineon", "SLB9635 TT 1.2");
 }
+
+
+static const struct tpm_ops tpm_tis_lpc_ops = {
+	.open		= tpm_tis_lpc_open,
+	.close		= tpm_tis_lpc_close,
+	.get_desc	= tpm_tis_get_desc,
+	.send		= tis_senddata,
+	.recv		= tis_readresponse,
+};
+
+static const struct udevice_id tpm_tis_lpc_ids[] = {
+	{ .compatible = "infineon,slb9635lpc" },
+	{ }
+};
+
+U_BOOT_DRIVER(tpm_tis_lpc) = {
+	.name   = "tpm_tis_lpc",
+	.id     = UCLASS_TPM,
+	.of_match = tpm_tis_lpc_ids,
+	.ops    = &tpm_tis_lpc_ops,
+	.probe	= tpm_tis_lpc_probe,
+	.priv_auto_alloc_size = sizeof(struct tpm_tis_lpc_priv),
+};
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c
index ed4b039..9ea9807 100644
--- a/drivers/tpm/tpm_tis_sandbox.c
+++ b/drivers/tpm/tpm_tis_sandbox.c
@@ -5,6 +5,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <tpm.h>
 #include <asm/state.h>
 #include <asm/unaligned.h>
 #include <linux/crc8.h>
@@ -56,7 +58,7 @@
  */
 static struct tpm_state {
 	uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
-} state;
+} g_state;
 
 /**
  * sandbox_tpm_read_state() - read the sandbox EC state from the state file
@@ -82,7 +84,7 @@
 		sprintf(prop_name, "nvdata%d", i);
 		prop = fdt_getprop(blob, node, prop_name, &len);
 		if (prop && len == NV_DATA_SIZE)
-			memcpy(state.nvdata[i], prop, NV_DATA_SIZE);
+			memcpy(g_state.nvdata[i], prop, NV_DATA_SIZE);
 	}
 
 	return 0;
@@ -110,7 +112,7 @@
 		char prop_name[20];
 
 		sprintf(prop_name, "nvdata%d", i);
-		fdt_setprop(blob, node, prop_name, state.nvdata[i],
+		fdt_setprop(blob, node, prop_name, g_state.nvdata[i],
 			    NV_DATA_SIZE);
 	}
 
@@ -135,10 +137,11 @@
 	return -1;
 }
 
-int tis_sendrecv(const u8 *sendbuf, size_t send_size,
-		 u8 *recvbuf, size_t *recv_len)
+static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
+			    size_t send_size, uint8_t *recvbuf,
+			    size_t *recv_len)
 {
-	struct tpm_state *tpm = &state;
+	struct tpm_state *tpm = dev_get_priv(dev);
 	uint32_t code, index, length, type;
 	uint8_t *data;
 	int seq;
@@ -241,20 +244,50 @@
 	return 0;
 }
 
-int tis_open(void)
+static int sandbox_tpm_get_desc(struct udevice *dev, char *buf, int size)
 {
-	printf("%s\n", __func__);
+	if (size < 15)
+		return -ENOSPC;
+
+	return snprintf(buf, size, "sandbox TPM");
+}
+
+static int sandbox_tpm_probe(struct udevice *dev)
+{
+	struct tpm_state *tpm = dev_get_priv(dev);
+
+	memcpy(tpm, &g_state, sizeof(*tpm));
+
 	return 0;
 }
 
-int tis_close(void)
+static int sandbox_tpm_open(struct udevice *dev)
 {
-	printf("%s\n", __func__);
 	return 0;
 }
 
-int tis_init(void)
+static int sandbox_tpm_close(struct udevice *dev)
 {
-	printf("%s\n", __func__);
 	return 0;
 }
+
+static const struct tpm_ops sandbox_tpm_ops = {
+	.open		= sandbox_tpm_open,
+	.close		= sandbox_tpm_close,
+	.get_desc	= sandbox_tpm_get_desc,
+	.xfer		= sandbox_tpm_xfer,
+};
+
+static const struct udevice_id sandbox_tpm_ids[] = {
+	{ .compatible = "google,sandbox-tpm" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_tpm) = {
+	.name   = "sandbox_tpm",
+	.id     = UCLASS_TPM,
+	.of_match = sandbox_tpm_ids,
+	.ops    = &sandbox_tpm_ops,
+	.probe	= sandbox_tpm_probe,
+	.priv_auto_alloc_size = sizeof(struct tpm_state),
+};
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 4a4f559..31d54ab 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -684,11 +684,13 @@
 		timing[PARAM_CPCON], timing[PARAM_LFCON]);
 }
 
-static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
+static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config)
 {
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
 	const char *phy, *mode;
 
-	config->reg = (struct usb_ctlr *)fdtdec_get_addr(blob, node, "reg");
+	config->reg = (struct usb_ctlr *)dev_get_addr(dev);
 	mode = fdt_getprop(blob, node, "dr_mode", NULL);
 	if (mode) {
 		if (0 == strcmp(mode, "host"))
@@ -812,7 +814,7 @@
 	struct fdt_usb *priv = dev_get_priv(dev);
 	int ret;
 
-	ret = fdt_decode_usb(gd->fdt_blob, dev->of_offset, priv);
+	ret = fdt_decode_usb(dev, priv);
 	if (ret)
 		return ret;
 
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index 251885b..28416ed 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -61,7 +61,7 @@
 	/*
 	 * Get the base address for XHCI controller from the device node
 	 */
-	plat->hcd_base = fdtdec_get_addr(blob, dev->of_offset, "reg");
+	plat->hcd_base = dev_get_addr(dev);
 	if (plat->hcd_base == FDT_ADDR_T_NONE) {
 		debug("Can't get the XHCI register base address\n");
 		return -ENXIO;
diff --git a/drivers/video/tegra124/dp.c b/drivers/video/tegra124/dp.c
index 3c0b721..1bf9202 100644
--- a/drivers/video/tegra124/dp.c
+++ b/drivers/video/tegra124/dp.c
@@ -1555,9 +1555,8 @@
 static int tegra_dp_ofdata_to_platdata(struct udevice *dev)
 {
 	struct tegra_dp_plat *plat = dev_get_platdata(dev);
-	const void *blob = gd->fdt_blob;
 
-	plat->base = fdtdec_get_addr(blob, dev->of_offset, "reg");
+	plat->base = dev_get_addr(dev);
 
 	return 0;
 }
diff --git a/dts/Kconfig b/dts/Kconfig
index d72a909..a04bb96 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -58,7 +58,7 @@
 
 config OF_SPL_REMOVE_PROPS
 	string "List of device tree properties to drop for SPL"
-	depends on OF_CONTROL && SPL
+	depends on SPL_OF_CONTROL
 	default "pinctrl-0 pinctrl-names clocks clock-names interrupt-parent"
 	help
 	  Since SPL normally runs in a reduced memory space, the device tree
diff --git a/include/configs/controlcenterd.h b/include/configs/controlcenterd.h
index 8f829ed..9a1f6d0 100644
--- a/include/configs/controlcenterd.h
+++ b/include/configs/controlcenterd.h
@@ -226,14 +226,7 @@
 #define CONFIG_SF_DEFAULT_MODE		0
 #endif
 
-/*
- * TPM
- */
-#define CONFIG_TPM_ATMEL_TWI
-#define CONFIG_TPM
-#define CONFIG_TPM_AUTH_SESSIONS
 #define CONFIG_SHA1
-#define CONFIG_CMD_TPM
 
 /*
  * MMC
diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h
index 5779cfd..1c955d9 100644
--- a/include/configs/efi-x86.h
+++ b/include/configs/efi-x86.h
@@ -11,8 +11,6 @@
 
 #undef CONFIG_CMD_SF_TEST
 
-#undef CONFIG_TPM
-#undef CONFIG_TPM_TIS_LPC
 #undef CONFIG_TPM_TIS_BASE_ADDRESS
 
 #undef CONFIG_CMD_IMLS
diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h
index e710f41..4866836 100644
--- a/include/configs/exynos5-common.h
+++ b/include/configs/exynos5-common.h
@@ -54,13 +54,6 @@
 #define CONFIG_CMD_DTT
 #define CONFIG_TMU_CMD_DTT
 
-/* TPM */
-#define CONFIG_TPM
-#define CONFIG_CMD_TPM
-#define CONFIG_TPM_TIS_I2C
-#define CONFIG_TPM_TIS_I2C_BUS_NUMBER	3
-#define CONFIG_TPM_TIS_I2C_SLAVE_ADDR	0x20
-
 /* MMC SPL */
 #define COPY_BL2_FNPTR_ADDR	0x02020030
 #define CONFIG_SUPPORT_EMMC_BOOT
diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h
index 217312e..3f153f2 100644
--- a/include/configs/x86-common.h
+++ b/include/configs/x86-common.h
@@ -47,8 +47,6 @@
 #endif
 
 /* Generic TPM interfaced through LPC bus */
-#define CONFIG_TPM
-#define CONFIG_TPM_TIS_LPC
 #define CONFIG_TPM_TIS_BASE_ADDRESS        0xfed40000
 
 /*-----------------------------------------------------------------------
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 04884f1..322d35a 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -31,7 +31,7 @@
  * devices which use device tree.
  * @of_offset: Offset of device tree node for this device. This is -1 for
  * devices which don't use device tree.
- * @devp: Returns a pointer to the bound device
+ * @devp: if non-NULL, returns a pointer to the bound device
  * @return 0 if OK, -ve on error
  */
 int device_bind(struct udevice *parent, const struct driver *drv,
@@ -48,7 +48,7 @@
  * @pre_reloc_only: If true, bind the driver only if its DM_INIT_F flag is set.
  * If false bind the driver always.
  * @info: Name and platdata for this device
- * @devp: Returns a pointer to the bound device
+ * @devp: if non-NULL, returns a pointer to the bound device
  * @return 0 if OK, -ve on error
  */
 int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
diff --git a/include/dm/lists.h b/include/dm/lists.h
index 61610e6..4513d6a 100644
--- a/include/dm/lists.h
+++ b/include/dm/lists.h
@@ -68,7 +68,7 @@
  * @parent:	Parent device
  * @drv_name:	Name of driver to attach to this parent
  * @dev_name:	Name of the new device thus created
- * @devp:	Returns the newly bound device
+ * @devp:	If non-NULL, returns the newly bound device
  */
 int device_bind_driver(struct udevice *parent, const char *drv_name,
 		       const char *dev_name, struct udevice **devp);
@@ -83,7 +83,7 @@
  * @drv_name:	Name of driver to attach to this parent
  * @dev_name:	Name of the new device thus created
  * @node:	Device tree node
- * @devp:	Returns the newly bound device
+ * @devp:	If non-NULL, returns the newly bound device
  */
 int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
 			       const char *dev_name, int node,
diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h
new file mode 100644
index 0000000..bc6fdb4
--- /dev/null
+++ b/include/dm/pinctrl.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __PINCTRL_H
+#define __PINCTRL_H
+
+/**
+ * struct pinconf_param - pin config parameters
+ *
+ * @property: property name in DT nodes
+ * @param: ID for this config parameter
+ * @default_value: default value for this config parameter used in case
+ *	no value is specified in DT nodes
+ */
+struct pinconf_param {
+	const char * const property;
+	unsigned int param;
+	u32 default_value;
+};
+
+/**
+ * struct pinctrl_ops - pin control operations, to be implemented by
+ * pin controller drivers.
+ *
+ * The @set_state is the only mandatory operation.  You can implement your
+ * pinctrl driver with its own @set_state.  In this case, the other callbacks
+ * are not required.  Otherwise, generic pinctrl framework is also available;
+ * use pinctrl_generic_set_state for @set_state, and implement other operations
+ * depending on your necessity.
+ *
+ * @get_pins_count: return number of selectable named pins available
+ *	in this driver.  (necessary to parse "pins" property in DTS)
+ * @get_pin_name: return the pin name of the pin selector,
+ *	called by the core to figure out which pin it shall do
+ *	operations to.  (necessary to parse "pins" property in DTS)
+ * @get_groups_count: return number of selectable named groups available
+ *	in this driver.  (necessary to parse "groups" property in DTS)
+ * @get_group_name: return the group name of the group selector,
+ *	called by the core to figure out which pin group it shall do
+ *	operations to.  (necessary to parse "groups" property in DTS)
+ * @get_functions_count: return number of selectable named functions available
+ *	in this driver.  (necessary for pin-muxing)
+ * @get_function_name: return the function name of the muxing selector,
+ *	called by the core to figure out which mux setting it shall map a
+ *	certain device to.  (necessary for pin-muxing)
+ * @pinmux_set: enable a certain muxing function with a certain pin.
+ *	The @func_selector selects a certain function whereas @pin_selector
+ *	selects a certain pin to be used. On simple controllers one of them
+ *	may be ignored.  (necessary for pin-muxing against a single pin)
+ * @pinmux_group_set: enable a certain muxing function with a certain pin
+ *	group.  The @func_selector selects a certain function whereas
+ *	@group_selector selects a certain set of pins to be used. On simple
+ *	controllers one of them may be ignored.
+ *	(necessary for pin-muxing against a pin group)
+ * @pinconf_num_params: number of driver-specific parameters to be parsed
+ *	from device trees  (necessary for pin-configuration)
+ * @pinconf_params: list of driver_specific parameters to be parsed from
+ *	device trees  (necessary for pin-configuration)
+ * @pinconf_set: configure an individual pin with a given parameter.
+ *	(necessary for pin-configuration against a single pin)
+ * @pinconf_group_set: configure all pins in a group with a given parameter.
+ *	(necessary for pin-configuration against a pin group)
+ * @set_state: do pinctrl operations specified by @config, a pseudo device
+ *	pointing a config node. (necessary for pinctrl_full)
+ * @set_state_simple: do needed pinctrl operations for a peripherl @periph.
+ *	(necessary for pinctrl_simple)
+ */
+struct pinctrl_ops {
+	int (*get_pins_count)(struct udevice *dev);
+	const char *(*get_pin_name)(struct udevice *dev, unsigned selector);
+	int (*get_groups_count)(struct udevice *dev);
+	const char *(*get_group_name)(struct udevice *dev, unsigned selector);
+	int (*get_functions_count)(struct udevice *dev);
+	const char *(*get_function_name)(struct udevice *dev,
+					 unsigned selector);
+	int (*pinmux_set)(struct udevice *dev, unsigned pin_selector,
+			  unsigned func_selector);
+	int (*pinmux_group_set)(struct udevice *dev, unsigned group_selector,
+				unsigned func_selector);
+	unsigned int pinconf_num_params;
+	const struct pinconf_param *pinconf_params;
+	int (*pinconf_set)(struct udevice *dev, unsigned pin_selector,
+			   unsigned param, unsigned argument);
+	int (*pinconf_group_set)(struct udevice *dev, unsigned group_selector,
+				 unsigned param, unsigned argument);
+	int (*set_state)(struct udevice *dev, struct udevice *config);
+	int (*set_state_simple)(struct udevice *dev, struct udevice *periph);
+};
+
+#define pinctrl_get_ops(dev)	((struct pinctrl_ops *)(dev)->driver->ops)
+
+/**
+ * Generic pin configuration paramters
+ *
+ * @PIN_CONFIG_BIAS_DISABLE: disable any pin bias on the pin, a
+ *	transition from say pull-up to pull-down implies that you disable
+ *	pull-up in the process, this setting disables all biasing.
+ * @PIN_CONFIG_BIAS_HIGH_IMPEDANCE: the pin will be set to a high impedance
+ *	mode, also know as "third-state" (tristate) or "high-Z" or "floating".
+ *	On output pins this effectively disconnects the pin, which is useful
+ *	if for example some other pin is going to drive the signal connected
+ *	to it for a while. Pins used for input are usually always high
+ *	impedance.
+ * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
+ *	weakly drives the last value on a tristate bus, also known as a "bus
+ *	holder", "bus keeper" or "repeater". This allows another device on the
+ *	bus to change the value by driving the bus high or low and switching to
+ *	tristate. The argument is ignored.
+ * @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high
+ *	impedance to VDD). If the argument is != 0 pull-up is enabled,
+ *	if it is 0, pull-up is total, i.e. the pin is connected to VDD.
+ * @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high
+ *	impedance to GROUND). If the argument is != 0 pull-down is enabled,
+ *	if it is 0, pull-down is total, i.e. the pin is connected to GROUND.
+ * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: the pin will be pulled up or down based
+ *	on embedded knowledge of the controller hardware, like current mux
+ *	function. The pull direction and possibly strength too will normally
+ *	be decided completely inside the hardware block and not be readable
+ *	from the kernel side.
+ *	If the argument is != 0 pull up/down is enabled, if it is 0, the
+ *	configuration is ignored. The proper way to disable it is to use
+ *	@PIN_CONFIG_BIAS_DISABLE.
+ * @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and
+ *	low, this is the most typical case and is typically achieved with two
+ *	active transistors on the output. Setting this config will enable
+ *	push-pull mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_DRAIN: the pin will be driven with open drain (open
+ *	collector) which means it is usually wired with other output ports
+ *	which are then pulled up with an external resistor. Setting this
+ *	config will enable open drain mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source
+ *	(open emitter). Setting this config will enable open source mode, the
+ *	argument is ignored.
+ * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current
+ *	passed as argument. The argument is in mA.
+ * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input.  Note that this does not
+ *	affect the pin's ability to drive output.  1 enables input, 0 disables
+ *	input.
+ * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: control schmitt-trigger mode on the pin.
+ *      If the argument != 0, schmitt-trigger mode is enabled. If it's 0,
+ *      schmitt-trigger mode is disabled.
+ * @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in
+ *	schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis,
+ *	the threshold value is given on a custom format as argument when
+ *	setting pins to this mode.
+ * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
+ *	which means it will wait for signals to settle when reading inputs. The
+ *	argument gives the debounce time in usecs. Setting the
+ *	argument to zero turns debouncing off.
+ * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
+ *	supplies, the argument to this parameter (on a custom format) tells
+ *	the driver which alternative power source to use.
+ * @PIN_CONFIG_SLEW_RATE: if the pin can select slew rate, the argument to
+ *	this parameter (on a custom format) tells the driver which alternative
+ *	slew rate to use.
+ * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power
+ *	operation, if several modes of operation are supported these can be
+ *	passed in the argument on a custom form, else just use argument 1
+ *	to indicate low power mode, argument 0 turns low power mode off.
+ * @PIN_CONFIG_OUTPUT: this will configure the pin as an output. Use argument
+ *	1 to indicate high level, argument 0 to indicate low level. (Please
+ *	see Documentation/pinctrl.txt, section "GPIO mode pitfalls" for a
+ *	discussion around this parameter.)
+ * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
+ *	you need to pass in custom configurations to the pin controller, use
+ *	PIN_CONFIG_END+1 as the base offset.
+ */
+#define PIN_CONFIG_BIAS_DISABLE			0
+#define PIN_CONFIG_BIAS_HIGH_IMPEDANCE		1
+#define PIN_CONFIG_BIAS_BUS_HOLD		2
+#define PIN_CONFIG_BIAS_PULL_UP			3
+#define PIN_CONFIG_BIAS_PULL_DOWN		4
+#define PIN_CONFIG_BIAS_PULL_PIN_DEFAULT	5
+#define PIN_CONFIG_DRIVE_PUSH_PULL		6
+#define PIN_CONFIG_DRIVE_OPEN_DRAIN		7
+#define PIN_CONFIG_DRIVE_OPEN_SOURCE		8
+#define PIN_CONFIG_DRIVE_STRENGTH		9
+#define PIN_CONFIG_INPUT_ENABLE			10
+#define PIN_CONFIG_INPUT_SCHMITT_ENABLE		11
+#define PIN_CONFIG_INPUT_SCHMITT		12
+#define PIN_CONFIG_INPUT_DEBOUNCE		13
+#define PIN_CONFIG_POWER_SOURCE			14
+#define PIN_CONFIG_SLEW_RATE			15
+#define PIN_CONFIG_LOW_POWER_MODE		16
+#define PIN_CONFIG_OUTPUT			17
+#define PIN_CONFIG_END				0x7FFF
+
+#if CONFIG_IS_ENABLED(PINCTRL_GENERIC)
+/**
+ * pinctrl_generic_set_state() - generic set_state operation
+ * Parse the DT node of @config and its children and handle generic properties
+ * such as "pins", "groups", "functions", and pin configuration parameters.
+ *
+ * @pctldev: pinctrl device
+ * @config: config device (pseudo device), pointing a config node in DTS
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_generic_set_state(struct udevice *pctldev, struct udevice *config);
+#else
+static inline int pinctrl_generic_set_state(struct udevice *pctldev,
+					    struct udevice *config)
+{
+	return -EINVAL;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(PINCTRL)
+/**
+ * pinctrl_select_state() - set a device to a given state
+ *
+ * @dev: peripheral device
+ * @statename: state name, like "default"
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_select_state(struct udevice *dev, const char *statename);
+#else
+static inline int pinctrl_select_state(struct udevice *dev,
+				       const char *statename)
+{
+	return -EINVAL;
+}
+#endif
+
+#endif /* __PINCTRL_H */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index c744044..1eeec74 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -44,6 +44,8 @@
 	UCLASS_PCH,		/* x86 platform controller hub */
 	UCLASS_PCI,		/* PCI bus */
 	UCLASS_PCI_GENERIC,	/* Generic PCI bus device */
+	UCLASS_PINCTRL,		/* Pinctrl (pin muxing/configuration) device */
+	UCLASS_PINCONFIG,	/* Pin configuration node device */
 	UCLASS_PMIC,		/* PMIC I/O device */
 	UCLASS_REGULATOR,	/* Regulator device */
 	UCLASS_RESET,		/* Reset device */
@@ -54,6 +56,7 @@
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
 	UCLASS_SYSCON,		/* System configuration device */
 	UCLASS_THERMAL,		/* Thermal sensor */
+	UCLASS_TPM,		/* Trusted Platform Module TIS interface */
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
 	UCLASS_USB_HUB,		/* USB hub */
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index d56877c..d214b88 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -240,12 +240,7 @@
  * are no more devices.
  * @uc: uclass to scan
  */
-#define uclass_foreach_dev(pos, uc)					\
-	for (pos = list_entry((&(uc)->dev_head)->next, typeof(*pos),	\
-			uclass_node);					\
-	     prefetch(pos->uclass_node.next),				\
-			&pos->uclass_node != (&(uc)->dev_head);		\
-	     pos = list_entry(pos->uclass_node.next, typeof(*pos),	\
-			uclass_node))
+#define uclass_foreach_dev(pos, uc)	\
+	list_for_each_entry(pos, &uc->dev_head, uclass_node)
 
 #endif
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 0cb6fa0..3e23731 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -154,8 +154,6 @@
 	COMPAT_MAXIM_MAX77686_PMIC,	/* MAX77686 PMIC */
 	COMPAT_GENERIC_SPI_FLASH,	/* Generic SPI Flash chip */
 	COMPAT_MAXIM_98095_CODEC,	/* MAX98095 Codec */
-	COMPAT_INFINEON_SLB9635_TPM,	/* Infineon SLB9635 TPM */
-	COMPAT_INFINEON_SLB9645_TPM,	/* Infineon SLB9645 TPM */
 	COMPAT_SAMSUNG_EXYNOS5_I2C,	/* Exynos5 High Speed I2C Controller */
 	COMPAT_SANDBOX_LCD_SDL,		/* Sandbox LCD emulation with SDL */
 	COMPAT_SAMSUNG_EXYNOS_SYSMMU,	/* Exynos sysmmu */
diff --git a/include/tis.h b/include/tis.h
index 40a1f86..1985d9e 100644
--- a/include/tis.h
+++ b/include/tis.h
@@ -7,6 +7,8 @@
 #ifndef __TIS_H
 #define __TIS_H
 
+#ifndef CONFIG_DM_TPM
+
 #include <common.h>
 
 /* Low-level interface to access TPM */
@@ -53,5 +55,6 @@
  */
 int tis_sendrecv(const uint8_t *sendbuf, size_t send_size, uint8_t *recvbuf,
 			size_t *recv_len);
+#endif
 
 #endif /* __TIS_H */
diff --git a/include/tpm.h b/include/tpm.h
index 88aeba2..086b672 100644
--- a/include/tpm.h
+++ b/include/tpm.h
@@ -15,6 +15,17 @@
  * Specification for definitions of TPM commands.
  */
 
+#define TPM_HEADER_SIZE		10
+
+enum tpm_duration {
+	TPM_SHORT = 0,
+	TPM_MEDIUM = 1,
+	TPM_LONG = 2,
+	TPM_UNDEFINED,
+
+	TPM_DURATION_COUNT,
+};
+
 enum tpm_startup_type {
 	TPM_ST_CLEAR		= 0x0001,
 	TPM_ST_STATE		= 0x0002,
@@ -38,6 +49,15 @@
 	TPM_NV_INDEX_DIR	= 0x10000001,
 };
 
+#define TPM_NV_PER_GLOBALLOCK		(1U << 15)
+#define TPM_NV_PER_PPWRITE		(1U << 0)
+#define TPM_NV_PER_READ_STCLEAR		(1U << 31)
+#define TPM_NV_PER_WRITE_STCLEAR	(1U << 14)
+
+enum {
+	TPM_PUBEK_SIZE			= 256,
+};
+
 /**
  * TPM return codes as defined in the TCG Main specification
  * (TPM Main Part 2 Structures; Specification version 1.2)
@@ -152,12 +172,217 @@
 	TPM_DEFEND_LOCK_RUNNING	= TPM_BASE + TPM_NON_FATAL + 3,
 };
 
+struct tpm_permanent_flags {
+	__be16	tag;
+	u8	disable;
+	u8	ownership;
+	u8	deactivated;
+	u8	read_pubek;
+	u8	disable_owner_clear;
+	u8	allow_maintenance;
+	u8	physical_presence_lifetime_lock;
+	u8	physical_presence_hw_enable;
+	u8	physical_presence_cmd_enable;
+	u8	cekp_used;
+	u8	tpm_post;
+	u8	tpm_post_lock;
+	u8	fips;
+	u8	operator;
+	u8	enable_revoke_ek;
+	u8	nv_locked;
+	u8	read_srk_pub;
+	u8	tpm_established;
+	u8	maintenance_done;
+	u8	disable_full_da_logic_info;
+} __packed;
+
+#ifdef CONFIG_DM_TPM
+
+/* Max buffer size supported by our tpm */
+#define TPM_DEV_BUFSIZE		1260
+
+/**
+ * struct tpm_chip_priv - Information about a TPM, stored by the uclass
+ *
+ * These values must be set up by the device's probe() method before
+ * communcation is attempted. If the device has an xfer() method, this is
+ * not needed. There is no need to set up @buf.
+ *
+ * @duration_ms:	Length of each duration type in milliseconds
+ * @retry_time_ms:	Time to wait before retrying receive
+ */
+struct tpm_chip_priv {
+	uint duration_ms[TPM_DURATION_COUNT];
+	uint retry_time_ms;
+	u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)];  /* Max buffer size + addr */
+};
+
+/**
+ * struct tpm_ops - low-level TPM operations
+ *
+ * These are designed to avoid loops and delays in the driver itself. These
+ * should be handled in the uclass.
+ *
+ * In gneral you should implement everything except xfer(). Where you need
+ * complete control of the transfer, then xfer() can be provided and will
+ * override the other methods.
+ *
+ * This interface is for low-level TPM access. It does not understand the
+ * concept of localities or the various TPM messages. That interface is
+ * defined in the functions later on in this file, but they all translate
+ * to bytes which are sent and received.
+ */
+struct tpm_ops {
+	/**
+	 * open() - Request access to locality 0 for the caller
+	 *
+	 * After all commands have been completed the caller should call
+	 * close().
+	 *
+	 * @dev:	Device to close
+	 * @return 0 ok OK, -ve on error
+	 */
+	int (*open)(struct udevice *dev);
+
+	/**
+	 * close() - Close the current session
+	 *
+	 * Releasing the locked locality. Returns 0 on success, -ve 1 on
+	 * failure (in case lock removal did not succeed).
+	 *
+	 * @dev:	Device to close
+	 * @return 0 ok OK, -ve on error
+	 */
+	int (*close)(struct udevice *dev);
+
+	/**
+	 * get_desc() - Get a text description of the TPM
+	 *
+	 * @dev:	Device to check
+	 * @buf:	Buffer to put the string
+	 * @size:	Maximum size of buffer
+	 * @return length of string, or -ENOSPC it no space
+	 */
+	int (*get_desc)(struct udevice *dev, char *buf, int size);
+
+	/**
+	 * send() - send data to the TPM
+	 *
+	 * @dev:	Device to talk to
+	 * @sendbuf:	Buffer of the data to send
+	 * @send_size:	Size of the data to send
+	 *
+	 * Returns 0 on success or -ve on failure.
+	 */
+	int (*send)(struct udevice *dev, const uint8_t *sendbuf,
+		    size_t send_size);
+
+	/**
+	 * recv() - receive a response from the TPM
+	 *
+	 * @dev:	Device to talk to
+	 * @recvbuf:	Buffer to save the response to
+	 * @max_size:	Maximum number of bytes to receive
+	 *
+	 * Returns number of bytes received on success, -EAGAIN if the TPM
+	 * response is not ready, -EINTR if cancelled, or other -ve value on
+	 * failure.
+	 */
+	int (*recv)(struct udevice *dev, uint8_t *recvbuf, size_t max_size);
+
+	/**
+	 * cleanup() - clean up after an operation in progress
+	 *
+	 * This is called if receiving times out. The TPM may need to abort
+	 * the current transaction if it did not complete, and make itself
+	 * ready for another.
+	 *
+	 * @dev:	Device to talk to
+	 */
+	int (*cleanup)(struct udevice *dev);
+
+	/**
+	 * xfer() - send data to the TPM and get response
+	 *
+	 * This method is optional. If it exists it is used in preference
+	 * to send(), recv() and cleanup(). It should handle all aspects of
+	 * TPM communication for a single transfer.
+	 *
+	 * @dev:	Device to talk to
+	 * @sendbuf:	Buffer of the data to send
+	 * @send_size:	Size of the data to send
+	 * @recvbuf:	Buffer to save the response to
+	 * @recv_size:	Pointer to the size of the response buffer
+	 *
+	 * Returns 0 on success (and places the number of response bytes at
+	 * recv_size) or -ve on failure.
+	 */
+	int (*xfer)(struct udevice *dev, const uint8_t *sendbuf,
+		    size_t send_size, uint8_t *recvbuf, size_t *recv_size);
+};
+
+#define tpm_get_ops(dev)        ((struct tpm_ops *)device_get_ops(dev))
+
+/**
+ * tpm_open() - Request access to locality 0 for the caller
+ *
+ * After all commands have been completed the caller is supposed to
+ * call tpm_close().
+ *
+ * Returns 0 on success, -ve on failure.
+ */
+int tpm_open(struct udevice *dev);
+
+/**
+ * tpm_close() - Close the current session
+ *
+ * Releasing the locked locality. Returns 0 on success, -ve 1 on
+ * failure (in case lock removal did not succeed).
+ */
+int tpm_close(struct udevice *dev);
+
+/**
+ * tpm_get_desc() - Get a text description of the TPM
+ *
+ * @dev:	Device to check
+ * @buf:	Buffer to put the string
+ * @size:	Maximum size of buffer
+ * @return length of string, or -ENOSPC it no space
+ */
+int tpm_get_desc(struct udevice *dev, char *buf, int size);
+
+/**
+ * tpm_xfer() - send data to the TPM and get response
+ *
+ * This first uses the device's send() method to send the bytes. Then it calls
+ * recv() to get the reply. If recv() returns -EAGAIN then it will delay a
+ * short time and then call recv() again.
+ *
+ * Regardless of whether recv() completes successfully, it will then call
+ * cleanup() to finish the transaction.
+ *
+ * Note that the outgoing data is inspected to determine command type
+ * (ordinal) and a timeout is used for that command type.
+ *
+ * @sendbuf - buffer of the data to send
+ * @send_size size of the data to send
+ * @recvbuf - memory to save the response to
+ * @recv_len - pointer to the size of the response buffer
+ *
+ * Returns 0 on success (and places the number of response bytes at
+ * recv_len) or -ve on failure.
+ */
+int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
+	     uint8_t *recvbuf, size_t *recv_size);
+
+#endif /* CONFIG_DM_TPM */
+
 /**
  * Initialize TPM device.  It must be called before any TPM commands.
  *
  * @return 0 on success, non-0 on error.
  */
-uint32_t tpm_init(void);
+int tpm_init(void);
 
 /**
  * Issue a TPM_Startup command.
@@ -359,4 +584,20 @@
 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
 		void *pubkey, size_t *pubkey_len);
 
+/**
+ * Get the TPM permanent flags value
+ *
+ * @param pflags	Place to put permanent flags
+ * @return return code of the operation
+ */
+uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags);
+
+/**
+ * Get the TPM permissions
+ *
+ * @param perm		Returns permissions value
+ * @return return code of the operation
+ */
+uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm);
+
 #endif /* __TPM_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 884218a..0673072 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -54,6 +54,16 @@
 
 source lib/rsa/Kconfig
 
+config TPM
+	bool "Trusted Platform Module (TPM) Support"
+	help
+	  This enables support for TPMs which can be used to provide security
+	  features for your board. The TPM can be connected via LPC or I2C
+	  and a sandbox TPM is provided for testing purposes. Use the 'tpm'
+	  command to interactive the TPM. Driver model support is provided
+	  for the low-level TPM interface, but only one TPM is supported at
+	  a time by the TPM library.
+
 menu "Hashing Support"
 
 config SHA1
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 81b54f8..29c5ccb 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -58,8 +58,6 @@
 	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686"),
 	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
 	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
-	COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),
-	COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645tt"),
 	COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
 	COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
 	COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
diff --git a/lib/tpm.c b/lib/tpm.c
index d9789b0..5d5f707 100644
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -6,10 +6,11 @@
  */
 
 #include <common.h>
-#include <stdarg.h>
-#include <u-boot/sha1.h>
+#include <dm.h>
+#include <tis.h>
 #include <tpm.h>
 #include <asm/unaligned.h>
+#include <u-boot/sha1.h>
 
 /* Internal error of TPM command library */
 #define TPM_LIB_ERROR	((uint32_t)~0u)
@@ -17,7 +18,6 @@
 /* Useful constants */
 enum {
 	COMMAND_BUFFER_SIZE		= 256,
-	TPM_PUBEK_SIZE			= 256,
 	TPM_REQUEST_HEADER_LENGTH	= 10,
 	TPM_RESPONSE_HEADER_LENGTH	= 10,
 	PCR_DIGEST_LENGTH		= 20,
@@ -240,9 +240,20 @@
 		response = response_buffer;
 		response_length = sizeof(response_buffer);
 	}
+#ifdef CONFIG_DM_TPM
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_TPM, &dev);
+	if (ret)
+		return ret;
+	err = tpm_xfer(dev, command, tpm_command_size(command),
+		       response, &response_length);
+#else
 	err = tis_sendrecv(command, tpm_command_size(command),
 			response, &response_length);
-	if (err)
+#endif
+	if (err < 0)
 		return TPM_LIB_ERROR;
 	if (size_ptr)
 		*size_ptr = response_length;
@@ -250,15 +261,24 @@
 	return tpm_return_code(response);
 }
 
-uint32_t tpm_init(void)
+int tpm_init(void)
 {
-	uint32_t err;
+	int err;
 
+#ifdef CONFIG_DM_TPM
+	struct udevice *dev;
+
+	err = uclass_first_device(UCLASS_TPM, &dev);
+	if (err)
+		return err;
+	return tpm_open(dev);
+#else
 	err = tis_init();
 	if (err)
 		return err;
 
 	return tis_open();
+#endif
 }
 
 uint32_t tpm_startup(enum tpm_startup_type mode)
@@ -589,6 +609,56 @@
 	return 0;
 }
 
+uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
+{
+	const uint8_t command[22] = {
+		0x0, 0xc1,		/* TPM_TAG */
+		0x0, 0x0, 0x0, 0x16,	/* parameter size */
+		0x0, 0x0, 0x0, 0x65,	/* TPM_COMMAND_CODE */
+		0x0, 0x0, 0x0, 0x4,	/* TPM_CAP_FLAG_PERM */
+		0x0, 0x0, 0x0, 0x4,	/* subcap size */
+		0x0, 0x0, 0x1, 0x8,	/* subcap value */
+	};
+	uint8_t response[COMMAND_BUFFER_SIZE];
+	size_t response_length = sizeof(response);
+	uint32_t err;
+
+	err = tpm_sendrecv_command(command, response, &response_length);
+	if (err)
+		return err;
+	memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
+
+	return 0;
+}
+
+uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
+{
+	const uint8_t command[22] = {
+		0x0, 0xc1,		/* TPM_TAG */
+		0x0, 0x0, 0x0, 0x16,	/* parameter size */
+		0x0, 0x0, 0x0, 0x65,	/* TPM_COMMAND_CODE */
+		0x0, 0x0, 0x0, 0x11,
+		0x0, 0x0, 0x0, 0x4,
+	};
+	const size_t index_offset = 18;
+	const size_t perm_offset = 60;
+	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
+	size_t response_length = sizeof(response);
+	uint32_t err;
+
+	if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
+			     index_offset, index))
+		return TPM_LIB_ERROR;
+	err = tpm_sendrecv_command(buf, response, &response_length);
+	if (err)
+		return err;
+	if (unpack_byte_string(response, response_length, "d",
+			       perm_offset, perm))
+		return TPM_LIB_ERROR;
+
+	return 0;
+}
+
 #ifdef CONFIG_TPM_AUTH_SESSIONS
 
 /**
diff --git a/tools/patman/series.py b/tools/patman/series.py
index a17a7d1..3399f2c 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -12,7 +12,7 @@
 
 # Series-xxx tags that we understand
 valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name',
-                'cover-cc', 'process_log']
+                'cover_cc', 'process_log']
 
 class Series(dict):
     """Holds information about a patch series, including all tags.