drivers: i2c_ll_stm32_v1: Reset i2c device on read/write error
Reset the i2c device when read or write return with an error code. This is to bring the i2c hardware back into a known state after a hardware error (like EMC spikes) caused the device to lock up. Signed-off-by: Erwin Rol <erwin@erwinrol.com>
This commit is contained in:
parent
9ac8dcf5a7
commit
dce9580490
|
@ -66,6 +66,8 @@ static void stm32_i2c_enable_transfer_interrupts(struct device *dev)
|
||||||
LL_I2C_EnableIT_BUF(i2c);
|
LL_I2C_EnableIT_BUF(i2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_I2C_STM32_INTERRUPT */
|
||||||
|
|
||||||
static void stm32_i2c_reset(struct device *dev)
|
static void stm32_i2c_reset(struct device *dev)
|
||||||
{
|
{
|
||||||
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
|
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
|
||||||
|
@ -77,7 +79,9 @@ static void stm32_i2c_reset(struct device *dev)
|
||||||
|
|
||||||
/* disable i2c and disable IRQ's */
|
/* disable i2c and disable IRQ's */
|
||||||
LL_I2C_Disable(i2c);
|
LL_I2C_Disable(i2c);
|
||||||
|
#ifdef CONFIG_I2C_STM32_INTERRUPT
|
||||||
stm32_i2c_disable_transfer_interrupts(dev);
|
stm32_i2c_disable_transfer_interrupts(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* save all important registers before reset */
|
/* save all important registers before reset */
|
||||||
cr1 = LL_I2C_ReadReg(i2c, CR1);
|
cr1 = LL_I2C_ReadReg(i2c, CR1);
|
||||||
|
@ -109,7 +113,6 @@ static void stm32_i2c_reset(struct device *dev)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_I2C_STM32_INTERRUPT */
|
|
||||||
|
|
||||||
static void stm32_i2c_master_finish(struct device *dev)
|
static void stm32_i2c_master_finish(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@ -714,6 +717,7 @@ int32_t stm32_i2c_msg_write(struct device *dev, struct i2c_msg *msg,
|
||||||
uint32_t len = msg->len;
|
uint32_t len = msg->len;
|
||||||
uint16_t timeout;
|
uint16_t timeout;
|
||||||
uint8_t *buf = msg->buf;
|
uint8_t *buf = msg->buf;
|
||||||
|
int32_t res;
|
||||||
|
|
||||||
msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_WRITE);
|
msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_WRITE);
|
||||||
|
|
||||||
|
@ -794,7 +798,12 @@ int32_t stm32_i2c_msg_write(struct device *dev, struct i2c_msg *msg,
|
||||||
|
|
||||||
end:
|
end:
|
||||||
check_errors(dev, __func__);
|
check_errors(dev, __func__);
|
||||||
return msg_end(dev, next_msg_flags, __func__);
|
res = msg_end(dev, next_msg_flags, __func__);
|
||||||
|
if (res < 0) {
|
||||||
|
stm32_i2c_reset(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
|
int32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
|
||||||
|
@ -806,6 +815,7 @@ int32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
|
||||||
uint32_t len = msg->len;
|
uint32_t len = msg->len;
|
||||||
uint16_t timeout;
|
uint16_t timeout;
|
||||||
uint8_t *buf = msg->buf;
|
uint8_t *buf = msg->buf;
|
||||||
|
int32_t res;
|
||||||
|
|
||||||
msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_READ);
|
msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_READ);
|
||||||
|
|
||||||
|
@ -950,7 +960,12 @@ int32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
check_errors(dev, __func__);
|
check_errors(dev, __func__);
|
||||||
return msg_end(dev, next_msg_flags, __func__);
|
res = msg_end(dev, next_msg_flags, __func__);
|
||||||
|
if (res < 0) {
|
||||||
|
stm32_i2c_reset(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_I2C_STM32_INTERRUPT */
|
#endif /* CONFIG_I2C_STM32_INTERRUPT */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue