| From 31b90a95ccbbb4b628578ac17e3b3cc8eeacfe31 Mon Sep 17 00:00:00 2001 |
| From: Alain Volmat <alain.volmat@foss.st.com> |
| Date: Mon, 20 Sep 2021 17:21:31 +0200 |
| Subject: i2c: stm32f7: stop dma transfer in case of NACK |
| |
| From: Alain Volmat <alain.volmat@foss.st.com> |
| |
| commit 31b90a95ccbbb4b628578ac17e3b3cc8eeacfe31 upstream. |
| |
| In case of receiving a NACK, the dma transfer should be stopped |
| to avoid feeding data into the FIFO. |
| Also ensure to properly return the proper error code and avoid |
| waiting for the end of the dma completion in case of |
| error happening during the transmission. |
| |
| Fixes: 7ecc8cfde553 ("i2c: i2c-stm32f7: Add DMA support") |
| 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 | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/i2c/busses/i2c-stm32f7.c |
| +++ b/drivers/i2c/busses/i2c-stm32f7.c |
| @@ -1472,6 +1472,7 @@ static irqreturn_t stm32f7_i2c_isr_event |
| { |
| struct stm32f7_i2c_dev *i2c_dev = data; |
| struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; |
| + struct stm32_i2c_dma *dma = i2c_dev->dma; |
| void __iomem *base = i2c_dev->base; |
| u32 status, mask; |
| int ret = IRQ_HANDLED; |
| @@ -1497,6 +1498,10 @@ static irqreturn_t stm32f7_i2c_isr_event |
| dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", |
| __func__, f7_msg->addr); |
| writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); |
| + if (i2c_dev->use_dma) { |
| + stm32f7_i2c_disable_dma_req(i2c_dev); |
| + dmaengine_terminate_all(dma->chan_using); |
| + } |
| f7_msg->result = -ENXIO; |
| } |
| |
| @@ -1512,7 +1517,7 @@ static irqreturn_t stm32f7_i2c_isr_event |
| /* Clear STOP flag */ |
| writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); |
| |
| - if (i2c_dev->use_dma) { |
| + if (i2c_dev->use_dma && !f7_msg->result) { |
| ret = IRQ_WAKE_THREAD; |
| } else { |
| i2c_dev->master_mode = false; |
| @@ -1525,7 +1530,7 @@ static irqreturn_t stm32f7_i2c_isr_event |
| if (f7_msg->stop) { |
| mask = STM32F7_I2C_CR2_STOP; |
| stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); |
| - } else if (i2c_dev->use_dma) { |
| + } else if (i2c_dev->use_dma && !f7_msg->result) { |
| ret = IRQ_WAKE_THREAD; |
| } else if (f7_msg->smbus) { |
| stm32f7_i2c_smbus_rep_start(i2c_dev); |