i2c: imx: support DMA defer probing
authorCarlos Song <carlos.song@nxp.com>
Thu, 26 Dec 2024 06:25:21 +0000 (14:25 +0800)
committerAndi Shyti <andi.shyti@kernel.org>
Tue, 7 Jan 2025 22:46:10 +0000 (23:46 +0100)
Return -EPROBE_DEFER when dma_request_slave_channel() because DMA driver
have not ready yet.

Move i2c_imx_dma_request() before registering I2C adapter to avoid
infinite loop of .probe() calls to the same driver, see "e8c220fac415
Revert "i2c: imx: improve the error handling in i2c_imx_dma_request()""
and "Documentation/driver-api/driver-model/driver.rst".

Use CPU mode to avoid stuck registering i2c adapter when DMA resources
are unavailable.

Signed-off-by: Carlos Song <carlos.song@nxp.com>
Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Link: https://lore.kernel.org/r/20241226062521.1004809-1-carlos.song@nxp.com
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
drivers/i2c/busses/i2c-imx.c

index 1f441227bfdcb5af8b882db6985a8fed3af304ca..ee0d25b498cb2c4f0eae39cf87d9bf67ef965075 100644 (file)
@@ -397,17 +397,16 @@ static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
 }
 
 /* Functions for DMA support */
-static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
-                                               dma_addr_t phy_addr)
+static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma_addr_t phy_addr)
 {
        struct imx_i2c_dma *dma;
        struct dma_slave_config dma_sconfig;
-       struct device *dev = &i2c_imx->adapter.dev;
+       struct device *dev = i2c_imx->adapter.dev.parent;
        int ret;
 
        dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
        if (!dma)
-               return;
+               return -ENOMEM;
 
        dma->chan_tx = dma_request_chan(dev, "tx");
        if (IS_ERR(dma->chan_tx)) {
@@ -452,7 +451,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
        dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
                dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
 
-       return;
+       return 0;
 
 fail_rx:
        dma_release_channel(dma->chan_rx);
@@ -460,6 +459,8 @@ fail_tx:
        dma_release_channel(dma->chan_tx);
 fail_al:
        devm_kfree(dev, dma);
+
+       return ret;
 }
 
 static void i2c_imx_dma_callback(void *arg)
@@ -1802,6 +1803,22 @@ static int i2c_imx_probe(struct platform_device *pdev)
        if (ret == -EPROBE_DEFER)
                goto clk_notifier_unregister;
 
+       /*
+        * DMA mode should be optional for I2C, when encountering DMA errors,
+        * no need to exit I2C probe. Only print warning to show DMA error and
+        * use PIO mode directly to ensure I2C bus available as much as possible.
+        */
+       ret = i2c_imx_dma_request(i2c_imx, phy_addr);
+       if (ret) {
+               if (ret == -EPROBE_DEFER)
+                       goto clk_notifier_unregister;
+               else if (ret == -ENODEV)
+                       dev_dbg(&pdev->dev, "Only use PIO mode\n");
+               else
+                       dev_warn(&pdev->dev, "Failed to setup DMA (%pe), only use PIO mode\n",
+                                ERR_PTR(ret));
+       }
+
        /* Add I2C adapter */
        ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
        if (ret < 0)
@@ -1816,9 +1833,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
                i2c_imx->adapter.name);
        dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
 
-       /* Init DMA config if supported */
-       i2c_imx_dma_request(i2c_imx, phy_addr);
-
        return 0;   /* Return OK */
 
 clk_notifier_unregister: