| From 0c21d02ca469574d2082379db52d1a27b99eed0c Mon Sep 17 00:00:00 2001 |
| From: Alain Volmat <alain.volmat@foss.st.com> |
| Date: Mon, 20 Sep 2021 17:21:29 +0200 |
| Subject: i2c: stm32f7: flush TX FIFO upon transfer errors |
| |
| From: Alain Volmat <alain.volmat@foss.st.com> |
| |
| commit 0c21d02ca469574d2082379db52d1a27b99eed0c upstream. |
| |
| While handling an error during transfer (ex: NACK), it could |
| happen that the driver has already written data into TXDR |
| before the transfer get stopped. |
| This commit add TXDR Flush after end of transfer in case of error to |
| avoid sending a wrong data on any other slave upon next transfer. |
| |
| Fixes: aeb068c57214 ("i2c: i2c-stm32f7: add driver") |
| Signed-off-by: Alain Volmat <alain.volmat@foss.st.com> |
| Reviewed-by: Pierre-Yves MORDRET <pierre-yves.mordret@foss.st.com> |
| Signed-off-by: Wolfram Sang <wsa@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/i2c/busses/i2c-stm32f7.c | 20 +++++++++++++++++++- |
| 1 file changed, 19 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/i2c/busses/i2c-stm32f7.c |
| +++ b/drivers/i2c/busses/i2c-stm32f7.c |
| @@ -1665,6 +1665,16 @@ static int stm32f7_i2c_xfer(struct i2c_a |
| time_left = wait_for_completion_timeout(&i2c_dev->complete, |
| i2c_dev->adap.timeout); |
| ret = f7_msg->result; |
| + if (ret) { |
| + /* |
| + * It is possible that some unsent data have already been |
| + * written into TXDR. To avoid sending old data in a |
| + * further transfer, flush TXDR in case of any error |
| + */ |
| + writel_relaxed(STM32F7_I2C_ISR_TXE, |
| + i2c_dev->base + STM32F7_I2C_ISR); |
| + goto pm_free; |
| + } |
| |
| if (!time_left) { |
| dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n", |
| @@ -1713,8 +1723,16 @@ static int stm32f7_i2c_smbus_xfer(struct |
| timeout = wait_for_completion_timeout(&i2c_dev->complete, |
| i2c_dev->adap.timeout); |
| ret = f7_msg->result; |
| - if (ret) |
| + if (ret) { |
| + /* |
| + * It is possible that some unsent data have already been |
| + * written into TXDR. To avoid sending old data in a |
| + * further transfer, flush TXDR in case of any error |
| + */ |
| + writel_relaxed(STM32F7_I2C_ISR_TXE, |
| + i2c_dev->base + STM32F7_I2C_ISR); |
| goto pm_free; |
| + } |
| |
| if (!timeout) { |
| dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); |