From 7ae44ec850a9c815e402742da8edbef3ca7496e3 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Wed, 16 Apr 2025 11:20:40 -0700 Subject: [PATCH] drivers: i2c: i2c_max32.c: Fix handling of 0-length I2C scan transactions The I2C shell allows a user to input "i2c scan i2c0" for instance, to scan addresses on the i2c0 bus enabled in DT. This currently causes an infinite loop when CONFIG_I2C_MAX32_INTERRUPT is enabled. The infinite loops happens because 0-length transactions (tx_len == rx_len == 0) not being handled both by the Async i2c_max32_transfer and by the controller ISR. This commit makes two changes: 1) [ISR] When an address ACK is received, if there is simply no data to send or receive, then just give up the semaphore, preventing the i2c_max32_transfer function from waiting infinitely. 2) [i2c_max32_transfer] After getting the semaphore back, if there is no data to send or receive, then avoid waiting for the BUSY flag to clear since clock stretching should not occur by definition for transactions which merely contain an address ACK. Signed-off-by: Brandon Hurst --- drivers/i2c/i2c_max32.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_max32.c b/drivers/i2c/i2c_max32.c index 8fdbe71de6c..d23910b416c 100644 --- a/drivers/i2c/i2c_max32.c +++ b/drivers/i2c/i2c_max32.c @@ -532,11 +532,19 @@ static int i2c_max32_transfer(const struct device *dev, struct i2c_msg *msgs, ui ret = data->err; } else { if (data->flags & I2C_MSG_STOP) { - /* Wait for busy flag to be cleared */ - while (i2c->status & ADI_MAX32_I2C_STATUS_MASTER_BUSY) { + /* 0 length transactions are needed for I2C SCANs */ + if ((req->tx_len == req->rx_len) && (req->tx_len == 0)) { + MXC_I2C_ClearFlags(i2c, ADI_MAX32_I2C_INT_FL0_MASK, + ADI_MAX32_I2C_INT_FL1_MASK); + } else { + /* Wait for busy flag to be cleared for clock stetching + * use-cases + */ + while (i2c->status & ADI_MAX32_I2C_STATUS_MASTER_BUSY) { + } + MXC_I2C_ClearFlags(i2c, ADI_MAX32_I2C_INT_FL0_MASK, + ADI_MAX32_I2C_INT_FL1_MASK); } - MXC_I2C_ClearFlags(i2c, ADI_MAX32_I2C_INT_FL0_MASK, - ADI_MAX32_I2C_INT_FL1_MASK); } } if (ret) { @@ -755,6 +763,12 @@ static void i2c_max32_isr_controller(const struct device *dev, mxc_i2c_regs_t *i MXC_I2C_EnableInt( i2c, ADI_MAX32_I2C_INT_EN0_RX_THD | ADI_MAX32_I2C_INT_EN0_DONE, 0); } + /* 0-length transactions are needed for I2C scans. + * In these cases, just give up the semaphore. + */ + else if ((req->tx_len == req->rx_len) && (req->tx_len == 0)) { + k_sem_give(&data->xfer); + } } if (req->tx_len &&