Skip to content

Commit e244450

Browse files
Jean Nanchennashif
authored andcommitted
drivers: i2c: stm32: add timeout to avoid infinite loop
Fix issue where STM32 I2C LL driver could block forever when SDA and SCL are shorted and interrupts are disabled (CONFIG_I2C_STM32_INTERRUPT=n). Added timeouts to all blocking wait loops in the STM32 LL I2C driver to avoid indefinite blocking. Fixes #88506 Signed-off-by: Jean Nanchen <[email protected]> (cherry picked from commit 2066b8c)
1 parent b45ca8d commit e244450

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

drivers/i2c/i2c_ll_stm32_v2.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,17 +736,26 @@ static inline int msg_done(const struct device *dev,
736736
{
737737
const struct i2c_stm32_config *cfg = dev->config;
738738
I2C_TypeDef *i2c = cfg->i2c;
739+
int64_t start_time = k_uptime_get();
739740

740741
/* Wait for transfer to complete */
741742
while (!LL_I2C_IsActiveFlag_TC(i2c) && !LL_I2C_IsActiveFlag_TCR(i2c)) {
742743
if (check_errors(dev, __func__)) {
743744
return -EIO;
744745
}
746+
if ((k_uptime_get() - start_time) >
747+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
748+
return -ETIMEDOUT;
749+
}
745750
}
746751
/* Issue stop condition if necessary */
747752
if (current_msg_flags & I2C_MSG_STOP) {
748753
LL_I2C_GenerateStopCondition(i2c);
749754
while (!LL_I2C_IsActiveFlag_STOP(i2c)) {
755+
if ((k_uptime_get() - start_time) >
756+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
757+
return -ETIMEDOUT;
758+
}
750759
}
751760

752761
LL_I2C_ClearFlag_STOP(i2c);
@@ -763,6 +772,7 @@ static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
763772
I2C_TypeDef *i2c = cfg->i2c;
764773
unsigned int len = 0U;
765774
uint8_t *buf = msg->buf;
775+
int64_t start_time = k_uptime_get();
766776

767777
msg_init(dev, msg, next_msg_flags, slave, LL_I2C_REQUEST_WRITE);
768778

@@ -776,6 +786,11 @@ static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
776786
if (check_errors(dev, __func__)) {
777787
return -EIO;
778788
}
789+
790+
if ((k_uptime_get() - start_time) >
791+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
792+
return -ETIMEDOUT;
793+
}
779794
}
780795

781796
LL_I2C_TransmitData8(i2c, *buf);
@@ -793,6 +808,7 @@ static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
793808
I2C_TypeDef *i2c = cfg->i2c;
794809
unsigned int len = 0U;
795810
uint8_t *buf = msg->buf;
811+
int64_t start_time = k_uptime_get();
796812

797813
msg_init(dev, msg, next_msg_flags, slave, LL_I2C_REQUEST_READ);
798814

@@ -802,6 +818,10 @@ static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
802818
if (check_errors(dev, __func__)) {
803819
return -EIO;
804820
}
821+
if ((k_uptime_get() - start_time) >
822+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
823+
return -ETIMEDOUT;
824+
}
805825
}
806826

807827
*buf = LL_I2C_ReceiveData8(i2c);
@@ -1172,5 +1192,26 @@ int stm32_i2c_transaction(const struct device *dev,
11721192
msg.len = rest;
11731193
} while (rest > 0U);
11741194

1195+
#ifndef CONFIG_I2C_STM32_INTERRUPT
1196+
struct i2c_stm32_data *data = dev->data;
1197+
1198+
if (ret == -ETIMEDOUT) {
1199+
if (LL_I2C_IsEnabledReloadMode(i2c)) {
1200+
LL_I2C_DisableReloadMode(i2c);
1201+
}
1202+
#if defined(CONFIG_I2C_TARGET)
1203+
data->master_active = false;
1204+
if (!data->slave_attached && !data->smbalert_active) {
1205+
LL_I2C_Disable(i2c);
1206+
}
1207+
#else
1208+
if (!data->smbalert_active) {
1209+
LL_I2C_Disable(i2c);
1210+
}
1211+
#endif
1212+
return -EIO;
1213+
}
1214+
#endif /* !CONFIG_I2C_STM32_INTERRUPT */
1215+
11751216
return ret;
11761217
}

0 commit comments

Comments
 (0)