2012-08-07 13:42:32 +04:00
/*
2013-03-04 18:41:46 +04:00
* Copyright ( C ) 2012 , 2013 Infineon Technologies
2012-08-07 13:42:32 +04:00
*
* Authors :
* Peter Huewe < peter . huewe @ infineon . com >
*
* Device driver for TCG / TCPA TPM ( trusted platform module ) .
* Specifications at www . trustedcomputinggroup . org
*
* This device driver implements the TPM interface as defined in
* the TCG TPM Interface Spec version 1.2 , revision 1.0 and the
* Infineon I2C Protocol Stack Specification v0 .20 .
*
* It is based on the original tpm_tis device driver from Leendert van
* Dorn and Kyleen Hall .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation , version 2 of the
* License .
*
*
*/
# include <linux/i2c.h>
# include <linux/module.h>
# include <linux/wait.h>
# include "tpm.h"
/* max. buffer size supported by our TPM */
# define TPM_BUFSIZE 1260
/* max. number of iterations after I2C NAK */
# define MAX_COUNT 3
# define SLEEP_DURATION_LOW 55
# define SLEEP_DURATION_HI 65
/* max. number of iterations after I2C NAK for 'long' commands
* we need this especially for sending TPM_READY , since the cleanup after the
* transtion to the ready state may take some time , but it is unpredictable
* how long it will take .
*/
# define MAX_COUNT_LONG 50
# define SLEEP_DURATION_LONG_LOW 200
# define SLEEP_DURATION_LONG_HI 220
/* After sending TPM_READY to 'reset' the TPM we have to sleep even longer */
# define SLEEP_DURATION_RESET_LOW 2400
# define SLEEP_DURATION_RESET_HI 2600
/* we want to use usleep_range instead of msleep for the 5ms TPM_TIMEOUT */
# define TPM_TIMEOUT_US_LOW (TPM_TIMEOUT * 1000)
# define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000)
/* expected value for DIDVID register */
2013-03-04 18:41:46 +04:00
# define TPM_TIS_I2C_DID_VID_9635 0xd1150b00L
# define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
enum i2c_chip_type {
SLB9635 ,
SLB9645 ,
UNKNOWN ,
} ;
2012-08-07 13:42:32 +04:00
/* Structure to store I2C TPM specific stuff */
struct tpm_inf_dev {
struct i2c_client * client ;
2016-03-31 23:56:58 +03:00
int locality ;
2012-08-07 13:42:32 +04:00
u8 buf [ TPM_BUFSIZE + sizeof ( u8 ) ] ; /* max. buffer size + addr */
struct tpm_chip * chip ;
2013-03-04 18:41:46 +04:00
enum i2c_chip_type chip_type ;
2017-05-22 12:20:11 +03:00
unsigned int adapterlimit ;
2012-08-07 13:42:32 +04:00
} ;
static struct tpm_inf_dev tpm_dev ;
/*
* iic_tpm_read ( ) - read from TPM register
* @ addr : register address to read from
* @ buffer : provided by caller
* @ len : number of bytes to read
*
* Read len bytes from TPM register and put them into
* buffer ( little - endian format , i . e . first byte is put into buffer [ 0 ] ) .
*
* NOTE : TPM is big - endian for multi - byte values . Multi - byte
* values have to be swapped .
*
* NOTE : We can ' t unfortunately use the combined read / write functions
* provided by the i2c core as the TPM currently does not support the
* repeated start condition and due to it ' s special requirements .
* The i2c_smbus * functions do not work for this chip .
*
* Return - EIO on error , 0 on success .
*/
static int iic_tpm_read ( u8 addr , u8 * buffer , size_t len )
{
2013-02-28 14:06:11 +04:00
struct i2c_msg msg1 = {
. addr = tpm_dev . client - > addr ,
. len = 1 ,
. buf = & addr
} ;
struct i2c_msg msg2 = {
. addr = tpm_dev . client - > addr ,
. flags = I2C_M_RD ,
. len = len ,
. buf = buffer
} ;
2013-03-04 18:41:46 +04:00
struct i2c_msg msgs [ ] = { msg1 , msg2 } ;
2012-08-07 13:42:32 +04:00
2013-03-04 18:41:46 +04:00
int rc = 0 ;
2012-08-07 13:42:32 +04:00
int count ;
2017-05-22 12:20:11 +03:00
unsigned int msglen = len ;
2012-08-07 13:42:32 +04:00
/* Lock the adapter for the duration of the whole sequence. */
if ( ! tpm_dev . client - > adapter - > algo - > master_xfer )
return - EOPNOTSUPP ;
i2c_lock_adapter ( tpm_dev . client - > adapter ) ;
2013-03-04 18:41:46 +04:00
if ( tpm_dev . chip_type = = SLB9645 ) {
/* use a combined read for newer chips
* unfortunately the smbus functions are not suitable due to
* the 32 byte limit of the smbus .
* retries should usually not be needed , but are kept just to
* be on the safe side .
*/
for ( count = 0 ; count < MAX_COUNT ; count + + ) {
rc = __i2c_transfer ( tpm_dev . client - > adapter , msgs , 2 ) ;
if ( rc > 0 )
break ; /* break here to skip sleep */
usleep_range ( SLEEP_DURATION_LOW , SLEEP_DURATION_HI ) ;
}
} else {
2017-05-22 12:20:11 +03:00
/* Expect to send one command message and one data message, but
* support looping over each or both if necessary .
2013-03-04 18:41:46 +04:00
*/
2017-05-22 12:20:11 +03:00
while ( len > 0 ) {
/* slb9635 protocol should work in all cases */
for ( count = 0 ; count < MAX_COUNT ; count + + ) {
rc = __i2c_transfer ( tpm_dev . client - > adapter ,
& msg1 , 1 ) ;
if ( rc > 0 )
break ; /* break here to skip sleep */
usleep_range ( SLEEP_DURATION_LOW ,
SLEEP_DURATION_HI ) ;
}
if ( rc < = 0 )
goto out ;
/* After the TPM has successfully received the register
* address it needs some time , thus we ' re sleeping here
* again , before retrieving the data
*/
for ( count = 0 ; count < MAX_COUNT ; count + + ) {
if ( tpm_dev . adapterlimit ) {
msglen = min_t ( unsigned int ,
tpm_dev . adapterlimit ,
len ) ;
msg2 . len = msglen ;
}
usleep_range ( SLEEP_DURATION_LOW ,
SLEEP_DURATION_HI ) ;
rc = __i2c_transfer ( tpm_dev . client - > adapter ,
& msg2 , 1 ) ;
if ( rc > 0 ) {
/* Since len is unsigned, make doubly
* sure we do not underflow it .
*/
if ( msglen > len )
len = 0 ;
else
len - = msglen ;
msg2 . buf + = msglen ;
break ;
}
/* If the I2C adapter rejected the request (e.g
* when the quirk read_max_len < len ) fall back
* to a sane minimum value and try again .
*/
if ( rc = = - EOPNOTSUPP )
tpm_dev . adapterlimit =
I2C_SMBUS_BLOCK_MAX ;
}
if ( rc < = 0 )
goto out ;
2013-03-04 18:41:46 +04:00
}
2012-08-07 13:42:32 +04:00
}
out :
i2c_unlock_adapter ( tpm_dev . client - > adapter ) ;
2013-03-04 18:41:46 +04:00
/* take care of 'guard time' */
usleep_range ( SLEEP_DURATION_LOW , SLEEP_DURATION_HI ) ;
2013-03-05 01:17:15 +04:00
/* __i2c_transfer returns the number of successfully transferred
* messages .
* So rc should be greater than 0 here otherwise we have an error .
*/
2012-08-07 13:42:32 +04:00
if ( rc < = 0 )
return - EIO ;
return 0 ;
}
static int iic_tpm_write_generic ( u8 addr , u8 * buffer , size_t len ,
unsigned int sleep_low ,
unsigned int sleep_hi , u8 max_count )
{
int rc = - EIO ;
int count ;
2013-02-28 14:06:11 +04:00
struct i2c_msg msg1 = {
. addr = tpm_dev . client - > addr ,
. len = len + 1 ,
. buf = tpm_dev . buf
} ;
2012-08-07 13:42:32 +04:00
if ( len > TPM_BUFSIZE )
return - EINVAL ;
if ( ! tpm_dev . client - > adapter - > algo - > master_xfer )
return - EOPNOTSUPP ;
i2c_lock_adapter ( tpm_dev . client - > adapter ) ;
/* prepend the 'register address' to the buffer */
tpm_dev . buf [ 0 ] = addr ;
memcpy ( & ( tpm_dev . buf [ 1 ] ) , buffer , len ) ;
/*
* NOTE : We have to use these special mechanisms here and unfortunately
* cannot rely on the standard behavior of i2c_transfer .
2013-03-04 18:41:46 +04:00
* Even for newer chips the smbus functions are not
* suitable due to the 32 byte limit of the smbus .
2012-08-07 13:42:32 +04:00
*/
for ( count = 0 ; count < max_count ; count + + ) {
rc = __i2c_transfer ( tpm_dev . client - > adapter , & msg1 , 1 ) ;
if ( rc > 0 )
break ;
usleep_range ( sleep_low , sleep_hi ) ;
}
i2c_unlock_adapter ( tpm_dev . client - > adapter ) ;
2013-03-04 18:41:46 +04:00
/* take care of 'guard time' */
usleep_range ( SLEEP_DURATION_LOW , SLEEP_DURATION_HI ) ;
2013-03-05 01:17:15 +04:00
/* __i2c_transfer returns the number of successfully transferred
* messages .
* So rc should be greater than 0 here otherwise we have an error .
*/
2012-08-07 13:42:32 +04:00
if ( rc < = 0 )
return - EIO ;
return 0 ;
}
/*
* iic_tpm_write ( ) - write to TPM register
* @ addr : register address to write to
* @ buffer : containing data to be written
* @ len : number of bytes to write
*
* Write len bytes from provided buffer to TPM register ( little
* endian format , i . e . buffer [ 0 ] is written as first byte ) .
*
* NOTE : TPM is big - endian for multi - byte values . Multi - byte
* values have to be swapped .
*
* NOTE : use this function instead of the iic_tpm_write_generic function .
*
* Return - EIO on error , 0 on success
*/
static int iic_tpm_write ( u8 addr , u8 * buffer , size_t len )
{
return iic_tpm_write_generic ( addr , buffer , len , SLEEP_DURATION_LOW ,
SLEEP_DURATION_HI , MAX_COUNT ) ;
}
/*
* This function is needed especially for the cleanup situation after
* sending TPM_READY
* */
static int iic_tpm_write_long ( u8 addr , u8 * buffer , size_t len )
{
return iic_tpm_write_generic ( addr , buffer , len , SLEEP_DURATION_LONG_LOW ,
SLEEP_DURATION_LONG_HI , MAX_COUNT_LONG ) ;
}
enum tis_access {
TPM_ACCESS_VALID = 0x80 ,
TPM_ACCESS_ACTIVE_LOCALITY = 0x20 ,
TPM_ACCESS_REQUEST_PENDING = 0x04 ,
TPM_ACCESS_REQUEST_USE = 0x02 ,
} ;
enum tis_status {
TPM_STS_VALID = 0x80 ,
TPM_STS_COMMAND_READY = 0x40 ,
TPM_STS_GO = 0x20 ,
TPM_STS_DATA_AVAIL = 0x10 ,
TPM_STS_DATA_EXPECT = 0x08 ,
} ;
enum tis_defaults {
TIS_SHORT_TIMEOUT = 750 , /* ms */
TIS_LONG_TIMEOUT = 2000 , /* 2 sec */
} ;
# define TPM_ACCESS(l) (0x0000 | ((l) << 4))
# define TPM_STS(l) (0x0001 | ((l) << 4))
# define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
# define TPM_DID_VID(l) (0x0006 | ((l) << 4))
2017-03-18 11:59:57 +03:00
static bool check_locality ( struct tpm_chip * chip , int loc )
2012-08-07 13:42:32 +04:00
{
u8 buf ;
int rc ;
rc = iic_tpm_read ( TPM_ACCESS ( loc ) , & buf , 1 ) ;
if ( rc < 0 )
2017-03-18 11:59:57 +03:00
return false ;
2012-08-07 13:42:32 +04:00
if ( ( buf & ( TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID ) ) = =
( TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID ) ) {
2016-03-31 23:56:58 +03:00
tpm_dev . locality = loc ;
2017-03-18 11:59:57 +03:00
return true ;
2012-08-07 13:42:32 +04:00
}
2017-03-18 11:59:57 +03:00
return false ;
2012-08-07 13:42:32 +04:00
}
/* implementation similar to tpm_tis */
static void release_locality ( struct tpm_chip * chip , int loc , int force )
{
u8 buf ;
if ( iic_tpm_read ( TPM_ACCESS ( loc ) , & buf , 1 ) < 0 )
return ;
if ( force | | ( buf & ( TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID ) ) = =
( TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID ) ) {
buf = TPM_ACCESS_ACTIVE_LOCALITY ;
iic_tpm_write ( TPM_ACCESS ( loc ) , & buf , 1 ) ;
}
}
static int request_locality ( struct tpm_chip * chip , int loc )
{
unsigned long stop ;
u8 buf = TPM_ACCESS_REQUEST_USE ;
2017-03-18 11:59:57 +03:00
if ( check_locality ( chip , loc ) )
2012-08-07 13:42:32 +04:00
return loc ;
iic_tpm_write ( TPM_ACCESS ( loc ) , & buf , 1 ) ;
/* wait for burstcount */
2016-03-31 23:56:59 +03:00
stop = jiffies + chip - > timeout_a ;
2012-08-07 13:42:32 +04:00
do {
2017-03-18 11:59:57 +03:00
if ( check_locality ( chip , loc ) )
2012-08-07 13:42:32 +04:00
return loc ;
usleep_range ( TPM_TIMEOUT_US_LOW , TPM_TIMEOUT_US_HI ) ;
} while ( time_before ( jiffies , stop ) ) ;
return - ETIME ;
}
static u8 tpm_tis_i2c_status ( struct tpm_chip * chip )
{
/* NOTE: since I2C read may fail, return 0 in this case --> time-out */
2013-03-04 18:41:46 +04:00
u8 buf = 0xFF ;
u8 i = 0 ;
do {
2016-03-31 23:56:58 +03:00
if ( iic_tpm_read ( TPM_STS ( tpm_dev . locality ) , & buf , 1 ) < 0 )
2013-03-04 18:41:46 +04:00
return 0 ;
i + + ;
/* if locallity is set STS should not be 0xFF */
} while ( ( buf = = 0xFF ) & & i < 10 ) ;
return buf ;
2012-08-07 13:42:32 +04:00
}
static void tpm_tis_i2c_ready ( struct tpm_chip * chip )
{
/* this causes the current command to be aborted */
u8 buf = TPM_STS_COMMAND_READY ;
2016-03-31 23:56:58 +03:00
iic_tpm_write_long ( TPM_STS ( tpm_dev . locality ) , & buf , 1 ) ;
2012-08-07 13:42:32 +04:00
}
static ssize_t get_burstcount ( struct tpm_chip * chip )
{
unsigned long stop ;
ssize_t burstcnt ;
u8 buf [ 3 ] ;
/* wait for burstcount */
/* which timeout value, spec has 2 answers (c & d) */
2016-03-31 23:56:59 +03:00
stop = jiffies + chip - > timeout_d ;
2012-08-07 13:42:32 +04:00
do {
/* Note: STS is little endian */
2016-03-31 23:56:58 +03:00
if ( iic_tpm_read ( TPM_STS ( tpm_dev . locality ) + 1 , buf , 3 ) < 0 )
2012-08-07 13:42:32 +04:00
burstcnt = 0 ;
else
burstcnt = ( buf [ 2 ] < < 16 ) + ( buf [ 1 ] < < 8 ) + buf [ 0 ] ;
if ( burstcnt )
return burstcnt ;
usleep_range ( TPM_TIMEOUT_US_LOW , TPM_TIMEOUT_US_HI ) ;
} while ( time_before ( jiffies , stop ) ) ;
return - EBUSY ;
}
static int wait_for_stat ( struct tpm_chip * chip , u8 mask , unsigned long timeout ,
int * status )
{
unsigned long stop ;
/* check current status */
* status = tpm_tis_i2c_status ( chip ) ;
2013-03-04 18:41:46 +04:00
if ( ( * status ! = 0xFF ) & & ( * status & mask ) = = mask )
2012-08-07 13:42:32 +04:00
return 0 ;
stop = jiffies + timeout ;
do {
/* since we just checked the status, give the TPM some time */
usleep_range ( TPM_TIMEOUT_US_LOW , TPM_TIMEOUT_US_HI ) ;
* status = tpm_tis_i2c_status ( chip ) ;
if ( ( * status & mask ) = = mask )
return 0 ;
} while ( time_before ( jiffies , stop ) ) ;
return - ETIME ;
}
static int recv_data ( struct tpm_chip * chip , u8 * buf , size_t count )
{
size_t size = 0 ;
ssize_t burstcnt ;
u8 retries = 0 ;
int rc ;
while ( size < count ) {
burstcnt = get_burstcount ( chip ) ;
/* burstcnt < 0 = TPM is busy */
if ( burstcnt < 0 )
return burstcnt ;
/* limit received data to max. left */
if ( burstcnt > ( count - size ) )
burstcnt = count - size ;
2016-03-31 23:56:58 +03:00
rc = iic_tpm_read ( TPM_DATA_FIFO ( tpm_dev . locality ) ,
2012-08-07 13:42:32 +04:00
& ( buf [ size ] ) , burstcnt ) ;
if ( rc = = 0 )
size + = burstcnt ;
else if ( rc < 0 )
retries + + ;
/* avoid endless loop in case of broken HW */
if ( retries > MAX_COUNT_LONG )
return - EIO ;
}
return size ;
}
static int tpm_tis_i2c_recv ( struct tpm_chip * chip , u8 * buf , size_t count )
{
int size = 0 ;
2018-02-08 23:30:01 +03:00
int status ;
u32 expected ;
2012-08-07 13:42:32 +04:00
if ( count < TPM_HEADER_SIZE ) {
size = - EIO ;
goto out ;
}
/* read first 10 bytes, including tag, paramsize, and result */
size = recv_data ( chip , buf , TPM_HEADER_SIZE ) ;
if ( size < TPM_HEADER_SIZE ) {
2016-02-29 20:29:47 +03:00
dev_err ( & chip - > dev , " Unable to read header \n " ) ;
2012-08-07 13:42:32 +04:00
goto out ;
}
expected = be32_to_cpu ( * ( __be32 * ) ( buf + 2 ) ) ;
2018-02-08 23:30:01 +03:00
if ( ( ( size_t ) expected > count ) | | ( expected < TPM_HEADER_SIZE ) ) {
2012-08-07 13:42:32 +04:00
size = - EIO ;
goto out ;
}
size + = recv_data ( chip , & buf [ TPM_HEADER_SIZE ] ,
expected - TPM_HEADER_SIZE ) ;
if ( size < expected ) {
2016-02-29 20:29:47 +03:00
dev_err ( & chip - > dev , " Unable to read remainder of result \n " ) ;
2012-08-07 13:42:32 +04:00
size = - ETIME ;
goto out ;
}
2016-03-31 23:56:59 +03:00
wait_for_stat ( chip , TPM_STS_VALID , chip - > timeout_c , & status ) ;
2012-08-07 13:42:32 +04:00
if ( status & TPM_STS_DATA_AVAIL ) { /* retry? */
2016-02-29 20:29:47 +03:00
dev_err ( & chip - > dev , " Error left over data \n " ) ;
2012-08-07 13:42:32 +04:00
size = - EIO ;
goto out ;
}
out :
tpm_tis_i2c_ready ( chip ) ;
/* The TPM needs some time to clean up here,
* so we sleep rather than keeping the bus busy
*/
usleep_range ( SLEEP_DURATION_RESET_LOW , SLEEP_DURATION_RESET_HI ) ;
2016-03-31 23:56:58 +03:00
release_locality ( chip , tpm_dev . locality , 0 ) ;
2012-08-07 13:42:32 +04:00
return size ;
}
static int tpm_tis_i2c_send ( struct tpm_chip * chip , u8 * buf , size_t len )
{
int rc , status ;
ssize_t burstcnt ;
size_t count = 0 ;
u8 retries = 0 ;
u8 sts = TPM_STS_GO ;
if ( len > TPM_BUFSIZE )
return - E2BIG ; /* command is too long for our tpm, sorry */
if ( request_locality ( chip , 0 ) < 0 )
return - EBUSY ;
status = tpm_tis_i2c_status ( chip ) ;
if ( ( status & TPM_STS_COMMAND_READY ) = = 0 ) {
tpm_tis_i2c_ready ( chip ) ;
if ( wait_for_stat
( chip , TPM_STS_COMMAND_READY ,
2016-03-31 23:56:59 +03:00
chip - > timeout_b , & status ) < 0 ) {
2012-08-07 13:42:32 +04:00
rc = - ETIME ;
goto out_err ;
}
}
while ( count < len - 1 ) {
burstcnt = get_burstcount ( chip ) ;
/* burstcnt < 0 = TPM is busy */
if ( burstcnt < 0 )
return burstcnt ;
if ( burstcnt > ( len - 1 - count ) )
burstcnt = len - 1 - count ;
2016-03-31 23:56:58 +03:00
rc = iic_tpm_write ( TPM_DATA_FIFO ( tpm_dev . locality ) ,
2012-08-07 13:42:32 +04:00
& ( buf [ count ] ) , burstcnt ) ;
if ( rc = = 0 )
count + = burstcnt ;
else if ( rc < 0 )
retries + + ;
/* avoid endless loop in case of broken HW */
if ( retries > MAX_COUNT_LONG ) {
rc = - EIO ;
goto out_err ;
}
wait_for_stat ( chip , TPM_STS_VALID ,
2016-03-31 23:56:59 +03:00
chip - > timeout_c , & status ) ;
2012-08-07 13:42:32 +04:00
if ( ( status & TPM_STS_DATA_EXPECT ) = = 0 ) {
rc = - EIO ;
goto out_err ;
}
}
/* write last byte */
2016-03-31 23:56:58 +03:00
iic_tpm_write ( TPM_DATA_FIFO ( tpm_dev . locality ) , & ( buf [ count ] ) , 1 ) ;
2016-03-31 23:56:59 +03:00
wait_for_stat ( chip , TPM_STS_VALID , chip - > timeout_c , & status ) ;
2012-08-07 13:42:32 +04:00
if ( ( status & TPM_STS_DATA_EXPECT ) ! = 0 ) {
rc = - EIO ;
goto out_err ;
}
/* go and do it */
2016-03-31 23:56:58 +03:00
iic_tpm_write ( TPM_STS ( tpm_dev . locality ) , & sts , 1 ) ;
2012-08-07 13:42:32 +04:00
return len ;
out_err :
tpm_tis_i2c_ready ( chip ) ;
/* The TPM needs some time to clean up here,
* so we sleep rather than keeping the bus busy
*/
usleep_range ( SLEEP_DURATION_RESET_LOW , SLEEP_DURATION_RESET_HI ) ;
2016-03-31 23:56:58 +03:00
release_locality ( chip , tpm_dev . locality , 0 ) ;
2012-08-07 13:42:32 +04:00
return rc ;
}
2013-01-22 23:52:35 +04:00
static bool tpm_tis_i2c_req_canceled ( struct tpm_chip * chip , u8 status )
{
return ( status = = TPM_STS_COMMAND_READY ) ;
}
2013-11-27 00:30:43 +04:00
static const struct tpm_class_ops tpm_tis_i2c = {
2016-07-12 20:41:49 +03:00
. flags = TPM_OPS_AUTO_STARTUP ,
2012-08-07 13:42:32 +04:00
. status = tpm_tis_i2c_status ,
. recv = tpm_tis_i2c_recv ,
. send = tpm_tis_i2c_send ,
. cancel = tpm_tis_i2c_ready ,
. req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID ,
. req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID ,
2013-01-22 23:52:35 +04:00
. req_canceled = tpm_tis_i2c_req_canceled ,
2012-08-07 13:42:32 +04:00
} ;
2012-11-19 22:22:42 +04:00
static int tpm_tis_i2c_init ( struct device * dev )
2012-08-07 13:42:32 +04:00
{
u32 vendor ;
int rc = 0 ;
struct tpm_chip * chip ;
2014-12-12 22:46:34 +03:00
chip = tpmm_chip_alloc ( dev , & tpm_tis_i2c ) ;
if ( IS_ERR ( chip ) )
return PTR_ERR ( chip ) ;
2012-08-07 13:42:32 +04:00
/* Default timeouts */
2016-03-31 23:56:59 +03:00
chip - > timeout_a = msecs_to_jiffies ( TIS_SHORT_TIMEOUT ) ;
chip - > timeout_b = msecs_to_jiffies ( TIS_LONG_TIMEOUT ) ;
chip - > timeout_c = msecs_to_jiffies ( TIS_SHORT_TIMEOUT ) ;
chip - > timeout_d = msecs_to_jiffies ( TIS_SHORT_TIMEOUT ) ;
2012-08-07 13:42:32 +04:00
if ( request_locality ( chip , 0 ) ! = 0 ) {
2013-03-04 18:41:46 +04:00
dev_err ( dev , " could not request locality \n " ) ;
2012-08-07 13:42:32 +04:00
rc = - ENODEV ;
2014-12-12 22:46:34 +03:00
goto out_err ;
2012-08-07 13:42:32 +04:00
}
/* read four bytes from DID_VID register */
if ( iic_tpm_read ( TPM_DID_VID ( 0 ) , ( u8 * ) & vendor , 4 ) < 0 ) {
2013-03-04 18:41:46 +04:00
dev_err ( dev , " could not read vendor id \n " ) ;
2012-08-07 13:42:32 +04:00
rc = - EIO ;
goto out_release ;
}
2013-03-04 18:41:46 +04:00
if ( vendor = = TPM_TIS_I2C_DID_VID_9645 ) {
tpm_dev . chip_type = SLB9645 ;
} else if ( vendor = = TPM_TIS_I2C_DID_VID_9635 ) {
tpm_dev . chip_type = SLB9635 ;
} else {
dev_err ( dev , " vendor id did not match! ID was %08x \n " , vendor ) ;
2012-08-07 13:42:32 +04:00
rc = - ENODEV ;
goto out_release ;
}
dev_info ( dev , " 1.2 TPM (device-id 0x%X) \n " , vendor > > 16 ) ;
tpm_dev . chip = chip ;
2014-12-12 22:46:34 +03:00
return tpm_chip_register ( chip ) ;
2012-08-07 13:42:32 +04:00
out_release :
2016-03-31 23:56:58 +03:00
release_locality ( chip , tpm_dev . locality , 1 ) ;
2012-08-07 13:42:32 +04:00
tpm_dev . client = NULL ;
out_err :
return rc ;
}
static const struct i2c_device_id tpm_tis_i2c_table [ ] = {
2017-12-22 20:47:41 +03:00
{ " tpm_i2c_infineon " } ,
{ " slb9635tt " } ,
{ " slb9645tt " } ,
2012-08-07 13:42:32 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , tpm_tis_i2c_table ) ;
2013-03-04 18:41:46 +04:00
# ifdef CONFIG_OF
static const struct of_device_id tpm_tis_i2c_of_match [ ] = {
2017-12-22 20:47:41 +03:00
{ . compatible = " infineon,tpm_i2c_infineon " } ,
{ . compatible = " infineon,slb9635tt " } ,
{ . compatible = " infineon,slb9645tt " } ,
2013-03-04 18:41:46 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , tpm_tis_i2c_of_match ) ;
# endif
2012-08-07 13:42:32 +04:00
static SIMPLE_DEV_PM_OPS ( tpm_tis_i2c_ops , tpm_pm_suspend , tpm_pm_resume ) ;
2012-11-19 22:22:42 +04:00
static int tpm_tis_i2c_probe ( struct i2c_client * client ,
2012-08-07 13:42:32 +04:00
const struct i2c_device_id * id )
{
int rc ;
2013-03-04 18:41:46 +04:00
struct device * dev = & ( client - > dev ) ;
if ( tpm_dev . client ! = NULL ) {
dev_err ( dev , " This driver only supports one client at a time \n " ) ;
2012-08-07 13:42:32 +04:00
return - EBUSY ; /* We only support one client */
2013-03-04 18:41:46 +04:00
}
2012-08-07 13:42:32 +04:00
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ) {
2013-03-04 18:41:46 +04:00
dev_err ( dev , " no algorithms associated to the i2c bus \n " ) ;
2012-08-07 13:42:32 +04:00
return - ENODEV ;
}
tpm_dev . client = client ;
rc = tpm_tis_i2c_init ( & client - > dev ) ;
if ( rc ! = 0 ) {
tpm_dev . client = NULL ;
rc = - ENODEV ;
}
return rc ;
}
2012-11-19 22:26:26 +04:00
static int tpm_tis_i2c_remove ( struct i2c_client * client )
2012-08-07 13:42:32 +04:00
{
struct tpm_chip * chip = tpm_dev . chip ;
2014-12-12 22:46:34 +03:00
tpm_chip_unregister ( chip ) ;
2016-03-31 23:56:58 +03:00
release_locality ( chip , tpm_dev . locality , 1 ) ;
2012-08-07 13:42:32 +04:00
tpm_dev . client = NULL ;
return 0 ;
}
static struct i2c_driver tpm_tis_i2c_driver = {
. id_table = tpm_tis_i2c_table ,
. probe = tpm_tis_i2c_probe ,
. remove = tpm_tis_i2c_remove ,
. driver = {
. name = " tpm_i2c_infineon " ,
. pm = & tpm_tis_i2c_ops ,
2013-03-04 18:41:46 +04:00
. of_match_table = of_match_ptr ( tpm_tis_i2c_of_match ) ,
2012-08-07 13:42:32 +04:00
} ,
} ;
module_i2c_driver ( tpm_tis_i2c_driver ) ;
MODULE_AUTHOR ( " Peter Huewe <peter.huewe@infineon.com> " ) ;
MODULE_DESCRIPTION ( " TPM TIS I2C Infineon Driver " ) ;
2013-03-04 18:41:46 +04:00
MODULE_VERSION ( " 2.2.0 " ) ;
2012-08-07 13:42:32 +04:00
MODULE_LICENSE ( " GPL " ) ;