Skip to content

Commit 01eef96

Browse files
itirdeaWolfram Sang
authored andcommitted
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>
1 parent 3f9c37a commit 01eef96

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

drivers/i2c/i2c-core.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3007,6 +3007,63 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
30073007
}
30083008
EXPORT_SYMBOL(i2c_smbus_xfer);
30093009

3010+
/**
3011+
* i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate
3012+
* @client: Handle to slave device
3013+
* @command: Byte interpreted by slave
3014+
* @length: Size of data block; SMBus allows at most I2C_SMBUS_BLOCK_MAX bytes
3015+
* @values: Byte array into which data will be read; big enough to hold
3016+
* the data returned by the slave. SMBus allows at most
3017+
* I2C_SMBUS_BLOCK_MAX bytes.
3018+
*
3019+
* This executes the SMBus "block read" protocol if supported by the adapter.
3020+
* If block read is not supported, it emulates it using either word or byte
3021+
* read protocols depending on availability.
3022+
*
3023+
* The addresses of the I2C slave device that are accessed with this function
3024+
* must be mapped to a linear region, so that a block read will have the same
3025+
* effect as a byte read. Before using this function you must double-check
3026+
* if the I2C slave does support exchanging a block transfer with a byte
3027+
* transfer.
3028+
*/
3029+
s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
3030+
u8 command, u8 length, u8 *values)
3031+
{
3032+
u8 i = 0;
3033+
int status;
3034+
3035+
if (length > I2C_SMBUS_BLOCK_MAX)
3036+
length = I2C_SMBUS_BLOCK_MAX;
3037+
3038+
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
3039+
return i2c_smbus_read_i2c_block_data(client, command, length, values);
3040+
3041+
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA))
3042+
return -EOPNOTSUPP;
3043+
3044+
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) {
3045+
while ((i + 2) <= length) {
3046+
status = i2c_smbus_read_word_data(client, command + i);
3047+
if (status < 0)
3048+
return status;
3049+
values[i] = status & 0xff;
3050+
values[i + 1] = status >> 8;
3051+
i += 2;
3052+
}
3053+
}
3054+
3055+
while (i < length) {
3056+
status = i2c_smbus_read_byte_data(client, command + i);
3057+
if (status < 0)
3058+
return status;
3059+
values[i] = status;
3060+
i++;
3061+
}
3062+
3063+
return i;
3064+
}
3065+
EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated);
3066+
30103067
#if IS_ENABLED(CONFIG_I2C_SLAVE)
30113068
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
30123069
{

include/linux/i2c.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ extern s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,
121121
extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
122122
u8 command, u8 length,
123123
const u8 *values);
124+
extern s32
125+
i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
126+
u8 command, u8 length, u8 *values);
124127
#endif /* I2C */
125128

126129
/**

0 commit comments

Comments
 (0)