mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
i2c: core: Add support for best effort block read emulation
There are devices that need to handle block transactions regardless of the capabilities exported by the adapter. For performance reasons, they need to use i2c read blocks if available, otherwise emulate the block transaction with word or byte transactions. Add support for a helper function that would read a data block using the best transfer available: I2C_FUNC_SMBUS_READ_I2C_BLOCK, I2C_FUNC_SMBUS_READ_WORD_DATA or I2C_FUNC_SMBUS_READ_BYTE_DATA. Signed-off-by: Irina Tirdea <irina.tirdea@intel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
3f9c37a0c9
commit
01eef96e37
2 changed files with 60 additions and 0 deletions
|
@ -3007,6 +3007,63 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
|
|||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_xfer);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
|
||||
{
|
||||
|
|
|
@ -121,6 +121,9 @@ extern s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,
|
|||
extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 length,
|
||||
const u8 *values);
|
||||
extern s32
|
||||
i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
|
||||
u8 command, u8 length, u8 *values);
|
||||
#endif /* I2C */
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue