i2c: tegra: Allocate DMA memory for DMA engine
authorThierry Reding <treding@nvidia.com>
Thu, 20 Oct 2022 14:39:33 +0000 (16:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 26 Nov 2022 08:24:31 +0000 (09:24 +0100)
[ Upstream commit cdbf26251d3b35c4ccaea0c3a6de4318f727d3d2 ]

When the I2C controllers are running in DMA mode, it is the DMA engine
that performs the memory accesses rather than the I2C controller. Pass
the DMA engine's struct device pointer to the DMA API to make sure the
correct DMA operations are used.

This fixes an issue where the DMA engine's SMMU stream ID needs to be
misleadingly set for the I2C controllers in device tree.

Suggested-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/i2c/busses/i2c-tegra.c

index c883044..444867c 100644 (file)
@@ -283,6 +283,7 @@ struct tegra_i2c_dev {
        struct dma_chan *tx_dma_chan;
        struct dma_chan *rx_dma_chan;
        unsigned int dma_buf_size;
+       struct device *dma_dev;
        dma_addr_t dma_phys;
        void *dma_buf;
 
@@ -419,7 +420,7 @@ static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
 static void tegra_i2c_release_dma(struct tegra_i2c_dev *i2c_dev)
 {
        if (i2c_dev->dma_buf) {
-               dma_free_coherent(i2c_dev->dev, i2c_dev->dma_buf_size,
+               dma_free_coherent(i2c_dev->dma_dev, i2c_dev->dma_buf_size,
                                  i2c_dev->dma_buf, i2c_dev->dma_phys);
                i2c_dev->dma_buf = NULL;
        }
@@ -466,10 +467,13 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
 
        i2c_dev->tx_dma_chan = chan;
 
+       WARN_ON(i2c_dev->tx_dma_chan->device != i2c_dev->rx_dma_chan->device);
+       i2c_dev->dma_dev = chan->device->dev;
+
        i2c_dev->dma_buf_size = i2c_dev->hw->quirks->max_write_len +
                                I2C_PACKET_HEADER_SIZE;
 
-       dma_buf = dma_alloc_coherent(i2c_dev->dev, i2c_dev->dma_buf_size,
+       dma_buf = dma_alloc_coherent(i2c_dev->dma_dev, i2c_dev->dma_buf_size,
                                     &dma_phys, GFP_KERNEL | __GFP_NOWARN);
        if (!dma_buf) {
                dev_err(i2c_dev->dev, "failed to allocate DMA buffer\n");
@@ -1255,7 +1259,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
        if (i2c_dev->dma_mode) {
                if (i2c_dev->msg_read) {
-                       dma_sync_single_for_device(i2c_dev->dev,
+                       dma_sync_single_for_device(i2c_dev->dma_dev,
                                                   i2c_dev->dma_phys,
                                                   xfer_size, DMA_FROM_DEVICE);
 
@@ -1263,7 +1267,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                        if (err)
                                return err;
                } else {
-                       dma_sync_single_for_cpu(i2c_dev->dev,
+                       dma_sync_single_for_cpu(i2c_dev->dma_dev,
                                                i2c_dev->dma_phys,
                                                xfer_size, DMA_TO_DEVICE);
                }
@@ -1276,7 +1280,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                        memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE,
                               msg->buf, msg->len);
 
-                       dma_sync_single_for_device(i2c_dev->dev,
+                       dma_sync_single_for_device(i2c_dev->dma_dev,
                                                   i2c_dev->dma_phys,
                                                   xfer_size, DMA_TO_DEVICE);
 
@@ -1327,7 +1331,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                }
 
                if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) {
-                       dma_sync_single_for_cpu(i2c_dev->dev,
+                       dma_sync_single_for_cpu(i2c_dev->dma_dev,
                                                i2c_dev->dma_phys,
                                                xfer_size, DMA_FROM_DEVICE);