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 <alex@edt.com>
This commit is contained in:
Alex Hogen 2025-07-02 11:37:05 -07:00 committed by Daniel DeGrasse
parent 92f7e8d84b
commit 257bcb8d58

View File

@ -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);
}