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


Reply via email to