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
 
 # SPDX-License-Identifier:     GPL-2.0+
 #
 
+obj-$(CONFIG_DM_TPM) += tpm-uclass.o
+
 obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
 obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o
 obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
 
--- /dev/null
+/*
+ * 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),
+};
 
--- /dev/null
+/*
+ * 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
 
 #include <fdtdec.h>
 #include <linux/compiler.h>
 #include <i2c.h>
+#include <tis.h>
 #include <tpm.h>
 #include <asm-generic/errno.h>
 #include <linux/types.h>
 #include <linux/unaligned/be_byteshift.h>
 
 #include "tpm_tis_i2c.h"
+#include "tpm_internal.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
 
 #define        TPM_DATA_FIFO(l)                (0x0005 | ((l) << 4))
 #define        TPM_DID_VID(l)                  (0x0006 | ((l) << 4))
 
-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,
-};
-
 #endif
 
 
 #include <common.h>
 #include <asm/io.h>
+#include <tis.h>
 #include <tpm.h>
 
 #define PREFIX "lpc_tpm: "
 {
        u8 locality = 0; /* we use locality zero for everything. */
 
-       if (tis_close())
-               return TPM_DRIVER_ERR;
-
        /* now request access to locality. */
        tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access);
 
 
        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 */
 
 #ifndef __TIS_H
 #define __TIS_H
 
+#ifndef CONFIG_DM_TPM
+
 #include <common.h>
 
 /* Low-level interface to access TPM */
  */
 int tis_sendrecv(const uint8_t *sendbuf, size_t send_size, uint8_t *recvbuf,
                        size_t *recv_len);
+#endif
 
 #endif /* __TIS_H */
 
  * 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,
        TPM_DEFEND_LOCK_RUNNING = TPM_BASE + TPM_NON_FATAL + 3,
 };
 
+#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.
  *