From: Raviteja Narayanam <raviteja.narayanam@xxxxxxxxxx> Xilinx I2C IP has two modes of operation, both of which implement I2C transactions. The only difference from sw perspective is the programming sequence for these modes. Dynamic mode -> Simple to program, less number of steps in sequence. Standard mode -> Gives flexibility, more number of steps in sequence. In dynamic mode, during the i2c-read transactions, if there is a delay(> 200us) between the register writes (address & byte count), read transaction fails. On a system with load, this scenario is occurring frequently. To avoid this, switch to standard mode if there is a read request. Added a quirk to identify the IP version effected by this and follow the standard mode. Signed-off-by: Raviteja Narayanam <raviteja.narayanam@xxxxxxxxxx> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@xxxxxxxxxx> --- drivers/i2c/busses/i2c-xiic.c | 87 +++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 57ede62de67d..74cd50478694 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -32,6 +32,7 @@ #include <linux/pm_runtime.h> #define DRIVER_NAME "xiic-i2c" +#define DYNAMIC_MODE_READ_BROKEN_BIT BIT(0) enum xilinx_i2c_state { STATE_DONE, @@ -63,6 +64,7 @@ enum xiic_endian { * @dynamic: Mode of controller * @prev_msg_tx: Previous message is Tx * @smbus_block_read: Flag to handle block read + * @quirks: To hold platform specific bug info */ struct xiic_i2c { struct device *dev; @@ -82,6 +84,11 @@ struct xiic_i2c { bool dynamic; bool prev_msg_tx; bool smbus_block_read; + u32 quirks; +}; + +struct xiic_version_data { + u32 quirks; }; #define XIIC_MSB_OFFSET 0 @@ -995,7 +1002,8 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) { - int ret; + bool broken_read, max_read_len, smbus_blk_read; + int ret, count; mutex_lock(&i2c->lock); @@ -1008,6 +1016,34 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) i2c->nmsgs = num; init_completion(&i2c->completion); + /* Decide standard mode or Dynamic mode */ + i2c->dynamic = true; + + /* Initialize prev message type */ + i2c->prev_msg_tx = false; + + /* + * Scan through nmsgs, use dynamic mode when none of the below three + * conditions occur. We need standard mode even if one condition holds + * true in the entire array of messages in a single transfer. + * If read transaction as dynamic mode is broken for delayed reads + * in xlnx,axi-iic-2.0 / xlnx,xps-iic-2.00.a IP versions. + * If read length is > 255 bytes. + * If smbus_block_read transaction. + */ + for (count = 0; count < i2c->nmsgs; count++) { + broken_read = (i2c->quirks & DYNAMIC_MODE_READ_BROKEN_BIT) && + (i2c->tx_msg[count].flags & I2C_M_RD); + max_read_len = (i2c->tx_msg[count].flags & I2C_M_RD) && + (i2c->tx_msg[count].len > MAX_READ_LENGTH_DYNAMIC); + smbus_blk_read = (i2c->tx_msg[count].flags & I2C_M_RECV_LEN); + + if (broken_read || max_read_len || smbus_blk_read) { + i2c->dynamic = false; + break; + } + } + ret = xiic_reinit(i2c); if (!ret) __xiic_start_xfer(i2c); @@ -1021,7 +1057,7 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct xiic_i2c *i2c = i2c_get_adapdata(adap); - int err, count; + int err; dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET)); @@ -1030,25 +1066,6 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (err < 0) return err; - /* Decide standard mode or Dynamic mode */ - i2c->dynamic = true; - - /* Initialize prev message type */ - i2c->prev_msg_tx = false; - - /* - * Enter standard mode only when read length is > 255 bytes or - * for smbus_block_read transaction - */ - for (count = 0; count < i2c->nmsgs; count++) { - if (((i2c->tx_msg[count].flags & I2C_M_RD) && - i2c->tx_msg[count].len > MAX_READ_LENGTH_DYNAMIC) || - (i2c->tx_msg[count].flags & I2C_M_RECV_LEN)) { - i2c->dynamic = false; - break; - } - } - err = xiic_start_xfer(i2c, msgs, num); if (err < 0) { dev_err(adap->dev.parent, "Error xiic_start_xfer\n"); @@ -1091,10 +1108,23 @@ static const struct i2c_adapter xiic_adapter = { .algo = &xiic_algorithm, }; +static const struct xiic_version_data xiic_2_00 = { + .quirks = DYNAMIC_MODE_READ_BROKEN_BIT, +}; + +#if defined(CONFIG_OF) +static const struct of_device_id xiic_of_match[] = { + { .compatible = "xlnx,xps-iic-2.00.a", .data = &xiic_2_00 }, + {}, +}; +MODULE_DEVICE_TABLE(of, xiic_of_match); +#endif + static int xiic_i2c_probe(struct platform_device *pdev) { struct xiic_i2c *i2c; struct xiic_i2c_platform_data *pdata; + const struct of_device_id *match; struct resource *res; int ret, irq; u8 i; @@ -1104,6 +1134,13 @@ static int xiic_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; + match = of_match_node(xiic_of_match, pdev->dev.of_node); + if (match && match->data) { + const struct xiic_version_data *data = match->data; + + i2c->quirks = data->quirks; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(i2c->base)) @@ -1215,14 +1252,6 @@ static int xiic_i2c_remove(struct platform_device *pdev) return 0; } -#if defined(CONFIG_OF) -static const struct of_device_id xiic_of_match[] = { - { .compatible = "xlnx,xps-iic-2.00.a", }, - {}, -}; -MODULE_DEVICE_TABLE(of, xiic_of_match); -#endif - static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev) { struct xiic_i2c *i2c = dev_get_drvdata(dev); -- 2.25.1