I2C documentation Documentation/i2c/fault-codes.rst defines fault codes for different negative results in I2C transmittion. Previously, i2c-designware driver didn't implement them properly - it returned EREMOTEIO on NACK either on address or data phase instead of ENXIO and EIO respectively, and EINVAL instead of EOPNOTSUPP if a message cannot be sent due to controller hardware limitations.
To comply with the documentation, return the proper fault codes for different conditions, namely: - EOPNOTSUPP if the controller cannot transfer the message sequence requested (for example, target address change without STOP condition) - ENXIO if target address is not acknowledged - EIO on other faults detected by controller (for example, NACK on data) Signed-off-by: Dmitry Guzman <[email protected]> --- drivers/i2c/busses/i2c-designware-common.c | 8 ++++++-- drivers/i2c/busses/i2c-designware-core.h | 3 +-- drivers/i2c/busses/i2c-designware-master.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index a1eca6cd4b75e9a76f2fc10afba8877d2b45417d..e934bcbe766042483874b3e43d10ffff30c59e04 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -776,11 +776,15 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) unsigned long abort_source = dev->abort_source; int i; - if (abort_source & DW_IC_TX_ABRT_NOACK) { + if (abort_source & (DW_IC_TX_ABRT_ADDR_NOACK | DW_IC_TX_ABRT_TXDATA_NOACK)) { for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) dev_dbg(dev->dev, "%s: %s\n", __func__, abort_sources[i]); - return -EREMOTEIO; + + if (abort_source & DW_IC_TX_ABRT_TXDATA_NOACK) + return -EIO; + else + return -ENXIO; } for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 2c929a6e8da2a35b3b2d8ad886e326e2df285927..025311c8662c612aaaf772fb223af38278217c90 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -112,10 +112,9 @@ #define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST) #define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO) -#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ +#define DW_IC_TX_ABRT_ADDR_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ DW_IC_TX_ABRT_10ADDR1_NOACK | \ DW_IC_TX_ABRT_10ADDR2_NOACK | \ - DW_IC_TX_ABRT_TXDATA_NOACK | \ DW_IC_TX_ABRT_GCALL_NOACK) struct clk; diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index a1bcc3797e4ffef0edb9d3e978eab20a3c09d6aa..d10f46cf4aa44344fa1c53b9b8798a8b0f0c193c 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -894,7 +894,7 @@ i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c_msg msgs[], int num) */ for (cnt = 1; ; cnt++) { if (!i2c_dw_msg_is_valid(dev, msgs_part, cnt - 1)) { - ret = -EINVAL; + ret = -EOPNOTSUPP; break; } -- 2.43.0
