18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012,2013 Infineon Technologies
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci * Peter Huewe <peter.huewe@infineon.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Device driver for TCG/TCPA TPM (trusted platform module).
98c2ecf20Sopenharmony_ci * Specifications at www.trustedcomputinggroup.org
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * This device driver implements the TPM interface as defined in
128c2ecf20Sopenharmony_ci * the TCG TPM Interface Spec version 1.2, revision 1.0 and the
138c2ecf20Sopenharmony_ci * Infineon I2C Protocol Stack Specification v0.20.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * It is based on the original tpm_tis device driver from Leendert van
168c2ecf20Sopenharmony_ci * Dorn and Kyleen Hall.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci#include <linux/i2c.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/wait.h>
218c2ecf20Sopenharmony_ci#include "tpm.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define TPM_I2C_INFINEON_BUFSIZE 1260
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* max. number of iterations after I2C NAK */
268c2ecf20Sopenharmony_ci#define MAX_COUNT 3
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define SLEEP_DURATION_LOW 55
298c2ecf20Sopenharmony_ci#define SLEEP_DURATION_HI 65
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* max. number of iterations after I2C NAK for 'long' commands
328c2ecf20Sopenharmony_ci * we need this especially for sending TPM_READY, since the cleanup after the
338c2ecf20Sopenharmony_ci * transtion to the ready state may take some time, but it is unpredictable
348c2ecf20Sopenharmony_ci * how long it will take.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define MAX_COUNT_LONG 50
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define SLEEP_DURATION_LONG_LOW 200
398c2ecf20Sopenharmony_ci#define SLEEP_DURATION_LONG_HI 220
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* After sending TPM_READY to 'reset' the TPM we have to sleep even longer */
428c2ecf20Sopenharmony_ci#define SLEEP_DURATION_RESET_LOW 2400
438c2ecf20Sopenharmony_ci#define SLEEP_DURATION_RESET_HI 2600
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* we want to use usleep_range instead of msleep for the 5ms TPM_TIMEOUT */
468c2ecf20Sopenharmony_ci#define TPM_TIMEOUT_US_LOW (TPM_TIMEOUT * 1000)
478c2ecf20Sopenharmony_ci#define TPM_TIMEOUT_US_HI  (TPM_TIMEOUT_US_LOW + 2000)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* expected value for DIDVID register */
508c2ecf20Sopenharmony_ci#define TPM_TIS_I2C_DID_VID_9635 0xd1150b00L
518c2ecf20Sopenharmony_ci#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cienum i2c_chip_type {
548c2ecf20Sopenharmony_ci	SLB9635,
558c2ecf20Sopenharmony_ci	SLB9645,
568c2ecf20Sopenharmony_ci	UNKNOWN,
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct tpm_inf_dev {
608c2ecf20Sopenharmony_ci	struct i2c_client *client;
618c2ecf20Sopenharmony_ci	int locality;
628c2ecf20Sopenharmony_ci	/* In addition to the data itself, the buffer must fit the 7-bit I2C
638c2ecf20Sopenharmony_ci	 * address and the direction bit.
648c2ecf20Sopenharmony_ci	 */
658c2ecf20Sopenharmony_ci	u8 buf[TPM_I2C_INFINEON_BUFSIZE + 1];
668c2ecf20Sopenharmony_ci	struct tpm_chip *chip;
678c2ecf20Sopenharmony_ci	enum i2c_chip_type chip_type;
688c2ecf20Sopenharmony_ci	unsigned int adapterlimit;
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic struct tpm_inf_dev tpm_dev;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * iic_tpm_read() - read from TPM register
758c2ecf20Sopenharmony_ci * @addr: register address to read from
768c2ecf20Sopenharmony_ci * @buffer: provided by caller
778c2ecf20Sopenharmony_ci * @len: number of bytes to read
788c2ecf20Sopenharmony_ci *
798c2ecf20Sopenharmony_ci * Read len bytes from TPM register and put them into
808c2ecf20Sopenharmony_ci * buffer (little-endian format, i.e. first byte is put into buffer[0]).
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * NOTE: TPM is big-endian for multi-byte values. Multi-byte
838c2ecf20Sopenharmony_ci * values have to be swapped.
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci * NOTE: We can't unfortunately use the combined read/write functions
868c2ecf20Sopenharmony_ci * provided by the i2c core as the TPM currently does not support the
878c2ecf20Sopenharmony_ci * repeated start condition and due to it's special requirements.
888c2ecf20Sopenharmony_ci * The i2c_smbus* functions do not work for this chip.
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci * Return -EIO on error, 0 on success.
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_cistatic int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	struct i2c_msg msg1 = {
968c2ecf20Sopenharmony_ci		.addr = tpm_dev.client->addr,
978c2ecf20Sopenharmony_ci		.len = 1,
988c2ecf20Sopenharmony_ci		.buf = &addr
998c2ecf20Sopenharmony_ci	};
1008c2ecf20Sopenharmony_ci	struct i2c_msg msg2 = {
1018c2ecf20Sopenharmony_ci		.addr = tpm_dev.client->addr,
1028c2ecf20Sopenharmony_ci		.flags = I2C_M_RD,
1038c2ecf20Sopenharmony_ci		.len = len,
1048c2ecf20Sopenharmony_ci		.buf = buffer
1058c2ecf20Sopenharmony_ci	};
1068c2ecf20Sopenharmony_ci	struct i2c_msg msgs[] = {msg1, msg2};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	int rc = 0;
1098c2ecf20Sopenharmony_ci	int count;
1108c2ecf20Sopenharmony_ci	unsigned int msglen = len;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/* Lock the adapter for the duration of the whole sequence. */
1138c2ecf20Sopenharmony_ci	if (!tpm_dev.client->adapter->algo->master_xfer)
1148c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1158c2ecf20Sopenharmony_ci	i2c_lock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (tpm_dev.chip_type == SLB9645) {
1188c2ecf20Sopenharmony_ci		/* use a combined read for newer chips
1198c2ecf20Sopenharmony_ci		 * unfortunately the smbus functions are not suitable due to
1208c2ecf20Sopenharmony_ci		 * the 32 byte limit of the smbus.
1218c2ecf20Sopenharmony_ci		 * retries should usually not be needed, but are kept just to
1228c2ecf20Sopenharmony_ci		 * be on the safe side.
1238c2ecf20Sopenharmony_ci		 */
1248c2ecf20Sopenharmony_ci		for (count = 0; count < MAX_COUNT; count++) {
1258c2ecf20Sopenharmony_ci			rc = __i2c_transfer(tpm_dev.client->adapter, msgs, 2);
1268c2ecf20Sopenharmony_ci			if (rc > 0)
1278c2ecf20Sopenharmony_ci				break;	/* break here to skip sleep */
1288c2ecf20Sopenharmony_ci			usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
1298c2ecf20Sopenharmony_ci		}
1308c2ecf20Sopenharmony_ci	} else {
1318c2ecf20Sopenharmony_ci		/* Expect to send one command message and one data message, but
1328c2ecf20Sopenharmony_ci		 * support looping over each or both if necessary.
1338c2ecf20Sopenharmony_ci		 */
1348c2ecf20Sopenharmony_ci		while (len > 0) {
1358c2ecf20Sopenharmony_ci			/* slb9635 protocol should work in all cases */
1368c2ecf20Sopenharmony_ci			for (count = 0; count < MAX_COUNT; count++) {
1378c2ecf20Sopenharmony_ci				rc = __i2c_transfer(tpm_dev.client->adapter,
1388c2ecf20Sopenharmony_ci						    &msg1, 1);
1398c2ecf20Sopenharmony_ci				if (rc > 0)
1408c2ecf20Sopenharmony_ci					break;	/* break here to skip sleep */
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci				usleep_range(SLEEP_DURATION_LOW,
1438c2ecf20Sopenharmony_ci					     SLEEP_DURATION_HI);
1448c2ecf20Sopenharmony_ci			}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci			if (rc <= 0)
1478c2ecf20Sopenharmony_ci				goto out;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci			/* After the TPM has successfully received the register
1508c2ecf20Sopenharmony_ci			 * address it needs some time, thus we're sleeping here
1518c2ecf20Sopenharmony_ci			 * again, before retrieving the data
1528c2ecf20Sopenharmony_ci			 */
1538c2ecf20Sopenharmony_ci			for (count = 0; count < MAX_COUNT; count++) {
1548c2ecf20Sopenharmony_ci				if (tpm_dev.adapterlimit) {
1558c2ecf20Sopenharmony_ci					msglen = min_t(unsigned int,
1568c2ecf20Sopenharmony_ci						       tpm_dev.adapterlimit,
1578c2ecf20Sopenharmony_ci						       len);
1588c2ecf20Sopenharmony_ci					msg2.len = msglen;
1598c2ecf20Sopenharmony_ci				}
1608c2ecf20Sopenharmony_ci				usleep_range(SLEEP_DURATION_LOW,
1618c2ecf20Sopenharmony_ci					     SLEEP_DURATION_HI);
1628c2ecf20Sopenharmony_ci				rc = __i2c_transfer(tpm_dev.client->adapter,
1638c2ecf20Sopenharmony_ci						    &msg2, 1);
1648c2ecf20Sopenharmony_ci				if (rc > 0) {
1658c2ecf20Sopenharmony_ci					/* Since len is unsigned, make doubly
1668c2ecf20Sopenharmony_ci					 * sure we do not underflow it.
1678c2ecf20Sopenharmony_ci					 */
1688c2ecf20Sopenharmony_ci					if (msglen > len)
1698c2ecf20Sopenharmony_ci						len = 0;
1708c2ecf20Sopenharmony_ci					else
1718c2ecf20Sopenharmony_ci						len -= msglen;
1728c2ecf20Sopenharmony_ci					msg2.buf += msglen;
1738c2ecf20Sopenharmony_ci					break;
1748c2ecf20Sopenharmony_ci				}
1758c2ecf20Sopenharmony_ci				/* If the I2C adapter rejected the request (e.g
1768c2ecf20Sopenharmony_ci				 * when the quirk read_max_len < len) fall back
1778c2ecf20Sopenharmony_ci				 * to a sane minimum value and try again.
1788c2ecf20Sopenharmony_ci				 */
1798c2ecf20Sopenharmony_ci				if (rc == -EOPNOTSUPP)
1808c2ecf20Sopenharmony_ci					tpm_dev.adapterlimit =
1818c2ecf20Sopenharmony_ci							I2C_SMBUS_BLOCK_MAX;
1828c2ecf20Sopenharmony_ci			}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci			if (rc <= 0)
1858c2ecf20Sopenharmony_ci				goto out;
1868c2ecf20Sopenharmony_ci		}
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ciout:
1908c2ecf20Sopenharmony_ci	i2c_unlock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT);
1918c2ecf20Sopenharmony_ci	/* take care of 'guard time' */
1928c2ecf20Sopenharmony_ci	usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* __i2c_transfer returns the number of successfully transferred
1958c2ecf20Sopenharmony_ci	 * messages.
1968c2ecf20Sopenharmony_ci	 * So rc should be greater than 0 here otherwise we have an error.
1978c2ecf20Sopenharmony_ci	 */
1988c2ecf20Sopenharmony_ci	if (rc <= 0)
1998c2ecf20Sopenharmony_ci		return -EIO;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
2058c2ecf20Sopenharmony_ci				 unsigned int sleep_low,
2068c2ecf20Sopenharmony_ci				 unsigned int sleep_hi, u8 max_count)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	int rc = -EIO;
2098c2ecf20Sopenharmony_ci	int count;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	struct i2c_msg msg1 = {
2128c2ecf20Sopenharmony_ci		.addr = tpm_dev.client->addr,
2138c2ecf20Sopenharmony_ci		.len = len + 1,
2148c2ecf20Sopenharmony_ci		.buf = tpm_dev.buf
2158c2ecf20Sopenharmony_ci	};
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (len > TPM_I2C_INFINEON_BUFSIZE)
2188c2ecf20Sopenharmony_ci		return -EINVAL;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (!tpm_dev.client->adapter->algo->master_xfer)
2218c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2228c2ecf20Sopenharmony_ci	i2c_lock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* prepend the 'register address' to the buffer */
2258c2ecf20Sopenharmony_ci	tpm_dev.buf[0] = addr;
2268c2ecf20Sopenharmony_ci	memcpy(&(tpm_dev.buf[1]), buffer, len);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/*
2298c2ecf20Sopenharmony_ci	 * NOTE: We have to use these special mechanisms here and unfortunately
2308c2ecf20Sopenharmony_ci	 * cannot rely on the standard behavior of i2c_transfer.
2318c2ecf20Sopenharmony_ci	 * Even for newer chips the smbus functions are not
2328c2ecf20Sopenharmony_ci	 * suitable due to the 32 byte limit of the smbus.
2338c2ecf20Sopenharmony_ci	 */
2348c2ecf20Sopenharmony_ci	for (count = 0; count < max_count; count++) {
2358c2ecf20Sopenharmony_ci		rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
2368c2ecf20Sopenharmony_ci		if (rc > 0)
2378c2ecf20Sopenharmony_ci			break;
2388c2ecf20Sopenharmony_ci		usleep_range(sleep_low, sleep_hi);
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	i2c_unlock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT);
2428c2ecf20Sopenharmony_ci	/* take care of 'guard time' */
2438c2ecf20Sopenharmony_ci	usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* __i2c_transfer returns the number of successfully transferred
2468c2ecf20Sopenharmony_ci	 * messages.
2478c2ecf20Sopenharmony_ci	 * So rc should be greater than 0 here otherwise we have an error.
2488c2ecf20Sopenharmony_ci	 */
2498c2ecf20Sopenharmony_ci	if (rc <= 0)
2508c2ecf20Sopenharmony_ci		return -EIO;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*
2568c2ecf20Sopenharmony_ci * iic_tpm_write() - write to TPM register
2578c2ecf20Sopenharmony_ci * @addr: register address to write to
2588c2ecf20Sopenharmony_ci * @buffer: containing data to be written
2598c2ecf20Sopenharmony_ci * @len: number of bytes to write
2608c2ecf20Sopenharmony_ci *
2618c2ecf20Sopenharmony_ci * Write len bytes from provided buffer to TPM register (little
2628c2ecf20Sopenharmony_ci * endian format, i.e. buffer[0] is written as first byte).
2638c2ecf20Sopenharmony_ci *
2648c2ecf20Sopenharmony_ci * NOTE: TPM is big-endian for multi-byte values. Multi-byte
2658c2ecf20Sopenharmony_ci * values have to be swapped.
2668c2ecf20Sopenharmony_ci *
2678c2ecf20Sopenharmony_ci * NOTE: use this function instead of the iic_tpm_write_generic function.
2688c2ecf20Sopenharmony_ci *
2698c2ecf20Sopenharmony_ci * Return -EIO on error, 0 on success
2708c2ecf20Sopenharmony_ci */
2718c2ecf20Sopenharmony_cistatic int iic_tpm_write(u8 addr, u8 *buffer, size_t len)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LOW,
2748c2ecf20Sopenharmony_ci				     SLEEP_DURATION_HI, MAX_COUNT);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci/*
2788c2ecf20Sopenharmony_ci * This function is needed especially for the cleanup situation after
2798c2ecf20Sopenharmony_ci * sending TPM_READY
2808c2ecf20Sopenharmony_ci * */
2818c2ecf20Sopenharmony_cistatic int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG_LOW,
2848c2ecf20Sopenharmony_ci				     SLEEP_DURATION_LONG_HI, MAX_COUNT_LONG);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cienum tis_access {
2888c2ecf20Sopenharmony_ci	TPM_ACCESS_VALID = 0x80,
2898c2ecf20Sopenharmony_ci	TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
2908c2ecf20Sopenharmony_ci	TPM_ACCESS_REQUEST_PENDING = 0x04,
2918c2ecf20Sopenharmony_ci	TPM_ACCESS_REQUEST_USE = 0x02,
2928c2ecf20Sopenharmony_ci};
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cienum tis_status {
2958c2ecf20Sopenharmony_ci	TPM_STS_VALID = 0x80,
2968c2ecf20Sopenharmony_ci	TPM_STS_COMMAND_READY = 0x40,
2978c2ecf20Sopenharmony_ci	TPM_STS_GO = 0x20,
2988c2ecf20Sopenharmony_ci	TPM_STS_DATA_AVAIL = 0x10,
2998c2ecf20Sopenharmony_ci	TPM_STS_DATA_EXPECT = 0x08,
3008c2ecf20Sopenharmony_ci};
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cienum tis_defaults {
3038c2ecf20Sopenharmony_ci	TIS_SHORT_TIMEOUT = 750,	/* ms */
3048c2ecf20Sopenharmony_ci	TIS_LONG_TIMEOUT = 2000,	/* 2 sec */
3058c2ecf20Sopenharmony_ci};
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci#define	TPM_ACCESS(l)			(0x0000 | ((l) << 4))
3088c2ecf20Sopenharmony_ci#define	TPM_STS(l)			(0x0001 | ((l) << 4))
3098c2ecf20Sopenharmony_ci#define	TPM_DATA_FIFO(l)		(0x0005 | ((l) << 4))
3108c2ecf20Sopenharmony_ci#define	TPM_DID_VID(l)			(0x0006 | ((l) << 4))
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic bool check_locality(struct tpm_chip *chip, int loc)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	u8 buf;
3158c2ecf20Sopenharmony_ci	int rc;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1);
3188c2ecf20Sopenharmony_ci	if (rc < 0)
3198c2ecf20Sopenharmony_ci		return false;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
3228c2ecf20Sopenharmony_ci	    (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
3238c2ecf20Sopenharmony_ci		tpm_dev.locality = loc;
3248c2ecf20Sopenharmony_ci		return true;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return false;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci/* implementation similar to tpm_tis */
3318c2ecf20Sopenharmony_cistatic void release_locality(struct tpm_chip *chip, int loc, int force)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	u8 buf;
3348c2ecf20Sopenharmony_ci	if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0)
3358c2ecf20Sopenharmony_ci		return;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
3388c2ecf20Sopenharmony_ci	    (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
3398c2ecf20Sopenharmony_ci		buf = TPM_ACCESS_ACTIVE_LOCALITY;
3408c2ecf20Sopenharmony_ci		iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int request_locality(struct tpm_chip *chip, int loc)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	unsigned long stop;
3478c2ecf20Sopenharmony_ci	u8 buf = TPM_ACCESS_REQUEST_USE;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (check_locality(chip, loc))
3508c2ecf20Sopenharmony_ci		return loc;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* wait for burstcount */
3558c2ecf20Sopenharmony_ci	stop = jiffies + chip->timeout_a;
3568c2ecf20Sopenharmony_ci	do {
3578c2ecf20Sopenharmony_ci		if (check_locality(chip, loc))
3588c2ecf20Sopenharmony_ci			return loc;
3598c2ecf20Sopenharmony_ci		usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI);
3608c2ecf20Sopenharmony_ci	} while (time_before(jiffies, stop));
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return -ETIME;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic u8 tpm_tis_i2c_status(struct tpm_chip *chip)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	/* NOTE: since I2C read may fail, return 0 in this case --> time-out */
3688c2ecf20Sopenharmony_ci	u8 buf = 0xFF;
3698c2ecf20Sopenharmony_ci	u8 i = 0;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	do {
3728c2ecf20Sopenharmony_ci		if (iic_tpm_read(TPM_STS(tpm_dev.locality), &buf, 1) < 0)
3738c2ecf20Sopenharmony_ci			return 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci		i++;
3768c2ecf20Sopenharmony_ci	/* if locallity is set STS should not be 0xFF */
3778c2ecf20Sopenharmony_ci	} while ((buf == 0xFF) && i < 10);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return buf;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void tpm_tis_i2c_ready(struct tpm_chip *chip)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	/* this causes the current command to be aborted */
3858c2ecf20Sopenharmony_ci	u8 buf = TPM_STS_COMMAND_READY;
3868c2ecf20Sopenharmony_ci	iic_tpm_write_long(TPM_STS(tpm_dev.locality), &buf, 1);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic ssize_t get_burstcount(struct tpm_chip *chip)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	unsigned long stop;
3928c2ecf20Sopenharmony_ci	ssize_t burstcnt;
3938c2ecf20Sopenharmony_ci	u8 buf[3];
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	/* wait for burstcount */
3968c2ecf20Sopenharmony_ci	/* which timeout value, spec has 2 answers (c & d) */
3978c2ecf20Sopenharmony_ci	stop = jiffies + chip->timeout_d;
3988c2ecf20Sopenharmony_ci	do {
3998c2ecf20Sopenharmony_ci		/* Note: STS is little endian */
4008c2ecf20Sopenharmony_ci		if (iic_tpm_read(TPM_STS(tpm_dev.locality)+1, buf, 3) < 0)
4018c2ecf20Sopenharmony_ci			burstcnt = 0;
4028c2ecf20Sopenharmony_ci		else
4038c2ecf20Sopenharmony_ci			burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		if (burstcnt)
4068c2ecf20Sopenharmony_ci			return burstcnt;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI);
4098c2ecf20Sopenharmony_ci	} while (time_before(jiffies, stop));
4108c2ecf20Sopenharmony_ci	return -EBUSY;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
4148c2ecf20Sopenharmony_ci			 int *status)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	unsigned long stop;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* check current status */
4198c2ecf20Sopenharmony_ci	*status = tpm_tis_i2c_status(chip);
4208c2ecf20Sopenharmony_ci	if ((*status != 0xFF) && (*status & mask) == mask)
4218c2ecf20Sopenharmony_ci		return 0;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	stop = jiffies + timeout;
4248c2ecf20Sopenharmony_ci	do {
4258c2ecf20Sopenharmony_ci		/* since we just checked the status, give the TPM some time */
4268c2ecf20Sopenharmony_ci		usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI);
4278c2ecf20Sopenharmony_ci		*status = tpm_tis_i2c_status(chip);
4288c2ecf20Sopenharmony_ci		if ((*status & mask) == mask)
4298c2ecf20Sopenharmony_ci			return 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	} while (time_before(jiffies, stop));
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return -ETIME;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	size_t size = 0;
4398c2ecf20Sopenharmony_ci	ssize_t burstcnt;
4408c2ecf20Sopenharmony_ci	u8 retries = 0;
4418c2ecf20Sopenharmony_ci	int rc;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	while (size < count) {
4448c2ecf20Sopenharmony_ci		burstcnt = get_burstcount(chip);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		/* burstcnt < 0 = TPM is busy */
4478c2ecf20Sopenharmony_ci		if (burstcnt < 0)
4488c2ecf20Sopenharmony_ci			return burstcnt;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		/* limit received data to max. left */
4518c2ecf20Sopenharmony_ci		if (burstcnt > (count - size))
4528c2ecf20Sopenharmony_ci			burstcnt = count - size;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		rc = iic_tpm_read(TPM_DATA_FIFO(tpm_dev.locality),
4558c2ecf20Sopenharmony_ci				  &(buf[size]), burstcnt);
4568c2ecf20Sopenharmony_ci		if (rc == 0)
4578c2ecf20Sopenharmony_ci			size += burstcnt;
4588c2ecf20Sopenharmony_ci		else if (rc < 0)
4598c2ecf20Sopenharmony_ci			retries++;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		/* avoid endless loop in case of broken HW */
4628c2ecf20Sopenharmony_ci		if (retries > MAX_COUNT_LONG)
4638c2ecf20Sopenharmony_ci			return -EIO;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci	return size;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	int size = 0;
4718c2ecf20Sopenharmony_ci	int status;
4728c2ecf20Sopenharmony_ci	u32 expected;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (count < TPM_HEADER_SIZE) {
4758c2ecf20Sopenharmony_ci		size = -EIO;
4768c2ecf20Sopenharmony_ci		goto out;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	/* read first 10 bytes, including tag, paramsize, and result */
4808c2ecf20Sopenharmony_ci	size = recv_data(chip, buf, TPM_HEADER_SIZE);
4818c2ecf20Sopenharmony_ci	if (size < TPM_HEADER_SIZE) {
4828c2ecf20Sopenharmony_ci		dev_err(&chip->dev, "Unable to read header\n");
4838c2ecf20Sopenharmony_ci		goto out;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	expected = be32_to_cpu(*(__be32 *)(buf + 2));
4878c2ecf20Sopenharmony_ci	if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) {
4888c2ecf20Sopenharmony_ci		size = -EIO;
4898c2ecf20Sopenharmony_ci		goto out;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
4938c2ecf20Sopenharmony_ci			  expected - TPM_HEADER_SIZE);
4948c2ecf20Sopenharmony_ci	if (size < expected) {
4958c2ecf20Sopenharmony_ci		dev_err(&chip->dev, "Unable to read remainder of result\n");
4968c2ecf20Sopenharmony_ci		size = -ETIME;
4978c2ecf20Sopenharmony_ci		goto out;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c, &status);
5018c2ecf20Sopenharmony_ci	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
5028c2ecf20Sopenharmony_ci		dev_err(&chip->dev, "Error left over data\n");
5038c2ecf20Sopenharmony_ci		size = -EIO;
5048c2ecf20Sopenharmony_ci		goto out;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ciout:
5088c2ecf20Sopenharmony_ci	tpm_tis_i2c_ready(chip);
5098c2ecf20Sopenharmony_ci	/* The TPM needs some time to clean up here,
5108c2ecf20Sopenharmony_ci	 * so we sleep rather than keeping the bus busy
5118c2ecf20Sopenharmony_ci	 */
5128c2ecf20Sopenharmony_ci	usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI);
5138c2ecf20Sopenharmony_ci	release_locality(chip, tpm_dev.locality, 0);
5148c2ecf20Sopenharmony_ci	return size;
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	int rc, status;
5208c2ecf20Sopenharmony_ci	ssize_t burstcnt;
5218c2ecf20Sopenharmony_ci	size_t count = 0;
5228c2ecf20Sopenharmony_ci	u8 retries = 0;
5238c2ecf20Sopenharmony_ci	u8 sts = TPM_STS_GO;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (len > TPM_I2C_INFINEON_BUFSIZE)
5268c2ecf20Sopenharmony_ci		return -E2BIG;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (request_locality(chip, 0) < 0)
5298c2ecf20Sopenharmony_ci		return -EBUSY;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	status = tpm_tis_i2c_status(chip);
5328c2ecf20Sopenharmony_ci	if ((status & TPM_STS_COMMAND_READY) == 0) {
5338c2ecf20Sopenharmony_ci		tpm_tis_i2c_ready(chip);
5348c2ecf20Sopenharmony_ci		if (wait_for_stat
5358c2ecf20Sopenharmony_ci		    (chip, TPM_STS_COMMAND_READY,
5368c2ecf20Sopenharmony_ci		     chip->timeout_b, &status) < 0) {
5378c2ecf20Sopenharmony_ci			rc = -ETIME;
5388c2ecf20Sopenharmony_ci			goto out_err;
5398c2ecf20Sopenharmony_ci		}
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	while (count < len - 1) {
5438c2ecf20Sopenharmony_ci		burstcnt = get_burstcount(chip);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci		/* burstcnt < 0 = TPM is busy */
5468c2ecf20Sopenharmony_ci		if (burstcnt < 0)
5478c2ecf20Sopenharmony_ci			return burstcnt;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		if (burstcnt > (len - 1 - count))
5508c2ecf20Sopenharmony_ci			burstcnt = len - 1 - count;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		rc = iic_tpm_write(TPM_DATA_FIFO(tpm_dev.locality),
5538c2ecf20Sopenharmony_ci				   &(buf[count]), burstcnt);
5548c2ecf20Sopenharmony_ci		if (rc == 0)
5558c2ecf20Sopenharmony_ci			count += burstcnt;
5568c2ecf20Sopenharmony_ci		else if (rc < 0)
5578c2ecf20Sopenharmony_ci			retries++;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci		/* avoid endless loop in case of broken HW */
5608c2ecf20Sopenharmony_ci		if (retries > MAX_COUNT_LONG) {
5618c2ecf20Sopenharmony_ci			rc = -EIO;
5628c2ecf20Sopenharmony_ci			goto out_err;
5638c2ecf20Sopenharmony_ci		}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci		wait_for_stat(chip, TPM_STS_VALID,
5668c2ecf20Sopenharmony_ci			      chip->timeout_c, &status);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		if ((status & TPM_STS_DATA_EXPECT) == 0) {
5698c2ecf20Sopenharmony_ci			rc = -EIO;
5708c2ecf20Sopenharmony_ci			goto out_err;
5718c2ecf20Sopenharmony_ci		}
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	/* write last byte */
5758c2ecf20Sopenharmony_ci	iic_tpm_write(TPM_DATA_FIFO(tpm_dev.locality), &(buf[count]), 1);
5768c2ecf20Sopenharmony_ci	wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c, &status);
5778c2ecf20Sopenharmony_ci	if ((status & TPM_STS_DATA_EXPECT) != 0) {
5788c2ecf20Sopenharmony_ci		rc = -EIO;
5798c2ecf20Sopenharmony_ci		goto out_err;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* go and do it */
5838c2ecf20Sopenharmony_ci	iic_tpm_write(TPM_STS(tpm_dev.locality), &sts, 1);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	return 0;
5868c2ecf20Sopenharmony_ciout_err:
5878c2ecf20Sopenharmony_ci	tpm_tis_i2c_ready(chip);
5888c2ecf20Sopenharmony_ci	/* The TPM needs some time to clean up here,
5898c2ecf20Sopenharmony_ci	 * so we sleep rather than keeping the bus busy
5908c2ecf20Sopenharmony_ci	 */
5918c2ecf20Sopenharmony_ci	usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI);
5928c2ecf20Sopenharmony_ci	release_locality(chip, tpm_dev.locality, 0);
5938c2ecf20Sopenharmony_ci	return rc;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cistatic bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	return (status == TPM_STS_COMMAND_READY);
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic const struct tpm_class_ops tpm_tis_i2c = {
6028c2ecf20Sopenharmony_ci	.flags = TPM_OPS_AUTO_STARTUP,
6038c2ecf20Sopenharmony_ci	.status = tpm_tis_i2c_status,
6048c2ecf20Sopenharmony_ci	.recv = tpm_tis_i2c_recv,
6058c2ecf20Sopenharmony_ci	.send = tpm_tis_i2c_send,
6068c2ecf20Sopenharmony_ci	.cancel = tpm_tis_i2c_ready,
6078c2ecf20Sopenharmony_ci	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
6088c2ecf20Sopenharmony_ci	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
6098c2ecf20Sopenharmony_ci	.req_canceled = tpm_tis_i2c_req_canceled,
6108c2ecf20Sopenharmony_ci};
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int tpm_tis_i2c_init(struct device *dev)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	u32 vendor;
6158c2ecf20Sopenharmony_ci	int rc = 0;
6168c2ecf20Sopenharmony_ci	struct tpm_chip *chip;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
6198c2ecf20Sopenharmony_ci	if (IS_ERR(chip))
6208c2ecf20Sopenharmony_ci		return PTR_ERR(chip);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* Default timeouts */
6238c2ecf20Sopenharmony_ci	chip->timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
6248c2ecf20Sopenharmony_ci	chip->timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
6258c2ecf20Sopenharmony_ci	chip->timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
6268c2ecf20Sopenharmony_ci	chip->timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (request_locality(chip, 0) != 0) {
6298c2ecf20Sopenharmony_ci		dev_err(dev, "could not request locality\n");
6308c2ecf20Sopenharmony_ci		rc = -ENODEV;
6318c2ecf20Sopenharmony_ci		goto out_err;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/* read four bytes from DID_VID register */
6358c2ecf20Sopenharmony_ci	if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) {
6368c2ecf20Sopenharmony_ci		dev_err(dev, "could not read vendor id\n");
6378c2ecf20Sopenharmony_ci		rc = -EIO;
6388c2ecf20Sopenharmony_ci		goto out_release;
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (vendor == TPM_TIS_I2C_DID_VID_9645) {
6428c2ecf20Sopenharmony_ci		tpm_dev.chip_type = SLB9645;
6438c2ecf20Sopenharmony_ci	} else if (vendor == TPM_TIS_I2C_DID_VID_9635) {
6448c2ecf20Sopenharmony_ci		tpm_dev.chip_type = SLB9635;
6458c2ecf20Sopenharmony_ci	} else {
6468c2ecf20Sopenharmony_ci		dev_err(dev, "vendor id did not match! ID was %08x\n", vendor);
6478c2ecf20Sopenharmony_ci		rc = -ENODEV;
6488c2ecf20Sopenharmony_ci		goto out_release;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	dev_info(dev, "1.2 TPM (device-id 0x%X)\n", vendor >> 16);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	tpm_dev.chip = chip;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	return tpm_chip_register(chip);
6568c2ecf20Sopenharmony_ciout_release:
6578c2ecf20Sopenharmony_ci	release_locality(chip, tpm_dev.locality, 1);
6588c2ecf20Sopenharmony_ci	tpm_dev.client = NULL;
6598c2ecf20Sopenharmony_ciout_err:
6608c2ecf20Sopenharmony_ci	return rc;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic const struct i2c_device_id tpm_tis_i2c_table[] = {
6648c2ecf20Sopenharmony_ci	{"tpm_i2c_infineon"},
6658c2ecf20Sopenharmony_ci	{"slb9635tt"},
6668c2ecf20Sopenharmony_ci	{"slb9645tt"},
6678c2ecf20Sopenharmony_ci	{},
6688c2ecf20Sopenharmony_ci};
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
6738c2ecf20Sopenharmony_cistatic const struct of_device_id tpm_tis_i2c_of_match[] = {
6748c2ecf20Sopenharmony_ci	{.compatible = "infineon,tpm_i2c_infineon"},
6758c2ecf20Sopenharmony_ci	{.compatible = "infineon,slb9635tt"},
6768c2ecf20Sopenharmony_ci	{.compatible = "infineon,slb9645tt"},
6778c2ecf20Sopenharmony_ci	{},
6788c2ecf20Sopenharmony_ci};
6798c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match);
6808c2ecf20Sopenharmony_ci#endif
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int tpm_tis_i2c_probe(struct i2c_client *client,
6858c2ecf20Sopenharmony_ci			     const struct i2c_device_id *id)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	int rc;
6888c2ecf20Sopenharmony_ci	struct device *dev = &(client->dev);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (tpm_dev.client != NULL) {
6918c2ecf20Sopenharmony_ci		dev_err(dev, "This driver only supports one client at a time\n");
6928c2ecf20Sopenharmony_ci		return -EBUSY;	/* We only support one client */
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
6968c2ecf20Sopenharmony_ci		dev_err(dev, "no algorithms associated to the i2c bus\n");
6978c2ecf20Sopenharmony_ci		return -ENODEV;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	tpm_dev.client = client;
7018c2ecf20Sopenharmony_ci	rc = tpm_tis_i2c_init(&client->dev);
7028c2ecf20Sopenharmony_ci	if (rc != 0) {
7038c2ecf20Sopenharmony_ci		tpm_dev.client = NULL;
7048c2ecf20Sopenharmony_ci		rc = -ENODEV;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci	return rc;
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic int tpm_tis_i2c_remove(struct i2c_client *client)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct tpm_chip *chip = tpm_dev.chip;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	tpm_chip_unregister(chip);
7148c2ecf20Sopenharmony_ci	release_locality(chip, tpm_dev.locality, 1);
7158c2ecf20Sopenharmony_ci	tpm_dev.client = NULL;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return 0;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic struct i2c_driver tpm_tis_i2c_driver = {
7218c2ecf20Sopenharmony_ci	.id_table = tpm_tis_i2c_table,
7228c2ecf20Sopenharmony_ci	.probe = tpm_tis_i2c_probe,
7238c2ecf20Sopenharmony_ci	.remove = tpm_tis_i2c_remove,
7248c2ecf20Sopenharmony_ci	.driver = {
7258c2ecf20Sopenharmony_ci		   .name = "tpm_i2c_infineon",
7268c2ecf20Sopenharmony_ci		   .pm = &tpm_tis_i2c_ops,
7278c2ecf20Sopenharmony_ci		   .of_match_table = of_match_ptr(tpm_tis_i2c_of_match),
7288c2ecf20Sopenharmony_ci		   },
7298c2ecf20Sopenharmony_ci};
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cimodule_i2c_driver(tpm_tis_i2c_driver);
7328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>");
7338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TPM TIS I2C Infineon Driver");
7348c2ecf20Sopenharmony_ciMODULE_VERSION("2.2.0");
7358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
736