drivers/i2c: it51xxx: Refactor ISR to reduce clock stretch in PIO mode

Move handling of write-to-clear status and stop detect to the
beginning of the ISR for PIO mode to reduce unnecessary clock
stretching and improve responsiveness during transfers.

This patch also separates status clearing for shared FIFO mode,
ensuring it is done at the appropriate point after data handling
completes, maintaining correct transfer behavior.

Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
This commit is contained in:
Tim Lin 2025-07-03 17:48:33 +08:00 committed by Benjamin Cabé
parent b8bfa36250
commit 648919f6df

View File

@ -545,23 +545,37 @@ done:
#endif
}
static void clear_target_status(const struct device *dev, uint8_t status)
{
const struct i2c_it51xxx_config *config = dev->config;
/* Write to clear a specific status */
#ifdef CONFIG_SOC_IT51526AW
sys_write8(status, config->i2cbase_mapping + SMB_SLSTA(config->port));
#else
sys_write8(status, config->target_base + SMB_SLSTn);
#endif
}
static void target_i2c_isr_pio(const struct device *dev)
{
const struct i2c_it51xxx_config *config = dev->config;
struct i2c_it51xxx_data *data = dev->data;
struct i2c_target_config *target_cfg;
const struct i2c_target_callbacks *target_cb;
int ret;
uint8_t target_status, target_idx;
uint8_t val;
target_status = sys_read8(config->target_base + SMB_SLSTn);
/* Write to clear a target status */
clear_target_status(dev, target_status);
/* Any error */
if (target_status & SMB_STS) {
data->w_index = 0;
data->r_index = 0;
goto done;
return;
}
/* Which target address to match. */
@ -569,6 +583,24 @@ static void target_i2c_isr_pio(const struct device *dev)
target_cfg = data->target_cfg[target_idx];
target_cb = target_cfg->callbacks;
/* Stop condition, indicate stop condition detected. */
if (target_status & SMB_SPDS) {
/* Transfer done callback function */
if (target_cb->stop) {
target_cb->stop(target_cfg);
}
data->w_index = 0;
data->r_index = 0;
if (config->target_shared_fifo_mode) {
uint8_t sdfpctl;
/* Disable FIFO mode to clear left count */
sdfpctl = sys_read8(config->target_base + SMB_SnDFPCTL);
sys_write8(sdfpctl & ~SMB_SADFE, config->target_base + SMB_SnDFPCTL);
}
}
if (target_status & SMB_SDS) {
if (target_status & SMB_RCS) {
/* Target shared FIFO mode */
@ -593,6 +625,8 @@ static void target_i2c_isr_pio(const struct device *dev)
sndfpctl = sys_read8(config->target_base + SMB_SnDFPCTL);
sys_write8(sndfpctl | SMB_SADFE,
config->target_base + SMB_SnDFPCTL);
/* Write to clear data status of target */
clear_target_status(dev, SMB_SDS);
} else {
/* Host receiving, target transmitting */
if (!data->r_index) {
@ -620,44 +654,14 @@ static void target_i2c_isr_pio(const struct device *dev)
/* Read data */
val = sys_read8(config->target_base + SMB_SLDn);
if (target_cb->write_received) {
ret = target_cb->write_received(target_cfg, val);
if (!ret) {
/* Release clock pin */
val = sys_read8(config->target_base + SMB_SLDn);
}
target_cb->write_received(target_cfg, val);
}
/* Release target clock stretch */
sys_write8(sys_read8(config->target_base + SMB_SLVCTLn) | SMB_RSCS,
config->target_base + SMB_SLVCTLn);
data->w_index++;
}
}
/* Stop condition, indicate stop condition detected. */
if (target_status & SMB_SPDS) {
/* Transfer done callback function */
if (target_cb->stop) {
target_cb->stop(target_cfg);
}
data->w_index = 0;
data->r_index = 0;
if (config->target_shared_fifo_mode) {
uint8_t sdfpctl;
/* Disable FIFO mode to clear left count */
sdfpctl = sys_read8(config->target_base + SMB_SnDFPCTL);
sys_write8(sdfpctl & ~SMB_SADFE, config->target_base + SMB_SnDFPCTL);
}
}
done:
sys_write8(sys_read8(config->target_base + SMB_SLVCTLn) | SMB_RSCS,
config->target_base + SMB_SLVCTLn);
/* W/C */
#ifdef CONFIG_SOC_IT51526AW
sys_write8(target_status, config->i2cbase_mapping + SMB_SLSTA(config->port));
#else
sys_write8(target_status, config->target_base + SMB_SLSTn);
#endif
}
static void target_i2c_isr(const struct device *dev)