From 010bde8db69dbe78328fe46b54febe3f9f5a91e7 Mon Sep 17 00:00:00 2001 From: Christoph Boese Date: Tue, 17 Feb 2026 02:04:17 +0100 Subject: [PATCH] i2c: imx: Avoid deadlock between clk_prepare_lock and i2c bus lock During deferred probing, clock registration can call into i2c (e.g. via pcf85063_clkout_recalc_rate() using regmap_i2c_read()) while the I2C bus lock is held. In parallel, the i.MX I2C transfer path calls clk_get_rate() from i2c_imx_start() while holding the same bus lock. clk_get_rate() takes clk_prepare_lock, which can already be held by the clock framework while invoking notifiers. This results in an ABBA deadlock between clk_prepare_lock and the I2C bus lock, stalling deferred probe. This patch fixes the issue by caching the clock rate in the notifier callback and removing the `clk_get_rate()` call from the transfer path. Signed-off-by: Christoph Boese --- drivers/i2c/busses/i2c-imx.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index e5da0588fa7ce..fbc9a5dffa501 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -265,6 +265,7 @@ struct imx_i2c_struct { int stopped; unsigned int ifdr; /* IMX_I2C_IFDR */ unsigned int cur_clk; + unsigned int clk_rate; unsigned int bitrate; const struct imx_i2c_hwdata *hwdata; struct i2c_bus_recovery_info rinfo; @@ -711,8 +712,10 @@ static int i2c_imx_clk_notifier_call(struct notifier_block *nb, struct imx_i2c_struct, clk_change_nb); - if (action & POST_RATE_CHANGE) + if (action & POST_RATE_CHANGE) { + WRITE_ONCE(i2c_imx->clk_rate, ndata->new_rate); ret = i2c_imx_set_clk(i2c_imx, ndata->new_rate); + } return notifier_from_errno(ret); } @@ -722,7 +725,11 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool atomic) unsigned int temp = 0; int result; - result = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); + if (!READ_ONCE(i2c_imx->clk_rate)) + return -EINVAL; + + result = i2c_imx_set_clk(i2c_imx, READ_ONCE(i2c_imx->clk_rate)); + if (result) return result; @@ -1763,7 +1770,8 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->bitrate = pdata->bitrate; i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call; clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb); - ret = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); + WRITE_ONCE(i2c_imx->clk_rate, clk_get_rate(i2c_imx->clk)); + ret = i2c_imx_set_clk(i2c_imx, READ_ONCE(i2c_imx->clk_rate)); if (ret < 0) { dev_err(&pdev->dev, "can't get I2C clock\n"); goto clk_notifier_unregister; @@ -1875,6 +1883,13 @@ static int __maybe_unused i2c_imx_runtime_resume(struct device *dev) ret = clk_prepare_enable(i2c_imx->clk); if (ret) dev_err(dev, "can't enable I2C clock, ret=%d\n", ret); + else { + i2c_imx->cur_clk = 0; + WRITE_ONCE(i2c_imx->clk_rate, clk_get_rate(i2c_imx->clk)); + ret = i2c_imx_set_clk(i2c_imx, READ_ONCE(i2c_imx->clk_rate)); + if (ret) + dev_err(dev, "can't set I2C clock, ret=%d\n", ret); + } return ret; }