]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
i2c: cadence: Check for errata condition involving master receive
authorHarini Katakam <harinik@xilinx.com>
Tue, 13 Jan 2015 18:34:59 +0000 (00:04 +0530)
committerWolfram Sang <wsa@the-dreams.de>
Wed, 14 Jan 2015 10:36:58 +0000 (11:36 +0100)
Cadence I2C controller has the following bugs:
- completion indication is not given to the driver at the end of
a read/receive transfer with HOLD bit set.
- Invalid read transaction are generated on the bus when HW timeout
condition occurs with HOLD bit set.

As a result of the above, if a set of messages to be transferred with
repeated start includes any message following a read message,
completion is never indicated and timeout occurs.
Hence a check is implemented to return -EOPNOTSUPP for such sequences.

Signed-off-by: Harini Katakam <harinik@xilinx.com>
Signed-off-by: Vishnu Motghare <vishnum@xilinx.com>
[wsa: fixed some whitespaces]
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/i2c/busses/i2c-cadence.c

index 871cb58aaa0688d15f37a8078b9ff33aa797081f..7d7a14cdadfb187d5fd4f95918146c8c6555443a 100644 (file)
@@ -545,6 +545,20 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
         * processed with a repeated start.
         */
        if (num > 1) {
+               /*
+                * This controller does not give completion interrupt after a
+                * master receive message if HOLD bit is set (repeated start),
+                * resulting in SW timeout. Hence, if a receive message is
+                * followed by any other message, an error is returned
+                * indicating that this sequence is not supported.
+                */
+               for (count = 0; count < num - 1; count++) {
+                       if (msgs[count].flags & I2C_M_RD) {
+                               dev_warn(adap->dev.parent,
+                                        "Can't do repeated start after a receive message\n");
+                               return -EOPNOTSUPP;
+                       }
+               }
                id->bus_hold_flag = 1;
                reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
                reg |= CDNS_I2C_CR_HOLD;