From cdac670237258c8ca063aa8a16998f680d81b80d Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Thu, 23 Jul 2026 10:11:40 +0800 Subject: [PATCH 1/9] i2c: spacemit: request IRQ after controller initialization spacemit_i2c_probe() requests the IRQ before it enables the clocks, resets the controller and runs init_completion(). If an interrupt is already pending, the handler runs too early: it reads registers while the clocks are still off and calls complete() on an uninitialized completion. Request the IRQ after the controller and completion are initialized, but still before the adapter is registered. Fixes: 5ea558473fa3 ("i2c: spacemit: add support for SpacemiT K1 SoC") Signed-off-by: Linmao Li Cc: # v6.15+ Reviewed-by: Troy Mitchell Reviewed-by: Alex Elder Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260723021140.2293844-1-lilinmao@kylinos.cn --- drivers/i2c/busses/i2c-k1.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c index 51a0c3d80fc9..3fe716cc153d 100644 --- a/drivers/i2c/busses/i2c-k1.c +++ b/drivers/i2c/busses/i2c-k1.c @@ -723,11 +723,6 @@ static int spacemit_i2c_probe(struct platform_device *pdev) if (i2c->irq < 0) return dev_err_probe(dev, i2c->irq, "failed to get irq resource"); - 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"); - clk = devm_clk_get_enabled(dev, "func"); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock"); @@ -755,6 +750,11 @@ static int spacemit_i2c_probe(struct platform_device *pdev) init_completion(&i2c->complete); + 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"); + platform_set_drvdata(pdev, i2c); ret = i2c_add_numbered_adapter(&i2c->adapt); From 82048795242f04275a3f49ffc66ad851b6120954 Mon Sep 17 00:00:00 2001 From: Myeonghun Pak Date: Tue, 21 Jul 2026 23:41:47 +0900 Subject: [PATCH 2/9] i2c: amd-mp2: Unregister callback on adapter add failure amd_mp2_register_cb() stores the platform I2C context in the MP2 PCI driver's callback table before the adapter is registered. If i2c_add_adapter() fails, probe returns and devres frees the context, but the PCI driver can still dereference the stale pointer from its IRQ and system-sleep callbacks. Unregister the callback before returning the adapter registration error. Fixes: 529766e0a011 ("i2c: Add drivers for the AMD PCIe MP2 I2C controller") Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Signed-off-by: Myeonghun Pak Cc: # v5.2+ Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260721144147.31150-1-mhun512@gmail.com --- drivers/i2c/busses/i2c-amd-mp2-plat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index 188e24cc4d35..9fdd6a5fb8b6 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -316,8 +316,10 @@ static int i2c_amd_probe(struct platform_device *pdev) amd_mp2_pm_runtime_put(mp2_dev); - if (ret < 0) + if (ret < 0) { dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret); + amd_mp2_unregister_cb(&i2c_dev->common); + } return ret; } From d99607c888f26e8a4e9fe9772860cef4aff86bb4 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Sun, 19 Jul 2026 22:19:43 +0200 Subject: [PATCH 3/9] i2c: jz4780: Cache host clock rate at probe to prevent CCF prepare_lock deadlock Fix a severe AB/BA deadlock between the Common Clock Framework (CCF) and the I2C adapter lock, which triggers when an I2C-controlled clock generator client (like the Si5351) is registered or modified under the CCF. During an i2c client clock (generator) frequency change, the CCF acquires its global 'prepare_lock' mutex and the driver calls i2c_transfer() to update the client's chip registers, stalling for the adapter's I2C bus lock. Concurrently, an independent, parallel transfer on the same bus (e.g., a GPIO expander handling LEDs) can hold the I2C adapter lock. Inside this parallel transfer path, jz4780_i2c_set_speed() calls clk_get_rate() on the host controller's input clock to calculate bus timings. This call attempts to acquire the blocked CCF 'prepare_lock', creating a circular dependency that freezes the system. The jz4780 host controller clock itself is static and never changes at runtime. However, calling clk_get_rate() inside the active transfer path introduces an unnecessary dependency on the CCF internal locks. Eliminate this synchronous clk_get_rate() call from the active transfer path by caching the static host peripheral clock rate once - inside the private jz4780_i2c structure during jz4780_i2c_probe(). Update jz4780_i2c_set_speed() to use this cached value, safely decoupling active I2C transactions from the CCF internal locks without any risk of stale timings. Assisted-by web based Google AI (pinpointing the bug and writing the message). Fixes: ba92222ed63a12 ("i2c: jz4780: Add i2c bus controller driver for Ingenic JZ4780") Signed-off-by: H. Nikolaus Schaller Cc: # v4.1+ Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/2db6fd233aceb7238474e4833f4d25ca681c3ffb.1784492382.git.hns@goldelico.com --- drivers/i2c/busses/i2c-jz4780.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index 664a5471d933..695be3b21460 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -141,6 +141,7 @@ struct jz4780_i2c { void __iomem *iomem; int irq; struct clk *clk; + unsigned long clk_rate_khz; struct i2c_adapter adap; const struct ingenic_i2c_config *cdata; @@ -246,7 +247,7 @@ static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address) static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c) { - int dev_clk_khz = clk_get_rate(i2c->clk) / 1000; + int dev_clk_khz = i2c->clk_rate_khz; int cnt_high = 0; /* HIGH period count of the SCL clock */ int cnt_low = 0; /* LOW period count of the SCL clock */ int cnt_period = 0; /* period count of the SCL clock */ @@ -796,6 +797,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->clk)) return PTR_ERR(i2c->clk); + i2c->clk_rate_khz = clk_get_rate(i2c->clk) / 1000; + ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clk_freq); if (ret) { From 0a4bb2abc3e56d7be6e69b050c88ba52c87e22bf Mon Sep 17 00:00:00 2001 From: Hardik Prakash Date: Sat, 18 Jul 2026 11:13:31 +0530 Subject: [PATCH 4/9] i2c: designware: defer probe if child GpioInt controllers are not bound I2C controllers may have child devices with GpioInt resources that depend on GPIO controllers being fully initialized. If the I2C controller probes and enumerates children before the referenced GPIO controller has completed probe, GPIO interrupts may not be properly configured, leading to device failures. On Lenovo Yoga 7 14AGP11, the WACF2200 touchscreen (child of AMDI0010:02) has a GpioInt resource pointing to GPIO 157 on the pinctrl-amd controller (AMDI0030:00). When i2c-designware probes AMDI0010:02 before pinctrl-amd finishes initializing, I2C transactions fail with lost arbitration errors: 0.285952 amd_gpio_probe: registering gpiochip <- GPIO chip visible 0.287121 amd_gpio_probe: requesting parent IRQ <- probe still running 0.301454 AMDI0010:02 dw_i2c_plat_probe: start <- races here 2.348157 lost arbitration Add a dependency check that walks ACPI child devices and defers probe until any referenced GPIO controller is bound. Fixes: 3812a9e84265 ("pinctrl-amd: enable IRQ for WACF2200 touchscreen on Lenovo Yoga 7 14AGP11") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221494 Suggested-by: Mario Limonciello Suggested-by: Andy Shevchenko Signed-off-by: Hardik Prakash Assisted-by: Claude:claude-sonnet-5 Assisted-by: DeepSeek:deepseek-v4-pro Cc: # v7.1+ Acked-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260718054330.8975-2-hardikprakash.official@gmail.com --- drivers/i2c/busses/i2c-designware-platdrv.c | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 6d6e81242f74..c8a203fff4d1 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -8,12 +8,14 @@ * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. */ +#include #include #include #include #include #include #include +#include #include #include #include @@ -130,6 +132,80 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) return 0; } +#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB) +/* + * Check whether an ACPI GpioInt resource's referenced GPIO controller + * has finished probing. Resources with no named controller (resource + * source string) are skipped, since they can't be resolved to a + * struct device. + */ +static int check_gpioint_resource(struct acpi_resource *ares, void *data) +{ + struct acpi_resource_gpio *agpio; + struct acpi_device *gpio_adev; + struct device *gpio_dev; + acpi_handle handle; + acpi_status status; + + if (!acpi_gpio_get_irq_resource(ares, &agpio)) + return 1; /* not a GpioInt resource, skip */ + + if (!agpio->resource_source.string_length) + return 1; /* no named controller, skip */ + + status = acpi_get_handle(NULL, agpio->resource_source.string_ptr, &handle); + if (ACPI_FAILURE(status)) + return 1; + + gpio_adev = acpi_fetch_acpi_dev(handle); + if (!gpio_adev) + return 1; + + struct gpio_device *gdev __free(gpio_device_put) = + gpio_device_find_by_fwnode(acpi_fwnode_handle(gpio_adev)); + if (!gdev) + return -EPROBE_DEFER; /* controller not registered yet: abort walk */ + + gpio_dev = gpio_device_to_device(gdev)->parent; + + guard(device)(gpio_dev); + if (!device_is_bound(gpio_dev)) + return -EPROBE_DEFER; /* controller not bound yet: abort walk */ + + return 1; /* bound, skip adding to resource list, continue walk */ +} + +static int check_child_gpioint(struct acpi_device *adev, void *data) +{ + LIST_HEAD(res_list); + int ret; + + ret = acpi_dev_get_resources(adev, &res_list, check_gpioint_resource, NULL); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&res_list); + + return 0; +} + +static int i2c_dw_check_gpio_dependencies(struct device *dev) +{ + struct acpi_device *adev; + + adev = ACPI_COMPANION(dev); + if (!adev) + return 0; + + return acpi_dev_for_each_child(adev, check_child_gpioint, NULL); +} +#else +static int i2c_dw_check_gpio_dependencies(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_ACPI && CONFIG_GPIOLIB */ + static int dw_i2c_plat_probe(struct platform_device *pdev) { u32 flags = (uintptr_t)device_get_match_data(&pdev->dev); @@ -138,6 +214,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) struct dw_i2c_dev *dev; int irq, ret; + ret = i2c_dw_check_gpio_dependencies(device); + if (ret) + return ret; + irq = platform_get_irq_optional(pdev, 0); if (irq == -ENXIO) flags |= ACCESS_POLLING; From 00d86dd5c2034e0e139e4806137b3b43e07ddd83 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Mon, 25 May 2026 11:04:00 +0800 Subject: [PATCH 5/9] i2c: imx: mark I2C adapter when hardware is powered down On some i.MX platforms, certain I2C client drivers keep a periodic workqueue which continues to trigger I2C transfers. During system suspend/resume, there exists a time window between: - suspend_noirq and the system entering suspend - the system starting to resume and resume_noirq In this window, the I2C controller resources such as clock and pinctrl may already be disabled or not yet restored. If a workqueue triggers an I2C transfer in this period, the driver attempts to access I2C registers while the hardware resources are unavailable, which may lead to system hang. Mark the I2C adapter as suspended during noirq suspend and block new transfers until resume, ensuring that I2C transfers are only issued when hardware resources are available. Fixes: 358025ac091e ("i2c: imx: make controller available until system suspend_noirq() and from resume_noirq()") Signed-off-by: Carlos Song Cc: # v6.14+ Reviewed-by: Frank Li Acked-by: Oleksij Rempel Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260525030400.3182911-1-carlos.song@oss.nxp.com --- drivers/i2c/busses/i2c-imx.c | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index d5e6e2eca3b3..d549d630b41a 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1952,6 +1952,47 @@ static int i2c_imx_runtime_resume(struct device *dev) return 0; } +static int __maybe_unused i2c_imx_suspend_noirq(struct device *dev) +{ + struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); + int ret; + + i2c_mark_adapter_suspended(&i2c_imx->adapter); + + /* + * Cancel the slave timer before powering down to prevent + * i2c_imx_slave_timeout() from accessing hardware registers + * while the clock is disabled. + */ + hrtimer_cancel(&i2c_imx->slave_timer); + + ret = pm_runtime_force_suspend(dev); + if (ret) { + i2c_mark_adapter_resumed(&i2c_imx->adapter); + if (i2c_imx->slave) { + hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY); + hrtimer_restart(&i2c_imx->slave_timer); + } + return ret; + } + + return 0; +} + +static int __maybe_unused i2c_imx_resume_noirq(struct device *dev) +{ + struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + i2c_mark_adapter_resumed(&i2c_imx->adapter); + + return 0; +} + static int i2c_imx_suspend(struct device *dev) { /* @@ -1985,8 +2026,8 @@ static int i2c_imx_resume(struct device *dev) } static const struct dev_pm_ops i2c_imx_pm_ops = { - NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend_noirq, + i2c_imx_resume_noirq) SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume) RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL) }; From 98f2e9e6d6f91a6abb43f166b244b428ba85fa2b Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 17 Jul 2026 10:55:07 +0200 Subject: [PATCH 6/9] i2c: iproc: reset bus after timeout if START_BUSY is stuck If a transaction times out, the START_BUSY signal can stay up, and subsequent transactaction attempts will fail as the bus is still considered busy. I can easily trigger this by attempting to read from an address with no device, e.g. when running i2cdetect. After the first read times out, all subsequent read attempts return busy. To get to a working state again, the controller needs to be reset to clear the START_BUSY signal. So check for START_BUSY still asserted on a timeout, and do reset in case it is, This is also done by the original non-upstream iproc-smbus driver implementation [1]. Works around situations like: bcm-iproc-2c 1803b000.i2c: transaction timed out bcm-iproc-2c 1803b000.i2c: bus is busy bcm-iproc-2c 1803b000.i2c: bus is busy bcm-iproc-2c 1803b000.i2c: bus is busy bcm-iproc-2c 1803b000.i2c: bus is busy bcm-iproc-2c 1803b000.i2c: bus is busy ... where the bus never recovers after a timeout. [1] https://github.com/opencomputeproject/onie/blob/master/patches/kernel/3.2.69/driver-iproc-smbus.patch Fixes: e6e5dd3566e0 ("i2c: iproc: Add Broadcom iProc I2C Driver") Signed-off-by: Jonas Gorski Cc: # v4.0+ Acked-by: Ray Jui Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260717085507.34209-1-jonas.gorski@bisdn.de --- drivers/i2c/busses/i2c-bcm-iproc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index b5629cffe99b..86ca4c2221c4 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -803,6 +803,17 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c, } if (!time_left && !iproc_i2c->xfer_is_done) { + /* + * The controller may fail to clear START_BUSY after a timeout, + * reset the controller to recover in that case. + */ + if (!!(iproc_i2c_rd_reg(iproc_i2c, M_CMD_OFFSET) & + BIT(M_CMD_START_BUSY_SHIFT))) { + bcm_iproc_i2c_enable_disable(iproc_i2c, false); + bcm_iproc_i2c_init(iproc_i2c); + bcm_iproc_i2c_enable_disable(iproc_i2c, true); + } + /* flush both TX/RX FIFOs */ val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT); iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val); From d64ec362c369bbc33833f7936d5f3a706b0d5c45 Mon Sep 17 00:00:00 2001 From: Liem Date: Mon, 29 Jun 2026 10:38:28 +0800 Subject: [PATCH 7/9] i2c: imx: Fix slave registration race and error handling In i2c_imx_reg_slave(), the slave pointer was assigned before pm_runtime_resume_and_get(). If pm_runtime_resume_and_get() failed, the error path returned without clearing i2c_imx->slave, leaving it non-NULL and causing all subsequent registration attempts to fail with -EBUSY. Additionally, because this driver uses a shared IRQ, the interrupt handler i2c_imx_isr() can execute concurrently and, after acquiring slave_lock, dereference i2c_imx->slave. The previous fix attempt added a lockless i2c_imx->slave = NULL on the error path, but that could race with the ISR under the lock and still cause a NULL pointer dereference. Fix both issues by deferring the assignment of i2c_imx->slave and i2c_imx->last_slave_event to after a successful resume, and by performing the assignment inside the slave_lock critical section. This guarantees that the slave pointer is never left stale on the error path and is always valid when observed by the interrupt handler. Fixes: f7414cd6923f ("i2c: imx: support slave mode for imx I2C driver") Signed-off-by: Liem Cc: # v5.11+ Reviewed-by: Frank Li Acked-by: Carlos Song Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260629023829.152651-2-liem16213@gmail.com --- drivers/i2c/busses/i2c-imx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index d549d630b41a..49859ee494c6 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -930,9 +930,6 @@ static int i2c_imx_reg_slave(struct i2c_client *client) if (i2c_imx->slave) return -EBUSY; - i2c_imx->slave = client; - i2c_imx->last_slave_event = I2C_SLAVE_STOP; - /* Resume */ ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent); if (ret < 0) { @@ -940,6 +937,11 @@ static int i2c_imx_reg_slave(struct i2c_client *client) return ret; } + scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) { + i2c_imx->slave = client; + i2c_imx->last_slave_event = I2C_SLAVE_STOP; + } + i2c_imx_slave_init(i2c_imx); return 0; From 6ac7702b6cc2b94aaed9ef2d95bfbefcdc90061f Mon Sep 17 00:00:00 2001 From: Liem Date: Mon, 29 Jun 2026 10:38:29 +0800 Subject: [PATCH 8/9] i2c: imx: Cancel hrtimer before clearing slave pointer In i2c_imx_unreg_slave(), the slave pointer is set to NULL after disabling interrupts. However, a pending interrupt might already have started the hrtimer (i2c_imx_slave_timeout) before the pointer was cleared. If the hrtimer fires after i2c_imx->slave is set to NULL, the timer callback i2c_imx_slave_finish_op() will call i2c_imx_slave_event() with a NULL slave pointer, which results in a use-after-free / NULL pointer dereference. Fix by canceling the hrtimer and waiting for it to complete after disabling interrupts, before clearing the slave pointer. Fixes: f7414cd6923f ("i2c: imx: support slave mode for imx I2C driver") Signed-off-by: Liem Cc: # v5.11+ Acked-by: Carlos Song Reviewed-by: Frank Li Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260629023829.152651-3-liem16213@gmail.com --- drivers/i2c/busses/i2c-imx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 49859ee494c6..9477d814fde9 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -960,6 +960,7 @@ static int i2c_imx_unreg_slave(struct i2c_client *client) i2c_imx_reset_regs(i2c_imx); + hrtimer_cancel(&i2c_imx->slave_timer); i2c_imx->slave = NULL; /* Suspend */ From b08c9857aa1f5f3a81d375d6d4bb1d8b92f22ebc Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Thu, 25 Jun 2026 17:42:45 +0800 Subject: [PATCH 9/9] i2c: qcom-cci: drop custom suspend/resume and rely on runtime PM helpers cci_resume() unconditionally calls cci_resume_runtime() regardless of the runtime PM state. If the device is already runtime-suspended before system suspend, the clock is re-enabled while runtime_status remains RPM_SUSPENDED. As a result, pm_request_autosuspend() does not arm the timer, leaving the clock permanently enabled. Fixes: e517526195de ("i2c: Add Qualcomm CCI I2C driver") Signed-off-by: Wenmeng Liu Cc: # v5.8+ Reviewed-by: Vladimir Zapolskiy Reviewed-by: Konrad Dybcio Reviewed-by: Loic Poulain Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20260625-cci-v1-1-a100cda673ce@oss.qualcomm.com --- drivers/i2c/busses/i2c-qcom-cci.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 4d64895a9e9e..bdeda3979c48 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -492,24 +492,8 @@ static int __maybe_unused cci_resume_runtime(struct device *dev) return 0; } -static int __maybe_unused cci_suspend(struct device *dev) -{ - if (!pm_runtime_suspended(dev)) - return cci_suspend_runtime(dev); - - return 0; -} - -static int __maybe_unused cci_resume(struct device *dev) -{ - cci_resume_runtime(dev); - pm_request_autosuspend(dev); - - return 0; -} - static const struct dev_pm_ops qcom_cci_pm = { - SET_SYSTEM_SLEEP_PM_OPS(cci_suspend, cci_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL) };