From 257bcb8d58f37e0806c66a41d067d8dee307eac0 Mon Sep 17 00:00:00 2001 From: Alex Hogen Date: Wed, 2 Jul 2025 11:37:05 -0700 Subject: [PATCH] drivers: i2c: gecko: Fix EFM32 I2C target Fix I2C target implementation so NACKs are issued if the callback returns an error. This allows for proper signaling to the I2C host when commands or data are invalid for the I2C target. Signed-off-by: Alex Hogen --- drivers/i2c/i2c_gecko.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/i2c_gecko.c b/drivers/i2c/i2c_gecko.c index 95ba6f1fac7..56cd21abdab 100644 --- a/drivers/i2c/i2c_gecko.c +++ b/drivers/i2c/i2c_gecko.c @@ -237,6 +237,7 @@ void i2c_gecko_isr(const struct device *dev) uint32_t pending; uint32_t rx_byte; uint8_t tx_byte; + int ret; pending = config->base->IF; @@ -249,31 +250,52 @@ void i2c_gecko_isr(const struct device *dev) if (pending & I2C_IF_ADDR) { /* Address Match, indicating that reception is started */ rx_byte = config->base->RXDATA; - config->base->CMD = I2C_CMD_ACK; /* Check if read bit set */ if (rx_byte & 0x1) { - data->target_cfg->callbacks->read_requested(data->target_cfg, - &tx_byte); - config->base->TXDATA = tx_byte; + ret = data->target_cfg->callbacks->read_requested(data->target_cfg, + &tx_byte); + if (ret == 0) { + config->base->CMD = I2C_CMD_ACK; + config->base->TXDATA = tx_byte; + } else { + config->base->CMD = I2C_CMD_NACK; + config->base->TXDATA = 0xFF; + } } else { - data->target_cfg->callbacks->write_requested(data->target_cfg); + ret = data->target_cfg->callbacks->write_requested( + data->target_cfg); + if (ret == 0) { + config->base->CMD = I2C_CMD_ACK; + } else { + config->base->CMD = I2C_CMD_NACK; + } } I2C_IntClear(config->base, I2C_IF_ADDR | I2C_IF_RXDATAV); } else if (pending & I2C_IF_RXDATAV) { rx_byte = config->base->RXDATA; /* Read new data and write to target address */ - data->target_cfg->callbacks->write_received(data->target_cfg, rx_byte); - config->base->CMD = I2C_CMD_ACK; + ret = data->target_cfg->callbacks->write_received(data->target_cfg, + rx_byte); + if (ret == 0) { + config->base->CMD = I2C_CMD_ACK; + } else { + config->base->CMD = I2C_CMD_NACK; + } I2C_IntClear(config->base, I2C_IF_RXDATAV); } if (pending & I2C_IF_ACK) { /* Leader ACK'ed, so requesting more data */ - data->target_cfg->callbacks->read_processed(data->target_cfg, &tx_byte); - config->base->TXDATA = tx_byte; + ret = data->target_cfg->callbacks->read_processed(data->target_cfg, + &tx_byte); + if (ret == 0) { + config->base->TXDATA = tx_byte; + } else { + config->base->TXDATA = 0xFF; + } I2C_IntClear(config->base, I2C_IF_ACK); }