From d1f112e2fa9b7f60f5dfa51118a0dad57fd3df88 Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Mon, 20 Jul 2026 16:53:26 +0800 Subject: [PATCH 1/8] i2c: busses: drop redundant dev_err_probe() around irq helpers platform_get_irq(), devm_request_irq() and devm_request_threaded_irq() already print an error message via dev_err_probe() on failure, so wrapping their return value with another dev_err_probe() results in duplicate error output. Drop these redundant dev_err_probe() calls across i2c bus drivers and return the error code directly instead. Signed-off-by: Pei Xiao Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/aea09858af6be39497325e2560267771ed62e6b0.1784537126.git.xiaopei01@kylinos.cn --- drivers/i2c/busses/i2c-amd-asf-plat.c | 4 ++-- drivers/i2c/busses/i2c-bcm-iproc.c | 3 +-- drivers/i2c/busses/i2c-gxp.c | 2 +- drivers/i2c/busses/i2c-hisi.c | 2 +- drivers/i2c/busses/i2c-imx-lpi2c.c | 2 +- drivers/i2c/busses/i2c-imx.c | 2 +- drivers/i2c/busses/i2c-k1.c | 4 ++-- drivers/i2c/busses/i2c-ls2x.c | 2 +- drivers/i2c/busses/i2c-microchip-corei2c.c | 3 +-- drivers/i2c/busses/i2c-mlxbf.c | 2 +- drivers/i2c/busses/i2c-nomadik.c | 3 +-- drivers/i2c/busses/i2c-qcom-geni.c | 3 +-- drivers/i2c/busses/i2c-riic.c | 3 +-- drivers/i2c/busses/i2c-rzv2m.c | 2 +- drivers/i2c/busses/i2c-sprd.c | 4 +--- drivers/i2c/busses/i2c-st.c | 3 +-- drivers/i2c/busses/i2c-stm32f4.c | 6 ++---- drivers/i2c/busses/i2c-stm32f7.c | 4 ++-- drivers/i2c/busses/i2c-sun6i-p2wi.c | 4 +--- drivers/i2c/busses/i2c-synquacer.c | 2 +- drivers/i2c/busses/i2c-uniphier-f.c | 2 +- drivers/i2c/busses/i2c-uniphier.c | 2 +- drivers/i2c/busses/i2c-viai2c-wmt.c | 3 +-- drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 3 +-- drivers/i2c/busses/i2c-xlp9xx.c | 2 +- 25 files changed, 29 insertions(+), 43 deletions(-) diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c index 5968953e483a..b0b40fe1d79b 100644 --- a/drivers/i2c/busses/i2c-amd-asf-plat.c +++ b/drivers/i2c/busses/i2c-amd-asf-plat.c @@ -337,11 +337,11 @@ static int amd_asf_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return dev_err_probe(dev, irq, "missing IRQ resources\n"); + return irq; ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev); if (ret) - return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq); + return ret; asf_dev->adap.owner = THIS_MODULE; asf_dev->adap.algo = &amd_asf_smbus_algorithm; diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 86ca4c2221c4..66bb3bfdaa4c 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1147,8 +1147,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) bcm_iproc_i2c_isr, 0, pdev->name, iproc_i2c); if (ret < 0) - return dev_err_probe(iproc_i2c->device, ret, - "unable to request irq %i\n", irq); + return ret; iproc_i2c->irq = irq; } else { diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c index f9a5465f52da..6a5cef7e4383 100644 --- a/drivers/i2c/busses/i2c-gxp.c +++ b/drivers/i2c/busses/i2c-gxp.c @@ -551,7 +551,7 @@ static int gxp_i2c_probe(struct platform_device *pdev) rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler, IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata); if (rc < 0) - return dev_err_probe(&pdev->dev, rc, "irq request failed\n"); + return rc; i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true); diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index 04d7978cae04..ba5c9579ae19 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -481,7 +481,7 @@ static int hisi_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, ctlr->irq, hisi_i2c_irq, 0, "hisi-i2c", ctlr); if (ret) - return dev_err_probe(dev, ret, "failed to request irq handler\n"); + return ret; ctlr->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); if (IS_ERR_OR_NULL(ctlr->clk)) { diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index e6c24a9d934d..1ad7a645ca9a 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -1513,7 +1513,7 @@ static int lpi2c_imx_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND, pdev->name, lpi2c_imx); if (ret) - return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", lpi2c_imx->irq); + return ret; i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx); platform_set_drvdata(pdev, lpi2c_imx); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 9477d814fde9..19ec056b00af 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1753,7 +1753,7 @@ static int i2c_imx_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return dev_err_probe(&pdev->dev, irq, "can't get IRQ\n"); + return irq; base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c index ee75eee15c10..4e1d67541132 100644 --- a/drivers/i2c/busses/i2c-k1.c +++ b/drivers/i2c/busses/i2c-k1.c @@ -852,7 +852,7 @@ static int spacemit_i2c_probe(struct platform_device *pdev) i2c->irq = platform_get_irq(pdev, 0); if (i2c->irq < 0) - return dev_err_probe(dev, i2c->irq, "failed to get irq resource"); + return i2c->irq; clk = devm_clk_get_enabled(dev, "func"); if (IS_ERR(clk)) @@ -906,7 +906,7 @@ static int spacemit_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler, IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c); if (ret) - return dev_err_probe(dev, ret, "failed to request irq"); + return ret; platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c index b475dd27b7af..af7bf61b0f4d 100644 --- a/drivers/i2c/busses/i2c-ls2x.c +++ b/drivers/i2c/busses/i2c-ls2x.c @@ -323,7 +323,7 @@ static int ls2x_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c", priv); if (ret < 0) - return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + return ret; return devm_i2c_add_adapter(dev, adap); } diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c index 330e150ef6d5..5a429f17359f 100644 --- a/drivers/i2c/busses/i2c-microchip-corei2c.c +++ b/drivers/i2c/busses/i2c-microchip-corei2c.c @@ -581,8 +581,7 @@ static int mchp_corei2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED, pdev->name, idev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "failed to claim irq %d\n", irq); + return ret; ret = clk_prepare_enable(idev->i2c_clk); if (ret) diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index e33512b25353..24ccc4546ab8 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -2350,7 +2350,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) IRQF_SHARED | IRQF_PROBE_SHARED, dev_name(dev), priv); if (ret < 0) - return dev_err_probe(dev, ret, "Cannot get irq %d\n", irq); + return ret; priv->irq = irq; diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 404709179d73..c3878670da9c 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1137,8 +1137,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) ret = devm_request_irq(dev, priv->irq, i2c_irq_handler, 0, DRIVER_NAME, priv); if (ret) - return dev_err_probe(dev, ret, - "cannot claim the irq %d\n", priv->irq); + return ret; priv->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(priv->clk)) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index dd488df45c4c..658636c1ee0e 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -1169,8 +1169,7 @@ static int geni_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN, dev_name(dev), gi2c); if (ret) - return dev_err_probe(dev, ret, - "Request_irq failed: %d\n", gi2c->irq); + return ret; i2c_set_adapdata(&gi2c->adap, gi2c); gi2c->adap.dev.parent = dev; diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 6d2ebf67dd62..2fa48219b66b 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -554,8 +554,7 @@ static int riic_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, irq_desc->isr, 0, irq_desc->name, riic); if (ret) - return dev_err_probe(dev, ret, "failed to request irq %s\n", - irq_desc->name); + return ret; } diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c index 4ba8eaa322e5..206a99e722a3 100644 --- a/drivers/i2c/busses/i2c-rzv2m.c +++ b/drivers/i2c/busses/i2c-rzv2m.c @@ -442,7 +442,7 @@ static int rzv2m_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, rzv2m_i2c_tia_irq_handler, 0, dev_name(dev), priv); if (ret < 0) - return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + return ret; adap = &priv->adap; adap->nr = pdev->id; diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 7b321a956fca..c42925f9a330 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -546,10 +546,8 @@ static int sprd_i2c_probe(struct platform_device *pdev) sprd_i2c_isr, sprd_i2c_isr_thread, IRQF_NO_SUSPEND | IRQF_ONESHOT, pdev->name, i2c_dev); - if (ret) { - dev_err_probe(&pdev->dev, ret, "failed to request irq %d\n", i2c_dev->irq); + if (ret) goto err_rpm_put; - } ret = i2c_add_numbered_adapter(&i2c_dev->adap); if (ret) { diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 3f89c2145741..0a2b43b5577b 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -825,8 +825,7 @@ static int st_i2c_probe(struct platform_device *pdev) NULL, st_i2c_isr_thread, IRQF_ONESHOT, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to request irq %i\n", i2c_dev->irq); + return ret; pinctrl_pm_select_default_state(i2c_dev->dev); /* In case idle state available, select it */ diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 44e8b04962bb..579ab29ef554 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -801,14 +801,12 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq_event, stm32f4_i2c_isr_event, 0, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to request irq event %i\n", irq_event); + return ret; ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to request irq error %i\n", irq_error); + return ret; ret = stm32f4_i2c_hw_config(i2c_dev); if (ret) diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index d6d993b436cb..6bd281a9ef72 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2204,7 +2204,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) IRQF_ONESHOT, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to request irq event\n"); + return ret; if (!i2c_dev->setup.single_it_line) { irq_error = platform_get_irq(pdev, 1); @@ -2217,7 +2217,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) IRQF_ONESHOT, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n"); + return ret; } ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup); diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index dffbe776a195..4f70b12a9559 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -261,10 +261,8 @@ static int p2wi_probe(struct platform_device *pdev) i2c_set_adapdata(&p2wi->adapter, p2wi); ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi); - if (ret) { - dev_err_probe(dev, ret, "can't register interrupt handler irq%d\n", irq); + if (ret) goto err_reset_assert; - } writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL); diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index 4891d68bf0ee..0216e398f274 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -576,7 +576,7 @@ static int synquacer_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr, 0, dev_name(&pdev->dev), i2c); if (ret < 0) - return dev_err_probe(&pdev->dev, ret, "cannot claim IRQ %d\n", i2c->irq); + return ret; i2c->state = STATE_IDLE; i2c->dev = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index ca0358e8f928..7190802a493c 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -560,7 +560,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, pdev->name, priv); if (ret) - return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); + return ret; return i2c_add_adapter(&priv->adap); } diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index 9d49a3d5d612..ad7bbf5e2466 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -354,7 +354,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, priv); if (ret) - return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); + return ret; return i2c_add_adapter(&priv->adap); } diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 2cf3cc0165fb..d3dda7534b0a 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -114,8 +114,7 @@ static int wmt_i2c_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr, 0, pdev->name, i2c); if (err) - return dev_err_probe(&pdev->dev, err, - "failed to request irq %i\n", i2c->irq); + return err; i2c->clk = of_clk_get(np, 0); if (IS_ERR(i2c->clk)) diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c index 95dc64902b7c..764a2dbc957a 100644 --- a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c +++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c @@ -305,8 +305,7 @@ static int zxi2c_probe(struct platform_device *pdev) error = devm_request_irq(&pdev->dev, i2c->irq, zxi2c_isr, IRQF_SHARED, pdev->name, i2c); if (error) - return dev_err_probe(&pdev->dev, error, - "failed to request irq %i\n", i2c->irq); + return error; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index ddb1c3e8bc9d..ad0e5cd218f0 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -530,7 +530,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, pdev->name, priv); if (err) - return dev_err_probe(&pdev->dev, err, "IRQ request failed!\n"); + return err; init_completion(&priv->msg_complete); priv->adapter.dev.parent = &pdev->dev; From cbd043b00ee3f542c115c8809c4d9a67465c07d5 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Thu, 16 Jul 2026 15:19:56 +0800 Subject: [PATCH 2/8] i2c: imx-lpi2c: properly unwind resources on probe failure When probe fails at devm_clk_rate_exclusive_get() or clk_get_rate(), which occur before runtime PM is initialized, the clocks enabled by clk_bulk_prepare_enable() are never disabled. When probe fails after runtime PM is initialized, the previous error path called pm_runtime_put_sync(), which triggers the runtime suspend callback. However, due to different clock management strategies on different SoCs[1] (to avoid deadlocks between the global prepare_lock and runtime PM), the callback may only disable clocks without unpreparing them, causing an incomplete unwind. Introduce a new error label 'clk_disable' to explicitly invoke clk_bulk_disable_unprepare(). Replace pm_runtime_put_sync() with the sequence of pm_runtime_disable(), pm_runtime_set_suspended() and pm_runtime_put_noidle() to bypass the runtime suspend callback during error recovery. During the LPI2C driver probe phase, clock APIs are used exclusively to manage clocks. Once probing succeeds, clock management is handed over to the runtime PM core. [1] https://lore.kernel.org/all/20251125084718.2156168-1-carlos.song@nxp.com/ Signed-off-by: Carlos Song Reviewed-by: Frank Li Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260716071957.2670263-2-carlos.song@oss.nxp.com --- drivers/i2c/busses/i2c-imx-lpi2c.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 1ad7a645ca9a..0081354d91e1 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -1527,14 +1527,18 @@ static int lpi2c_imx_probe(struct platform_device *pdev) * each transfer */ ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk); - if (ret) - return dev_err_probe(&pdev->dev, ret, - "can't lock I2C peripheral clock rate\n"); + if (ret) { + ret = dev_err_probe(&pdev->dev, ret, + "can't lock I2C peripheral clock rate\n"); + goto clk_disable; + } lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk); - if (!lpi2c_imx->rate_per) - return dev_err_probe(&pdev->dev, -EINVAL, - "can't get I2C peripheral clock rate\n"); + if (!lpi2c_imx->rate_per) { + ret = dev_err_probe(&pdev->dev, -EINVAL, + "can't get I2C peripheral clock rate\n"); + goto clk_disable; + } if (lpi2c_imx->hwdata->need_prepare_unprepare_clk) pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_LONG_TIMEOUT_MS); @@ -1576,8 +1580,11 @@ static int lpi2c_imx_probe(struct platform_device *pdev) rpm_disable: pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); +clk_disable: + clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks); return ret; } From a4c419356a33324bb14f88511b990e2eee6dce56 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Thu, 16 Jul 2026 15:19:57 +0800 Subject: [PATCH 3/8] i2c: imx-lpi2c: reset controller in probe stage Reset I2C controller in probe stage to avoid unexpected LPI2C controller state left from previous stages and hang system boot. Per the LPI2C reference manual, section 7.1.4 "Controller Control (MCR)" and 7.1.20 Target Control (SCR), the RST bit (bit 1) description states: "The reset takes effect immediately and remains asserted until negated by software. There is no minimum delay required before clearing the software reset." Therefore, it is safe to write 0 to MCR and SCR immediately after asserting the RST bit without any additional delay. Signed-off-by: Carlos Song Reviewed-by: Frank Li Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260716071957.2670263-3-carlos.song@oss.nxp.com --- drivers/i2c/busses/i2c-imx-lpi2c.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 0081354d91e1..e1a4338bc51e 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -1510,11 +1510,6 @@ static int lpi2c_imx_probe(struct platform_device *pdev) if (ret) lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ; - ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND, - pdev->name, lpi2c_imx); - if (ret) - return ret; - i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx); platform_set_drvdata(pdev, lpi2c_imx); @@ -1550,6 +1545,20 @@ static int lpi2c_imx_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + /* + * Reset all internal controller registers of both Master and Target + * to avoid effects of previous status. + */ + writel(MCR_RST, lpi2c_imx->base + LPI2C_MCR); + writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR); + writel(0, lpi2c_imx->base + LPI2C_MCR); + writel(0, lpi2c_imx->base + LPI2C_SCR); + + ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND, + pdev->name, lpi2c_imx); + if (ret) + goto rpm_disable; + temp = readl(lpi2c_imx->base + LPI2C_PARAM); lpi2c_imx->txfifosize = 1 << (temp & 0x0f); lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); From 43eb13f13385a1e7251978a1977ac61b99edef01 Mon Sep 17 00:00:00 2001 From: Ruoyu Wang Date: Thu, 13 Aug 2026 23:31:55 +0800 Subject: [PATCH 4/8] i2c: ocores: Disable clock on failed resume ocores_i2c_resume() enables the controller clock before reinitializing the hardware. If the clock rate changed while the device was suspended, ocores_init() may reject the resulting prescaler. The callback then returns an error with the clock still enabled, while the controller itself remains disabled. Disable and unprepare the clock when ocores_init() fails so the failed resume path balances the successful clk_prepare_enable() call. This issue was found by a static analysis checker and confirmed by manual source review. Fixes: e961a094afe0 ("i2c: ocores: add common clock support") Signed-off-by: Ruoyu Wang Reviewed-by: Max Filippov Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260813153155.3953577-1-ruoyuw560@gmail.com --- drivers/i2c/busses/i2c-ocores.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index df6ebf32d6e8..2d18c1035837 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -755,7 +755,11 @@ static int ocores_i2c_resume(struct device *dev) rate = clk_get_rate(i2c->clk) / 1000; if (rate) i2c->ip_clock_khz = rate; - return ocores_init(dev, i2c); + ret = ocores_init(dev, i2c); + if (ret) + clk_disable_unprepare(i2c->clk); + + return ret; } static DEFINE_NOIRQ_DEV_PM_OPS(ocores_i2c_pm, From 62edb8ca0aa44517cc23cfa26cd8a51f15ea92fe Mon Sep 17 00:00:00 2001 From: Linkai Gong Date: Thu, 13 Aug 2026 17:56:17 +0800 Subject: [PATCH 5/8] i2c: mux: demux-pinctrl: fix OF node leak on kstrdup failure of_parse_phandle() takes a reference on the parent node. If a later devm_kstrdup() fails, err_rollback only releases nodes for indices 0..i-1, so the current node is leaked. of_node_put() the current parent before rolling back. Fixes: 7c0195fa9a9e ("i2c: mux: demux-pinctrl: check the return value of devm_kstrdup()") Signed-off-by: Linkai Gong Cc: # v6.6+ Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260813095617.2246320-1-gonglinkai@kylinos.cn --- drivers/i2c/muxes/i2c-demux-pinctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index f2a1f4744978..2403c0bf7c43 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -247,6 +247,7 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL); if (!props[i].name || !props[i].value) { err = -ENOMEM; + of_node_put(adap_np); goto err_rollback; } props[i].length = 3; From 777979e627115734052b323d2721cdb500e81dcf Mon Sep 17 00:00:00 2001 From: Ruoyu Wang Date: Sat, 15 Aug 2026 23:17:20 +0800 Subject: [PATCH 6/8] i2c: mxs: fix DMA channel leak on probe error mxs_i2c_probe() requests an exclusive DMA channel before resetting the controller and registering the I2C adapter. If either later operation fails, probe returns without releasing the channel because the remove callback is not invoked after a failed probe. Use devm_dma_request_chan() so the device core releases the channel on probe failure and driver detach. Remove the manual release from the remove callback because the channel is now device-managed. This issue was found by a static analysis checker and confirmed by manual source review. Fixes: 62885f59a261 ("MXS: Implement DMA support into mxs-i2c") Assisted-by: unnamed:claude-opus-4.8 typestate Signed-off-by: Ruoyu Wang Cc: # v3.7+ Reviewed-by: Frank Li Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260815151720.3757460-1-ruoyuw560@gmail.com --- drivers/i2c/busses/i2c-mxs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 4e07babea9c3..eee4fdcd9df3 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -839,7 +839,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) } /* Setup the DMA */ - i2c->dmach = dma_request_chan(dev, "rx-tx"); + i2c->dmach = devm_dma_request_chan(dev, "rx-tx"); if (IS_ERR(i2c->dmach)) { return dev_err_probe(dev, PTR_ERR(i2c->dmach), "Failed to request dma\n"); @@ -877,9 +877,6 @@ static void mxs_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adapter); - if (i2c->dmach) - dma_release_channel(i2c->dmach); - writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); } From 7a79b02dd1b09c235c3cf6075bccca2160d1b826 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 17 Aug 2026 10:26:45 +0200 Subject: [PATCH 7/8] i2c: rcar: fix reset handling for Gen5 Missing reset_control_status() support is not Gen5 specific. It depends on the firmware used, if any. Refactor the code to handle missing reset_control_status() more generically. Fixes: 87e713f20048 ("i2c: rcar: add R-Car Gen5 support") Suggested-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260817083046.11935-2-wsa+renesas@sang-engineering.com --- drivers/i2c/busses/i2c-rcar.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 46508176712c..755064804cb2 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -123,12 +123,13 @@ #define ID_NACK BIT(4) #define ID_EPROTO BIT(5) /* persistent flags */ +#define ID_P_NO_RST_STAT BIT(26) #define ID_P_FMPLUS BIT(27) #define ID_P_NOT_ATOMIC BIT(28) #define ID_P_HOST_NOTIFY BIT(29) #define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */ #define ID_P_PM_BLOCKED BIT(31) -#define ID_P_MASK GENMASK(31, 27) +#define ID_P_MASK GENMASK(31, 26) #define ID_SLAVE_NACK BIT(0) @@ -901,12 +902,11 @@ static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv) if (ret) return ret; - /* SCMI based resets don't need to poll for success */ - if (priv->devtype < I2C_RCAR_GEN5) - return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, - 1, 100, false, priv->rstc); + if (priv->flags & ID_P_NO_RST_STAT) + return 0; - return 0; + return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, + 1, 100, false, priv->rstc); } static int rcar_i2c_master_xfer(struct i2c_adapter *adap, @@ -1200,15 +1200,12 @@ static int rcar_i2c_probe(struct platform_device *pdev) goto out_pm_put; } - /* - * Gen5+ uses SCMI based reset which cannot report status. - * Firmware has to ensure proper reset - */ - if (priv->devtype < I2C_RCAR_GEN5) { - ret = reset_control_status(priv->rstc); - if (ret < 0) - goto out_pm_put; - } + ret = reset_control_status(priv->rstc); + /* Some SCMI firmware does not support reading reset status */ + if (ret == -ENOTSUPP) + priv->flags |= ID_P_NO_RST_STAT; + else if (ret < 0) + goto out_pm_put; /* hard reset disturbs HostNotify local target, so disable it */ priv->flags &= ~ID_P_HOST_NOTIFY; From b5fa55ad007059547c9139d4c4872e158ae255f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Antinori?= Date: Thu, 21 May 2026 16:08:50 -0300 Subject: [PATCH 8/8] i2c: rust: mark I2cAdapter methods as inline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building the kernel using llvm-19.1.7-rust-1.85.0-x86_64, the following symbols are generated: $ nm vmlinux | grep ' _R'.*I2cAdapter | rustfilt ffffffff817ff380 T ::get ffffffff817ff400 T ::dec_ref ffffffff817ff3e0 T ::inc_ref However, these Rust symbols are trivial wrappers around the `i2c_get_adapter` and `i2c_put_adapter` functions. It doesn't make sense to go through a trivial wrapper for these functions. Link: https://github.com/Rust-for-Linux/linux/issues/1145 Suggested-by: Alice Ryhl Signed-off-by: Nicolás Antinori Reviewed-by: Onur Özkan Reviewed-by: Igor Korotin Signed-off-by: Igor Korotin --- rust/kernel/i2c.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index dd9271af5eb8..c4002e293a73 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -404,6 +404,7 @@ pub fn index(&self) -> i32 { } /// Gets pointer to an `i2c_adapter` by index. + #[inline] pub fn get(index: i32) -> Result> { // SAFETY: `index` must refer to a valid I2C adapter; the kernel // guarantees that `i2c_get_adapter(index)` returns either a valid @@ -425,11 +426,13 @@ pub fn get(index: i32) -> Result> { // SAFETY: Instances of `I2cAdapter` are always reference-counted. unsafe impl AlwaysRefCounted for I2cAdapter { + #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. unsafe { bindings::i2c_get_adapter(self.index()) }; } + #[inline] unsafe fn dec_ref(obj: NonNull) { // SAFETY: The safety requirements guarantee that the refcount is non-zero. unsafe { bindings::i2c_put_adapter(obj.as_ref().as_raw()) }