We should not mix managed calls with non-managed. This will break the calls order at the error path and ->remove() stages. Fix this by wrapping reset control to become managed one. With that start checking the rerurn code from reset_control_deassert() as it may fail and calling assertion in that scenario is not always a good idea. Reviewed-by: Andi Shyti <andi.shyti@xxxxxxxxxx> Tested-by: Serge Semin <fancer.lancer@xxxxxxxxx> Acked-by: Jarkko Nikula <jarkko.nikula@xxxxxxxxxxxxxxx> Link: https://lore.kernel.org/r/20231120144641.1660574-3-andriy.shevchenko@xxxxxxxxxxxxxxx Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> --- drivers/i2c/busses/i2c-designware-platdrv.c | 62 +++++++++++---------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index fd3cd65f9c88..648fb84e574d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -285,6 +285,28 @@ static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev); } +static void dw_i2c_plat_assert_reset(void *data) +{ + struct dw_i2c_dev *dev = data; + + reset_control_assert(dev->rst); +} + +static int dw_i2c_plat_get_reset(struct dw_i2c_dev *dev) +{ + int ret; + + dev->rst = devm_reset_control_get_optional_exclusive(dev->dev, NULL); + if (IS_ERR(dev->rst)) + return PTR_ERR(dev->rst); + + ret = reset_control_deassert(dev->rst); + if (ret) + return ret; + + return devm_add_action_or_reset(dev->dev, dw_i2c_plat_assert_reset, dev); +} + static int dw_i2c_plat_probe(struct platform_device *pdev) { struct i2c_adapter *adap; @@ -312,11 +334,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (ret) return ret; - dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(dev->rst)) - return PTR_ERR(dev->rst); - - reset_control_deassert(dev->rst); + ret = dw_i2c_plat_get_reset(dev); + if (ret) + return ret; t = &dev->timings; i2c_parse_fw_timings(&pdev->dev, t, false); @@ -331,30 +351,26 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ret = i2c_dw_validate_speed(dev); if (ret) - goto exit_reset; + return ret; ret = i2c_dw_probe_lock_support(dev); if (ret) - goto exit_reset; + return ret; i2c_dw_configure(dev); /* Optional interface clock */ dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk"); - if (IS_ERR(dev->pclk)) { - ret = PTR_ERR(dev->pclk); - goto exit_reset; - } + if (IS_ERR(dev->pclk)) + return PTR_ERR(dev->pclk); dev->clk = devm_clk_get_optional(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) { - ret = PTR_ERR(dev->clk); - goto exit_reset; - } + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); ret = i2c_dw_prepare_clk(dev, true); if (ret) - goto exit_reset; + return ret; if (dev->clk) { u64 clk_khz; @@ -395,17 +411,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ret = dw_i2c_plat_pm_setup(dev); if (ret) - goto exit_reset; + return ret; - ret = i2c_dw_probe(dev); - if (ret) - goto exit_reset; - - return ret; - -exit_reset: - reset_control_assert(dev->rst); - return ret; + return i2c_dw_probe(dev); } static void dw_i2c_plat_remove(struct platform_device *pdev) @@ -422,8 +430,6 @@ static void dw_i2c_plat_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); i2c_dw_remove_lock_support(dev); - - reset_control_assert(dev->rst); } static int dw_i2c_plat_prepare(struct device *dev) -- 2.43.0.rc1.1.gbec44491f096