]> Git Repo - linux.git/commitdiff
i2c: testunit: on errors, repeat NACK until STOP
authorWolfram Sang <[email protected]>
Wed, 15 Jan 2025 16:23:47 +0000 (17:23 +0100)
committerWolfram Sang <[email protected]>
Wed, 15 Jan 2025 18:44:21 +0000 (19:44 +0100)
This backend requests a NACK from the controller driver when it detects
an error. If that request gets ignored from some reason, subsequent
accesses will wrongly be handled OK. To fix this, an error now changes
the state machine, so the backend will report NACK until a STOP
condition has been detected. This make the driver more robust against
controllers which will sadly apply the NACK not to the current byte but
the next one.

Fixes: a8335c64c5f0 ("i2c: add slave testunit driver")
Signed-off-by: Wolfram Sang <[email protected]>
drivers/i2c/i2c-slave-testunit.c

index 0d6fbaa48248792ff989f9646f6e0bbc5691d603..6de4307050dde6d9670b4bef83c202a57eb44c99 100644 (file)
@@ -38,6 +38,7 @@ enum testunit_regs {
 
 enum testunit_flags {
        TU_FLAG_IN_PROCESS,
+       TU_FLAG_NACK,
 };
 
 struct testunit_data {
@@ -90,8 +91,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
 
        switch (event) {
        case I2C_SLAVE_WRITE_REQUESTED:
-               if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
-                       return -EBUSY;
+               if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) {
+                       ret = -EBUSY;
+                       break;
+               }
 
                memset(tu->regs, 0, TU_NUM_REGS);
                tu->reg_idx = 0;
@@ -99,8 +102,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
                break;
 
        case I2C_SLAVE_WRITE_RECEIVED:
-               if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
-                       return -EBUSY;
+               if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) {
+                       ret = -EBUSY;
+                       break;
+               }
 
                if (tu->reg_idx < TU_NUM_REGS)
                        tu->regs[tu->reg_idx] = *val;
@@ -129,6 +134,8 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
                 * here because we still need them in the workqueue!
                 */
                tu->reg_idx = 0;
+
+               clear_bit(TU_FLAG_NACK, &tu->flags);
                break;
 
        case I2C_SLAVE_READ_PROCESSED:
@@ -151,6 +158,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
                break;
        }
 
+       /* If an error occurred somewhen, we NACK everything until next STOP */
+       if (ret)
+               set_bit(TU_FLAG_NACK, &tu->flags);
+
        return ret;
 }
 
This page took 0.051275 seconds and 4 git commands to generate.