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