From 659f47a82486d27f579f57d067a4d2de6ea48bfa Mon Sep 17 00:00:00 2001 From: Jacob Dahl Date: Wed, 5 Aug 2026 20:43:40 -0600 Subject: [PATCH] arch/arm/stm32h7/i2c: use per-instance RCC registers for clock and reset stm32_i2c_init() and stm32_i2c_deinit() hardcoded APB1LENR/APB1LRSTR while taking the enable and reset bits from the per-instance config. That is correct for I2C1-3, but I2C4 is on APB4: its clk_bit and reset_bit are RCC_APB4ENR_I2C4EN and RCC_APB4RSTR_I2C4RST, both bit 7, and bit 7 of APB1LENR/APB1LRSTR is TIM13. So for I2C4 the driver enabled and pulsed the reset of TIM13 instead, and never reset the I2C4 peripheral at all. I2C4 still works because rcc_enableapb4() enables I2C4EN at boot, but the peripheral reset that stm32_i2c_reset() (CONFIG_I2C_RESET) relies on to clear a wedged I2C state machine never happens, and deinit gates TIM13 while leaving the I2C4 clock running. Store the clock enable and reset register addresses in struct stm32_i2c_config_s next to the bits, and use them in stm32_i2c_init() and stm32_i2c_deinit(). Signed-off-by: Jacob Dahl --- arch/arm/src/stm32h7/stm32_i2c.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/arm/src/stm32h7/stm32_i2c.c b/arch/arm/src/stm32h7/stm32_i2c.c index e01dd136a21..65eb3df23e1 100644 --- a/arch/arm/src/stm32h7/stm32_i2c.c +++ b/arch/arm/src/stm32h7/stm32_i2c.c @@ -374,7 +374,9 @@ struct stm32_trace_s struct stm32_i2c_config_s { uint32_t base; /* I2C base address */ + uint32_t clk_reg; /* Clock enable register */ uint32_t clk_bit; /* Clock enable bit */ + uint32_t rst_reg; /* Peripheral reset register */ uint32_t reset_bit; /* Reset bit */ uint32_t scl_pin; /* GPIO configuration for SCL as SCL */ uint32_t sda_pin; /* GPIO configuration for SDA as SDA */ @@ -492,7 +494,9 @@ static int stm32_i2c_pm_prepare(struct pm_callback_s *cb, int domain, static const struct stm32_i2c_config_s stm32_i2c1_config = { .base = STM32_I2C1_BASE, + .clk_reg = STM32_RCC_APB1LENR, .clk_bit = RCC_APB1LENR_I2C1EN, + .rst_reg = STM32_RCC_APB1LRSTR, .reset_bit = RCC_APB1LRSTR_I2C1RST, .scl_pin = GPIO_I2C1_SCL, .sda_pin = GPIO_I2C1_SDA, @@ -528,7 +532,9 @@ static struct stm32_i2c_priv_s stm32_i2c1_priv = static const struct stm32_i2c_config_s stm32_i2c2_config = { .base = STM32_I2C2_BASE, + .clk_reg = STM32_RCC_APB1LENR, .clk_bit = RCC_APB1LENR_I2C2EN, + .rst_reg = STM32_RCC_APB1LRSTR, .reset_bit = RCC_APB1LRSTR_I2C2RST, .scl_pin = GPIO_I2C2_SCL, .sda_pin = GPIO_I2C2_SDA, @@ -564,7 +570,9 @@ static struct stm32_i2c_priv_s stm32_i2c2_priv = static const struct stm32_i2c_config_s stm32_i2c3_config = { .base = STM32_I2C3_BASE, + .clk_reg = STM32_RCC_APB1LENR, .clk_bit = RCC_APB1LENR_I2C3EN, + .rst_reg = STM32_RCC_APB1LRSTR, .reset_bit = RCC_APB1LRSTR_I2C3RST, .scl_pin = GPIO_I2C3_SCL, .sda_pin = GPIO_I2C3_SDA, @@ -600,7 +608,9 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv = static const struct stm32_i2c_config_s stm32_i2c4_config = { .base = STM32_I2C4_BASE, + .clk_reg = STM32_RCC_APB4ENR, .clk_bit = RCC_APB4ENR_I2C4EN, + .rst_reg = STM32_RCC_APB4RSTR, .reset_bit = RCC_APB4RSTR_I2C4RST, .scl_pin = GPIO_I2C4_SCL, .sda_pin = GPIO_I2C4_SDA, @@ -2143,9 +2153,9 @@ static int stm32_i2c_init(struct stm32_i2c_priv_s *priv) /* Enable power and reset the peripheral */ - modifyreg32(STM32_RCC_APB1LENR, 0, priv->config->clk_bit); - modifyreg32(STM32_RCC_APB1LRSTR, 0, priv->config->reset_bit); - modifyreg32(STM32_RCC_APB1LRSTR, priv->config->reset_bit, 0); + modifyreg32(priv->config->clk_reg, 0, priv->config->clk_bit); + modifyreg32(priv->config->rst_reg, 0, priv->config->reset_bit); + modifyreg32(priv->config->rst_reg, priv->config->reset_bit, 0); /* Configure pins */ @@ -2213,7 +2223,7 @@ static int stm32_i2c_deinit(struct stm32_i2c_priv_s *priv) /* Disable clocking */ - modifyreg32(STM32_RCC_APB1LENR, priv->config->clk_bit, 0); + modifyreg32(priv->config->clk_reg, priv->config->clk_bit, 0); return OK; }