Skip to content

Commit c9bfdc7

Browse files
Michael ShychWolfram Sang
authored andcommitted
i2c: mlxcpld: Add support for smbus block read transaction
It adds support for smbus block read transaction. CPLD smbus block read bit of capability register is verified during driver initialization, and driver data is updated if such capability is available. In case an upper layer requests a read transaction of length one and expects that length will be the first received byte, driver will notify CPLD about SMBus block read transaction flavor, so CPLD will know to execute such kind of transaction. Signed-off-by: Michael Shych <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 313ce64 commit c9bfdc7

File tree

1 file changed

+32
-6
lines changed

1 file changed

+32
-6
lines changed

drivers/i2c/busses/i2c-mlxcpld.c

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#define MLXCPLD_I2C_DATA_REG_SZ 36
4848
#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5)
4949
#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5)
50+
#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7)
5051
#define MLXCPLD_I2C_MAX_ADDR_LEN 4
5152
#define MLXCPLD_I2C_RETR_NUM 2
5253
#define MLXCPLD_I2C_XFER_TO 500000 /* usec */
@@ -85,6 +86,7 @@ struct mlxcpld_i2c_priv {
8586
struct mutex lock;
8687
struct mlxcpld_i2c_curr_xfer xfer;
8788
struct device *dev;
89+
bool smbus_block;
8890
};
8991

9092
static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr)
@@ -297,7 +299,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv)
297299
static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
298300
{
299301
int status, i, timeout = 0;
300-
u8 datalen;
302+
u8 datalen, val;
301303

302304
do {
303305
usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
@@ -326,9 +328,22 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
326328
* Actual read data len will be always the same as
327329
* requested len. 0xff (line pull-up) will be returned
328330
* if slave has no data to return. Thus don't read
329-
* MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD.
331+
* MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of
332+
* SMBus block read transaction data len can be different,
333+
* check this case.
330334
*/
331-
datalen = priv->xfer.data_len;
335+
mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val,
336+
1);
337+
if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) {
338+
mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
339+
&datalen, 1);
340+
if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) {
341+
dev_err(priv->dev, "Incorrect smbus block read message len\n");
342+
return -E2BIG;
343+
}
344+
} else {
345+
datalen = priv->xfer.data_len;
346+
}
332347

333348
mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG,
334349
priv->xfer.msg[i].buf, datalen);
@@ -346,12 +361,20 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
346361
static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv)
347362
{
348363
int i, len = 0;
349-
u8 cmd;
364+
u8 cmd, val;
350365

351366
mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
352367
&priv->xfer.data_len, 1);
353-
mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG,
354-
&priv->xfer.addr_width, 1);
368+
369+
val = priv->xfer.addr_width;
370+
/* Notify HW about SMBus block read transaction */
371+
if (priv->smbus_block && priv->xfer.msg_num >= 2 &&
372+
priv->xfer.msg[1].len == 1 &&
373+
(priv->xfer.msg[1].flags & I2C_M_RECV_LEN) &&
374+
(priv->xfer.msg[1].flags & I2C_M_RD))
375+
val |= MLXCPLD_I2C_SMBUS_BLK_BIT;
376+
377+
mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1);
355378

356379
for (i = 0; i < priv->xfer.msg_num; i++) {
357380
if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) {
@@ -481,6 +504,9 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
481504
/* Check support for extended transaction length */
482505
if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT)
483506
mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext;
507+
/* Check support for smbus block transaction */
508+
if (val & MLXCPLD_I2C_SMBUS_BLK_BIT)
509+
priv->smbus_block = true;
484510
priv->adap = mlxcpld_i2c_adapter;
485511
priv->adap.dev.parent = &pdev->dev;
486512
priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;

0 commit comments

Comments
 (0)