[PATCH v4 11/31] i2c: tegra: Factor out runtime PM and hardware initialization

Dmitry Osipenko
2020-09-05T20:46:37Z

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 <digetx@gmail.com>
---
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