Factor out runtime PM and hardware initialization into separate function
in order have a cleaner error unwinding in the probe function.

Signed-off-by: Dmitry Osipenko <[email protected]>
---
 drivers/i2c/busses/i2c-tegra.c | 68 +++++++++++++++++++---------------
 1 file changed, 38 insertions(+), 30 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 8e4e72dec6ea..6e5af03d0b1d 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -1670,6 +1670,37 @@ static void tegra_i2c_release_clocks(struct 
tegra_i2c_dev *i2c_dev)
        clk_bulk_unprepare(i2c_dev->nclocks, i2c_dev->clocks);
 }
 
+static int tegra_i2c_init_runtime_pm_and_hardware(struct tegra_i2c_dev 
*i2c_dev)
+{
+       int ret;
+
+       /*
+        * VI I2C is in VE power domain which is not always on and not
+        * an IRQ safe. So, IRQ safe device can't be attached to a non-IRQ
+        * safe domain as it prevents powering off the PM domain.
+        * Also, VI I2C device don't need to use runtime IRQ safe as it will
+        * not be used for atomic transfers.
+        */
+       if (!i2c_dev->is_vi)
+               pm_runtime_irq_safe(i2c_dev->dev);
+
+       pm_runtime_enable(i2c_dev->dev);
+
+       ret = pm_runtime_get_sync(i2c_dev->dev);
+       if (ret < 0) {
+               dev_err(i2c_dev->dev, "runtime resume failed: %d\n", ret);
+               pm_runtime_disable(i2c_dev->dev);
+               return ret;
+       }
+
+       /* initialize hardware state */
+       ret = tegra_i2c_init(i2c_dev);
+
+       pm_runtime_put(i2c_dev->dev);
+
+       return ret;
+}
+
 static int tegra_i2c_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1728,41 +1759,23 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, i2c_dev);
 
-       /*
-        * VI I2C is in VE power domain which is not always on and not
-        * an IRQ safe. So, IRQ safe device can't be attached to a non-IRQ
-        * safe domain as it prevents powering off the PM domain.
-        * Also, VI I2C device don't need to use runtime IRQ safe as it will
-        * not be used for atomic transfers.
-        */
-       if (!i2c_dev->is_vi)
-               pm_runtime_irq_safe(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_get_sync(i2c_dev->dev);
-       if (ret < 0) {
-               dev_err(dev, "runtime resume failed\n");
-               goto disable_rpm;
-       }
-
        if (i2c_dev->hw->supports_bus_clear)
                i2c_dev->adapter.bus_recovery_info = &tegra_i2c_recovery_info;
 
        ret = tegra_i2c_init_dma(i2c_dev);
        if (ret < 0)
-               goto put_rpm;
+               goto release_clocks;
 
-       ret = tegra_i2c_init(i2c_dev);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
+       ret = tegra_i2c_init_runtime_pm_and_hardware(i2c_dev);
+       if (ret)
                goto release_dma;
-       }
 
        irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
 
        ret = devm_request_irq(&pdev->dev, i2c_dev->irq, tegra_i2c_isr,
                               IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c_dev);
        if (ret)
-               goto release_dma;
+               goto release_rpm;
 
        i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
        i2c_dev->adapter.owner = THIS_MODULE;
@@ -1777,18 +1790,13 @@ static int tegra_i2c_probe(struct platform_device *pdev)
        if (ret)
                goto release_dma;
 
-       pm_runtime_put(&pdev->dev);
-
        return 0;
 
+release_rpm:
+       pm_runtime_disable(i2c_dev->dev);
 release_dma:
        tegra_i2c_release_dma(i2c_dev);
-
-put_rpm:
-       pm_runtime_put_sync(&pdev->dev);
-
-disable_rpm:
-       pm_runtime_disable(&pdev->dev);
+release_clocks:
        tegra_i2c_release_clocks(i2c_dev);
 
        return ret;
-- 
2.27.0

Reply via email to