From 648919f6df3da46e00a3f9c3fee33a9d4f81d904 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Thu, 3 Jul 2025 17:48:33 +0800 Subject: [PATCH] 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 --- drivers/i2c/i2c_ite_it51xxx.c | 76 ++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/drivers/i2c/i2c_ite_it51xxx.c b/drivers/i2c/i2c_ite_it51xxx.c index 96d76746279..3b655293815 100644 --- a/drivers/i2c/i2c_ite_it51xxx.c +++ b/drivers/i2c/i2c_ite_it51xxx.c @@ -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)