i2c-mlxbf: Add repeated start condition support

Add support for SMBus repeated start conditions to the Mellanox I2C
driver. This support is specifically enabled for the
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK implementation which is required for
communication with a specific I2C device on BlueField 3.

Signed-off-by: Chris Babroski <cbabroski@nvidia.com>
Reviewed-by: Asmaa Mnebhi <asmaa@nvidia.com>
Reviewed-by: Khalil Blaiech <kblaiech@nvidia.com>
Link: https://lore.kernel.org/r/20250506193059.321345-1-cbabroski@nvidia.com
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
This commit is contained in:
Chris Babroski 2025-05-06 19:30:58 +00:00 committed by Andi Shyti
parent 24d9f60505
commit 6bdc662c05

View File

@ -224,7 +224,7 @@
#define MLXBF_I2C_MASTER_ENABLE \
(MLXBF_I2C_MASTER_LOCK_BIT | MLXBF_I2C_MASTER_BUSY_BIT | \
MLXBF_I2C_MASTER_START_BIT | MLXBF_I2C_MASTER_STOP_BIT)
MLXBF_I2C_MASTER_START_BIT)
#define MLXBF_I2C_MASTER_ENABLE_WRITE \
(MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_WRITE_BIT)
@ -338,6 +338,7 @@ enum {
MLXBF_I2C_F_SMBUS_BLOCK = BIT(5),
MLXBF_I2C_F_SMBUS_PEC = BIT(6),
MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7),
MLXBF_I2C_F_WRITE_WITHOUT_STOP = BIT(8),
};
/* Mellanox BlueField chip type. */
@ -638,16 +639,19 @@ static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv,
}
static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave,
u8 len, u8 block_en, u8 pec_en, bool read)
u8 len, u8 block_en, u8 pec_en, bool read,
bool stop)
{
u32 command;
u32 command = 0;
/* Set Master GW control word. */
if (stop)
command |= MLXBF_I2C_MASTER_STOP_BIT;
if (read) {
command = MLXBF_I2C_MASTER_ENABLE_READ;
command |= MLXBF_I2C_MASTER_ENABLE_READ;
command |= rol32(len, MLXBF_I2C_MASTER_READ_SHIFT);
} else {
command = MLXBF_I2C_MASTER_ENABLE_WRITE;
command |= MLXBF_I2C_MASTER_ENABLE_WRITE;
command |= rol32(len, MLXBF_I2C_MASTER_WRITE_SHIFT);
}
command |= rol32(slave, MLXBF_I2C_MASTER_SLV_ADDR_SHIFT);
@ -682,8 +686,10 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
u8 op_idx, data_idx, data_len, write_len, read_len;
struct mlxbf_i2c_smbus_operation *operation;
u8 read_en, write_en, block_en, pec_en;
u8 slave, flags, addr;
bool stop_after_write = true;
u8 slave, addr;
u8 *read_buf;
u32 flags;
u32 bits;
int ret;
@ -755,7 +761,16 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
memcpy(data_desc + data_idx,
operation->buffer, operation->length);
data_idx += operation->length;
/*
* The stop condition can be skipped when writing on the bus
* to implement a repeated start condition on the next read
* as required for several SMBus and I2C operations.
*/
if (flags & MLXBF_I2C_F_WRITE_WITHOUT_STOP)
stop_after_write = false;
}
/*
* We assume that read operations are performed only once per
* SMBus transaction. *TBD* protect this statement so it won't
@ -781,7 +796,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
if (write_en) {
ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en,
pec_en, 0);
pec_en, 0, stop_after_write);
if (ret)
goto out_unlock;
}
@ -791,7 +806,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
mlxbf_i2c_smbus_write_data(priv, (const u8 *)&addr, 1,
MLXBF_I2C_MASTER_DATA_DESC_ADDR, true);
ret = mlxbf_i2c_smbus_enable(priv, slave, read_len, block_en,
pec_en, 1);
pec_en, 1, true);
if (!ret) {
/* Get Master GW data descriptor. */
mlxbf_i2c_smbus_read_data(priv, data_desc, read_len + 1,
@ -897,6 +912,9 @@ mlxbf_i2c_smbus_i2c_block_func(struct mlxbf_i2c_smbus_request *request,
request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0;
request->operation[0].buffer = command;
if (read)
request->operation[0].flags |= MLXBF_I2C_F_WRITE_WITHOUT_STOP;
/*
* As specified in the standard, the max number of bytes to read/write
* per block operation is 32 bytes. In Golan code, the controller can