2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-05-23 13:27:17 +03:00
/*
* Linux I2C core SMBus and SMBus emulation code
*
* This file contains the SMBus functions which are always included in the I2C
* core because they can be emulated via I2C . SMBus specific extensions
2020-06-13 00:26:35 +03:00
* ( e . g . smbalert ) are handled in a separate i2c - smbus module .
2017-05-23 13:27:17 +03:00
*
* All SMBus - related things are written by Frodo Looijaard < frodol @ dds . nl >
* SMBus 2.0 support by Mark Studebaker < mdsxyz123 @ yahoo . com > and
* Jean Delvare < jdelvare @ suse . de >
*/
# include <linux/device.h>
# include <linux/err.h>
# include <linux/i2c.h>
2017-08-24 12:31:02 +03:00
# include <linux/i2c-smbus.h>
2017-11-04 23:20:06 +03:00
# include <linux/slab.h>
2017-05-23 13:27:17 +03:00
2019-04-03 15:40:09 +03:00
# include "i2c-core.h"
2017-05-23 13:27:17 +03:00
# define CREATE_TRACE_POINTS
# include <trace/events/smbus.h>
/* The SMBus parts */
# define POLY (0x1070U << 3)
static u8 crc8 ( u16 data )
{
int i ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( data & 0x8000 )
data = data ^ POLY ;
data = data < < 1 ;
}
return ( u8 ) ( data > > 8 ) ;
}
2021-05-19 10:49:28 +03:00
/**
* i2c_smbus_pec - Incremental CRC8 over the given input data array
* @ crc : previous return crc8 value
* @ p : pointer to data buffer .
* @ count : number of bytes in data buffer .
*
* Incremental CRC8 over count bytes in the array pointed to by p
*/
u8 i2c_smbus_pec ( u8 crc , u8 * p , size_t count )
2017-05-23 13:27:17 +03:00
{
int i ;
for ( i = 0 ; i < count ; i + + )
crc = crc8 ( ( crc ^ p [ i ] ) < < 8 ) ;
return crc ;
}
2021-05-19 10:49:28 +03:00
EXPORT_SYMBOL ( i2c_smbus_pec ) ;
2017-05-23 13:27:17 +03:00
/* Assume a 7-bit address, which is reasonable for SMBus */
static u8 i2c_smbus_msg_pec ( u8 pec , struct i2c_msg * msg )
{
/* The address will be sent first */
u8 addr = i2c_8bit_addr_from_msg ( msg ) ;
pec = i2c_smbus_pec ( pec , & addr , 1 ) ;
/* The data buffer follows */
return i2c_smbus_pec ( pec , msg - > buf , msg - > len ) ;
}
/* Used for write only transactions */
static inline void i2c_smbus_add_pec ( struct i2c_msg * msg )
{
msg - > buf [ msg - > len ] = i2c_smbus_msg_pec ( 0 , msg ) ;
msg - > len + + ;
}
/* Return <0 on CRC error
If there was a write before this read ( most cases ) we need to take the
partial CRC from the write part into account .
Note that this function does modify the message ( we need to decrease the
message length to hide the CRC byte from the caller ) . */
static int i2c_smbus_check_pec ( u8 cpec , struct i2c_msg * msg )
{
u8 rpec = msg - > buf [ - - msg - > len ] ;
cpec = i2c_smbus_msg_pec ( cpec , msg ) ;
if ( rpec ! = cpec ) {
pr_debug ( " Bad PEC 0x%02x vs. 0x%02x \n " ,
rpec , cpec ) ;
return - EBADMSG ;
}
return 0 ;
}
/**
* i2c_smbus_read_byte - SMBus " receive byte " protocol
* @ client : Handle to slave device
*
* This executes the SMBus " receive byte " protocol , returning negative errno
* else the byte received from the device .
*/
s32 i2c_smbus_read_byte ( const struct i2c_client * client )
{
union i2c_smbus_data data ;
int status ;
status = i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_READ , 0 ,
I2C_SMBUS_BYTE , & data ) ;
return ( status < 0 ) ? status : data . byte ;
}
EXPORT_SYMBOL ( i2c_smbus_read_byte ) ;
/**
* i2c_smbus_write_byte - SMBus " send byte " protocol
* @ client : Handle to slave device
* @ value : Byte to be sent
*
* This executes the SMBus " send byte " protocol , returning negative errno
* else zero on success .
*/
s32 i2c_smbus_write_byte ( const struct i2c_client * client , u8 value )
{
return i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_WRITE , value , I2C_SMBUS_BYTE , NULL ) ;
}
EXPORT_SYMBOL ( i2c_smbus_write_byte ) ;
/**
* i2c_smbus_read_byte_data - SMBus " read byte " protocol
* @ client : Handle to slave device
* @ command : Byte interpreted by slave
*
* This executes the SMBus " read byte " protocol , returning negative errno
* else a data byte received from the device .
*/
s32 i2c_smbus_read_byte_data ( const struct i2c_client * client , u8 command )
{
union i2c_smbus_data data ;
int status ;
status = i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_READ , command ,
I2C_SMBUS_BYTE_DATA , & data ) ;
return ( status < 0 ) ? status : data . byte ;
}
EXPORT_SYMBOL ( i2c_smbus_read_byte_data ) ;
/**
* i2c_smbus_write_byte_data - SMBus " write byte " protocol
* @ client : Handle to slave device
* @ command : Byte interpreted by slave
* @ value : Byte being written
*
* This executes the SMBus " write byte " protocol , returning negative errno
* else zero on success .
*/
s32 i2c_smbus_write_byte_data ( const struct i2c_client * client , u8 command ,
u8 value )
{
union i2c_smbus_data data ;
data . byte = value ;
return i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_WRITE , command ,
I2C_SMBUS_BYTE_DATA , & data ) ;
}
EXPORT_SYMBOL ( i2c_smbus_write_byte_data ) ;
/**
* i2c_smbus_read_word_data - SMBus " read word " protocol
* @ client : Handle to slave device
* @ command : Byte interpreted by slave
*
* This executes the SMBus " read word " protocol , returning negative errno
* else a 16 - bit unsigned " word " received from the device .
*/
s32 i2c_smbus_read_word_data ( const struct i2c_client * client , u8 command )
{
union i2c_smbus_data data ;
int status ;
status = i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_READ , command ,
I2C_SMBUS_WORD_DATA , & data ) ;
return ( status < 0 ) ? status : data . word ;
}
EXPORT_SYMBOL ( i2c_smbus_read_word_data ) ;
/**
* i2c_smbus_write_word_data - SMBus " write word " protocol
* @ client : Handle to slave device
* @ command : Byte interpreted by slave
* @ value : 16 - bit " word " being written
*
* This executes the SMBus " write word " protocol , returning negative errno
* else zero on success .
*/
s32 i2c_smbus_write_word_data ( const struct i2c_client * client , u8 command ,
u16 value )
{
union i2c_smbus_data data ;
data . word = value ;
return i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_WRITE , command ,
I2C_SMBUS_WORD_DATA , & data ) ;
}
EXPORT_SYMBOL ( i2c_smbus_write_word_data ) ;
/**
* i2c_smbus_read_block_data - SMBus " block read " protocol
* @ client : Handle to slave device
* @ command : Byte interpreted by slave
* @ values : Byte array into which data will be read ; big enough to hold
* the data returned by the slave . SMBus allows at most 32 bytes .
*
* This executes the SMBus " block read " protocol , returning negative errno
* else the number of data bytes in the slave ' s response .
*
* Note that using this function requires that the client ' s adapter support
* the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality . Not all adapter drivers
* support this ; its emulation through I2C messaging relies on a specific
* mechanism ( I2C_M_RECV_LEN ) which may not be implemented .
*/
s32 i2c_smbus_read_block_data ( const struct i2c_client * client , u8 command ,
u8 * values )
{
union i2c_smbus_data data ;
int status ;
status = i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_READ , command ,
I2C_SMBUS_BLOCK_DATA , & data ) ;
if ( status )
return status ;
memcpy ( values , & data . block [ 1 ] , data . block [ 0 ] ) ;
return data . block [ 0 ] ;
}
EXPORT_SYMBOL ( i2c_smbus_read_block_data ) ;
/**
* i2c_smbus_write_block_data - SMBus " block write " protocol
* @ client : Handle to slave device
* @ command : Byte interpreted by slave
* @ length : Size of data block ; SMBus allows at most 32 bytes
* @ values : Byte array which will be written .
*
* This executes the SMBus " block write " protocol , returning negative errno
* else zero on success .
*/
s32 i2c_smbus_write_block_data ( const struct i2c_client * client , u8 command ,
u8 length , const u8 * values )
{
union i2c_smbus_data data ;
if ( length > I2C_SMBUS_BLOCK_MAX )
length = I2C_SMBUS_BLOCK_MAX ;
data . block [ 0 ] = length ;
memcpy ( & data . block [ 1 ] , values , length ) ;
return i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_WRITE , command ,
I2C_SMBUS_BLOCK_DATA , & data ) ;
}
EXPORT_SYMBOL ( i2c_smbus_write_block_data ) ;
/* Returns the number of read bytes */
s32 i2c_smbus_read_i2c_block_data ( const struct i2c_client * client , u8 command ,
u8 length , u8 * values )
{
union i2c_smbus_data data ;
int status ;
if ( length > I2C_SMBUS_BLOCK_MAX )
length = I2C_SMBUS_BLOCK_MAX ;
data . block [ 0 ] = length ;
status = i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_READ , command ,
I2C_SMBUS_I2C_BLOCK_DATA , & data ) ;
if ( status < 0 )
return status ;
memcpy ( values , & data . block [ 1 ] , data . block [ 0 ] ) ;
return data . block [ 0 ] ;
}
EXPORT_SYMBOL ( i2c_smbus_read_i2c_block_data ) ;
s32 i2c_smbus_write_i2c_block_data ( const struct i2c_client * client , u8 command ,
u8 length , const u8 * values )
{
union i2c_smbus_data data ;
if ( length > I2C_SMBUS_BLOCK_MAX )
length = I2C_SMBUS_BLOCK_MAX ;
data . block [ 0 ] = length ;
memcpy ( data . block + 1 , values , length ) ;
return i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
I2C_SMBUS_WRITE , command ,
I2C_SMBUS_I2C_BLOCK_DATA , & data ) ;
}
EXPORT_SYMBOL ( i2c_smbus_write_i2c_block_data ) ;
2017-11-04 23:20:06 +03:00
static void i2c_smbus_try_get_dmabuf ( struct i2c_msg * msg , u8 init_val )
{
bool is_read = msg - > flags & I2C_M_RD ;
unsigned char * dma_buf ;
dma_buf = kzalloc ( I2C_SMBUS_BLOCK_MAX + ( is_read ? 2 : 3 ) , GFP_KERNEL ) ;
if ( ! dma_buf )
return ;
msg - > buf = dma_buf ;
msg - > flags | = I2C_M_DMA_SAFE ;
if ( init_val )
msg - > buf [ 0 ] = init_val ;
}
2018-02-27 00:17:53 +03:00
/*
* Simulate a SMBus command using the I2C protocol .
* No checking of parameters is done !
*/
2017-05-23 13:27:17 +03:00
static s32 i2c_smbus_xfer_emulated ( struct i2c_adapter * adapter , u16 addr ,
unsigned short flags ,
char read_write , u8 command , int size ,
union i2c_smbus_data * data )
{
2018-02-27 00:17:53 +03:00
/*
* So we need to generate a series of msgs . In the case of writing , we
* need to use only one message ; when reading , we need two . We
* initialize most things with sane defaults , to keep the code below
* somewhat simpler .
*/
2017-05-23 13:27:17 +03:00
unsigned char msgbuf0 [ I2C_SMBUS_BLOCK_MAX + 3 ] ;
unsigned char msgbuf1 [ I2C_SMBUS_BLOCK_MAX + 2 ] ;
2021-01-12 18:12:30 +03:00
int nmsgs = read_write = = I2C_SMBUS_READ ? 2 : 1 ;
2017-05-23 13:27:17 +03:00
u8 partial_pec = 0 ;
int status ;
struct i2c_msg msg [ 2 ] = {
{
. addr = addr ,
. flags = flags ,
. len = 1 ,
. buf = msgbuf0 ,
} , {
. addr = addr ,
. flags = flags | I2C_M_RD ,
. len = 0 ,
. buf = msgbuf1 ,
} ,
} ;
2021-01-12 18:12:29 +03:00
bool wants_pec = ( ( flags & I2C_CLIENT_PEC ) & & size ! = I2C_SMBUS_QUICK
& & size ! = I2C_SMBUS_I2C_BLOCK_DATA ) ;
2017-05-23 13:27:17 +03:00
msgbuf0 [ 0 ] = command ;
switch ( size ) {
case I2C_SMBUS_QUICK :
msg [ 0 ] . len = 0 ;
/* Special case: The read/write field is used as data */
msg [ 0 ] . flags = flags | ( read_write = = I2C_SMBUS_READ ?
I2C_M_RD : 0 ) ;
2021-01-12 18:12:30 +03:00
nmsgs = 1 ;
2017-05-23 13:27:17 +03:00
break ;
case I2C_SMBUS_BYTE :
if ( read_write = = I2C_SMBUS_READ ) {
/* Special case: only a read! */
msg [ 0 ] . flags = I2C_M_RD | flags ;
2021-01-12 18:12:30 +03:00
nmsgs = 1 ;
2017-05-23 13:27:17 +03:00
}
break ;
case I2C_SMBUS_BYTE_DATA :
if ( read_write = = I2C_SMBUS_READ )
msg [ 1 ] . len = 1 ;
else {
msg [ 0 ] . len = 2 ;
msgbuf0 [ 1 ] = data - > byte ;
}
break ;
case I2C_SMBUS_WORD_DATA :
if ( read_write = = I2C_SMBUS_READ )
msg [ 1 ] . len = 2 ;
else {
msg [ 0 ] . len = 3 ;
msgbuf0 [ 1 ] = data - > word & 0xff ;
msgbuf0 [ 2 ] = data - > word > > 8 ;
}
break ;
case I2C_SMBUS_PROC_CALL :
2021-01-12 18:12:30 +03:00
nmsgs = 2 ; /* Special case */
2017-05-23 13:27:17 +03:00
read_write = I2C_SMBUS_READ ;
msg [ 0 ] . len = 3 ;
msg [ 1 ] . len = 2 ;
msgbuf0 [ 1 ] = data - > word & 0xff ;
msgbuf0 [ 2 ] = data - > word > > 8 ;
break ;
case I2C_SMBUS_BLOCK_DATA :
if ( read_write = = I2C_SMBUS_READ ) {
msg [ 1 ] . flags | = I2C_M_RECV_LEN ;
msg [ 1 ] . len = 1 ; /* block length will be added by
the underlying bus driver */
2017-11-04 23:20:06 +03:00
i2c_smbus_try_get_dmabuf ( & msg [ 1 ] , 0 ) ;
2017-05-23 13:27:17 +03:00
} else {
msg [ 0 ] . len = data - > block [ 0 ] + 2 ;
if ( msg [ 0 ] . len > I2C_SMBUS_BLOCK_MAX + 2 ) {
dev_err ( & adapter - > dev ,
" Invalid block write size %d \n " ,
data - > block [ 0 ] ) ;
return - EINVAL ;
}
2017-11-04 23:20:06 +03:00
i2c_smbus_try_get_dmabuf ( & msg [ 0 ] , command ) ;
2021-01-11 23:40:38 +03:00
memcpy ( msg [ 0 ] . buf + 1 , data - > block , msg [ 0 ] . len - 1 ) ;
2017-05-23 13:27:17 +03:00
}
break ;
case I2C_SMBUS_BLOCK_PROC_CALL :
2021-01-12 18:12:30 +03:00
nmsgs = 2 ; /* Another special case */
2017-05-23 13:27:17 +03:00
read_write = I2C_SMBUS_READ ;
if ( data - > block [ 0 ] > I2C_SMBUS_BLOCK_MAX ) {
dev_err ( & adapter - > dev ,
" Invalid block write size %d \n " ,
data - > block [ 0 ] ) ;
return - EINVAL ;
}
2017-11-04 23:20:06 +03:00
2017-05-23 13:27:17 +03:00
msg [ 0 ] . len = data - > block [ 0 ] + 2 ;
2017-11-04 23:20:06 +03:00
i2c_smbus_try_get_dmabuf ( & msg [ 0 ] , command ) ;
2021-01-11 23:40:38 +03:00
memcpy ( msg [ 0 ] . buf + 1 , data - > block , msg [ 0 ] . len - 1 ) ;
2017-11-04 23:20:06 +03:00
2017-05-23 13:27:17 +03:00
msg [ 1 ] . flags | = I2C_M_RECV_LEN ;
msg [ 1 ] . len = 1 ; /* block length will be added by
the underlying bus driver */
2017-11-04 23:20:06 +03:00
i2c_smbus_try_get_dmabuf ( & msg [ 1 ] , 0 ) ;
2017-05-23 13:27:17 +03:00
break ;
case I2C_SMBUS_I2C_BLOCK_DATA :
2017-11-15 22:31:44 +03:00
if ( data - > block [ 0 ] > I2C_SMBUS_BLOCK_MAX ) {
dev_err ( & adapter - > dev , " Invalid block %s size %d \n " ,
read_write = = I2C_SMBUS_READ ? " read " : " write " ,
data - > block [ 0 ] ) ;
return - EINVAL ;
}
2017-05-23 13:27:17 +03:00
if ( read_write = = I2C_SMBUS_READ ) {
msg [ 1 ] . len = data - > block [ 0 ] ;
2017-11-04 23:20:06 +03:00
i2c_smbus_try_get_dmabuf ( & msg [ 1 ] , 0 ) ;
2017-05-23 13:27:17 +03:00
} else {
msg [ 0 ] . len = data - > block [ 0 ] + 1 ;
2017-11-04 23:20:06 +03:00
i2c_smbus_try_get_dmabuf ( & msg [ 0 ] , command ) ;
2021-01-11 23:40:38 +03:00
memcpy ( msg [ 0 ] . buf + 1 , data - > block + 1 , data - > block [ 0 ] ) ;
2017-05-23 13:27:17 +03:00
}
break ;
default :
dev_err ( & adapter - > dev , " Unsupported transaction %d \n " , size ) ;
return - EOPNOTSUPP ;
}
2021-01-12 18:12:29 +03:00
if ( wants_pec ) {
2017-05-23 13:27:17 +03:00
/* Compute PEC if first message is a write */
if ( ! ( msg [ 0 ] . flags & I2C_M_RD ) ) {
2021-01-12 18:12:30 +03:00
if ( nmsgs = = 1 ) /* Write only */
2017-05-23 13:27:17 +03:00
i2c_smbus_add_pec ( & msg [ 0 ] ) ;
else /* Write followed by read */
partial_pec = i2c_smbus_msg_pec ( 0 , & msg [ 0 ] ) ;
}
/* Ask for PEC if last message is a read */
2021-01-12 18:12:30 +03:00
if ( msg [ nmsgs - 1 ] . flags & I2C_M_RD )
msg [ nmsgs - 1 ] . len + + ;
2017-05-23 13:27:17 +03:00
}
2021-01-12 18:12:30 +03:00
status = __i2c_transfer ( adapter , msg , nmsgs ) ;
2017-05-23 13:27:17 +03:00
if ( status < 0 )
2018-06-20 12:43:23 +03:00
goto cleanup ;
2021-01-12 18:12:30 +03:00
if ( status ! = nmsgs ) {
2018-06-20 12:43:23 +03:00
status = - EIO ;
goto cleanup ;
}
status = 0 ;
2017-05-23 13:27:17 +03:00
/* Check PEC if last message is a read */
2021-01-12 18:12:30 +03:00
if ( wants_pec & & ( msg [ nmsgs - 1 ] . flags & I2C_M_RD ) ) {
status = i2c_smbus_check_pec ( partial_pec , & msg [ nmsgs - 1 ] ) ;
2017-05-23 13:27:17 +03:00
if ( status < 0 )
2018-06-20 12:43:23 +03:00
goto cleanup ;
2017-05-23 13:27:17 +03:00
}
if ( read_write = = I2C_SMBUS_READ )
switch ( size ) {
case I2C_SMBUS_BYTE :
data - > byte = msgbuf0 [ 0 ] ;
break ;
case I2C_SMBUS_BYTE_DATA :
data - > byte = msgbuf1 [ 0 ] ;
break ;
case I2C_SMBUS_WORD_DATA :
case I2C_SMBUS_PROC_CALL :
data - > word = msgbuf1 [ 0 ] | ( msgbuf1 [ 1 ] < < 8 ) ;
break ;
case I2C_SMBUS_I2C_BLOCK_DATA :
2021-01-11 23:40:38 +03:00
memcpy ( data - > block + 1 , msg [ 1 ] . buf , data - > block [ 0 ] ) ;
2017-05-23 13:27:17 +03:00
break ;
case I2C_SMBUS_BLOCK_DATA :
case I2C_SMBUS_BLOCK_PROC_CALL :
2020-06-13 13:41:09 +03:00
if ( msg [ 1 ] . buf [ 0 ] > I2C_SMBUS_BLOCK_MAX ) {
dev_err ( & adapter - > dev ,
" Invalid block size returned: %d \n " ,
msg [ 1 ] . buf [ 0 ] ) ;
status = - EPROTO ;
goto cleanup ;
}
2021-01-11 23:40:38 +03:00
memcpy ( data - > block , msg [ 1 ] . buf , msg [ 1 ] . buf [ 0 ] + 1 ) ;
2017-05-23 13:27:17 +03:00
break ;
}
2017-11-04 23:20:06 +03:00
2018-06-20 12:43:23 +03:00
cleanup :
2017-11-04 23:20:06 +03:00
if ( msg [ 0 ] . flags & I2C_M_DMA_SAFE )
kfree ( msg [ 0 ] . buf ) ;
if ( msg [ 1 ] . flags & I2C_M_DMA_SAFE )
kfree ( msg [ 1 ] . buf ) ;
2018-06-20 12:43:23 +03:00
return status ;
2017-05-23 13:27:17 +03:00
}
/**
* i2c_smbus_xfer - execute SMBus protocol operations
* @ adapter : Handle to I2C bus
* @ addr : Address of SMBus slave on that bus
* @ flags : I2C_CLIENT_ * flags ( usually zero or I2C_CLIENT_PEC )
* @ read_write : I2C_SMBUS_READ or I2C_SMBUS_WRITE
* @ command : Byte interpreted by slave , for protocols which use such bytes
* @ protocol : SMBus protocol operation to execute , such as I2C_SMBUS_PROC_CALL
* @ data : Data to be read or written
*
* This executes an SMBus protocol operation , and returns a negative
* errno code else zero on success .
*/
2018-06-20 11:51:53 +03:00
s32 i2c_smbus_xfer ( struct i2c_adapter * adapter , u16 addr ,
unsigned short flags , char read_write ,
u8 command , int protocol , union i2c_smbus_data * data )
{
s32 res ;
2019-04-03 15:40:09 +03:00
res = __i2c_lock_bus_helper ( adapter ) ;
if ( res )
return res ;
2018-06-20 11:51:53 +03:00
res = __i2c_smbus_xfer ( adapter , addr , flags , read_write ,
command , protocol , data ) ;
i2c_unlock_bus ( adapter , I2C_LOCK_SEGMENT ) ;
return res ;
}
EXPORT_SYMBOL ( i2c_smbus_xfer ) ;
s32 __i2c_smbus_xfer ( struct i2c_adapter * adapter , u16 addr ,
unsigned short flags , char read_write ,
u8 command , int protocol , union i2c_smbus_data * data )
2017-05-23 13:27:17 +03:00
{
2019-04-03 15:40:10 +03:00
int ( * xfer_func ) ( struct i2c_adapter * adap , u16 addr ,
unsigned short flags , char read_write ,
u8 command , int size , union i2c_smbus_data * data ) ;
2017-05-23 13:27:17 +03:00
unsigned long orig_jiffies ;
int try ;
s32 res ;
2019-04-25 17:19:48 +03:00
res = __i2c_check_suspended ( adapter ) ;
if ( res )
return res ;
2017-05-23 13:27:17 +03:00
/* If enabled, the following two tracepoints are conditional on
* read_write and protocol .
*/
trace_smbus_write ( adapter , addr , flags , read_write ,
command , protocol , data ) ;
trace_smbus_read ( adapter , addr , flags , read_write ,
command , protocol ) ;
flags & = I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB ;
2019-04-03 15:40:10 +03:00
xfer_func = adapter - > algo - > smbus_xfer ;
if ( i2c_in_atomic_xfer_mode ( ) ) {
if ( adapter - > algo - > smbus_xfer_atomic )
xfer_func = adapter - > algo - > smbus_xfer_atomic ;
else if ( adapter - > algo - > master_xfer_atomic )
xfer_func = NULL ; /* fallback to I2C emulation */
}
if ( xfer_func ) {
2017-05-23 13:27:17 +03:00
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies ;
for ( res = 0 , try = 0 ; try < = adapter - > retries ; try + + ) {
2019-04-03 15:40:10 +03:00
res = xfer_func ( adapter , addr , flags , read_write ,
command , protocol , data ) ;
2017-05-23 13:27:17 +03:00
if ( res ! = - EAGAIN )
break ;
if ( time_after ( jiffies ,
orig_jiffies + adapter - > timeout ) )
break ;
}
if ( res ! = - EOPNOTSUPP | | ! adapter - > algo - > master_xfer )
goto trace ;
/*
* Fall back to i2c_smbus_xfer_emulated if the adapter doesn ' t
* implement native support for the SMBus operation .
*/
}
res = i2c_smbus_xfer_emulated ( adapter , addr , flags , read_write ,
command , protocol , data ) ;
trace :
/* If enabled, the reply tracepoint is conditional on read_write. */
trace_smbus_reply ( adapter , addr , flags , read_write ,
2019-02-13 06:40:57 +03:00
command , protocol , data , res ) ;
2017-05-23 13:27:17 +03:00
trace_smbus_result ( adapter , addr , flags , read_write ,
command , protocol , res ) ;
return res ;
}
2018-06-20 11:51:53 +03:00
EXPORT_SYMBOL ( __i2c_smbus_xfer ) ;
2017-05-23 13:27:17 +03:00
/**
* i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate
* @ client : Handle to slave device
* @ command : Byte interpreted by slave
* @ length : Size of data block ; SMBus allows at most I2C_SMBUS_BLOCK_MAX bytes
* @ values : Byte array into which data will be read ; big enough to hold
* the data returned by the slave . SMBus allows at most
* I2C_SMBUS_BLOCK_MAX bytes .
*
* This executes the SMBus " block read " protocol if supported by the adapter .
* If block read is not supported , it emulates it using either word or byte
* read protocols depending on availability .
*
* The addresses of the I2C slave device that are accessed with this function
* must be mapped to a linear region , so that a block read will have the same
* effect as a byte read . Before using this function you must double - check
* if the I2C slave does support exchanging a block transfer with a byte
* transfer .
*/
s32 i2c_smbus_read_i2c_block_data_or_emulated ( const struct i2c_client * client ,
u8 command , u8 length , u8 * values )
{
u8 i = 0 ;
int status ;
if ( length > I2C_SMBUS_BLOCK_MAX )
length = I2C_SMBUS_BLOCK_MAX ;
if ( i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_READ_I2C_BLOCK ) )
return i2c_smbus_read_i2c_block_data ( client , command , length , values ) ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_READ_BYTE_DATA ) )
return - EOPNOTSUPP ;
if ( i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_READ_WORD_DATA ) ) {
while ( ( i + 2 ) < = length ) {
status = i2c_smbus_read_word_data ( client , command + i ) ;
if ( status < 0 )
return status ;
values [ i ] = status & 0xff ;
values [ i + 1 ] = status > > 8 ;
i + = 2 ;
}
}
while ( i < length ) {
status = i2c_smbus_read_byte_data ( client , command + i ) ;
if ( status < 0 )
return status ;
values [ i ] = status ;
i + + ;
}
return i ;
}
EXPORT_SYMBOL ( i2c_smbus_read_i2c_block_data_or_emulated ) ;
2017-08-24 12:31:02 +03:00
/**
2020-02-28 20:12:20 +03:00
* i2c_new_smbus_alert_device - get ara client for SMBus alert support
2017-08-24 12:31:02 +03:00
* @ adapter : the target adapter
* @ setup : setup data for the SMBus alert handler
* Context : can sleep
*
* Setup handling of the SMBus alert protocol on a given I2C bus segment .
*
* Handling can be done either through our IRQ handler , or by the
* adapter ( from its handler , periodic polling , or whatever ) .
*
* This returns the ara client , which should be saved for later use with
2020-02-28 20:12:20 +03:00
* i2c_handle_smbus_alert ( ) and ultimately i2c_unregister_device ( ) ; or an
* ERRPTR to indicate an error .
2017-08-24 12:31:02 +03:00
*/
2020-02-28 20:12:20 +03:00
struct i2c_client * i2c_new_smbus_alert_device ( struct i2c_adapter * adapter ,
struct i2c_smbus_alert_setup * setup )
2017-08-24 12:31:02 +03:00
{
struct i2c_board_info ara_board_info = {
I2C_BOARD_INFO ( " smbus_alert " , 0x0c ) ,
. platform_data = setup ,
} ;
2020-02-28 20:12:20 +03:00
return i2c_new_client_device ( adapter , & ara_board_info ) ;
2017-08-24 12:31:02 +03:00
}
2020-02-28 20:12:20 +03:00
EXPORT_SYMBOL_GPL ( i2c_new_smbus_alert_device ) ;
2017-08-24 12:31:03 +03:00
# if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF)
int of_i2c_setup_smbus_alert ( struct i2c_adapter * adapter )
{
int irq ;
irq = of_property_match_string ( adapter - > dev . of_node , " interrupt-names " ,
" smbus_alert " ) ;
if ( irq = = - EINVAL | | irq = = - ENODATA )
return 0 ;
else if ( irq < 0 )
return irq ;
2020-02-28 20:12:20 +03:00
return PTR_ERR_OR_ZERO ( i2c_new_smbus_alert_device ( adapter , NULL ) ) ;
2017-08-24 12:31:03 +03:00
}
EXPORT_SYMBOL_GPL ( of_i2c_setup_smbus_alert ) ;
# endif