]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
i2c: designware: Fix clock issue when PM is disabled
authorKunihiko Hayashi <hayashi.kunihiko@socionext.com>
Thu, 24 Jul 2025 04:22:10 +0000 (13:22 +0900)
committerWolfram Sang <wsa+renesas@sang-engineering.com>
Fri, 26 Sep 2025 07:34:50 +0000 (09:34 +0200)
When the driver is removed, the clocks are first enabled by
calling pm_runtime_get_sync(), and then disabled with
pm_runtime_put_sync().

If CONFIG_PM=y, clocks for this controller are disabled when it's in
the idle state. So the clocks are properly disabled when the driver
exits.

Othewise, the clocks are always enabled and the PM functions have
no effect. Therefore, the driver exits without disabling the clocks.

    # cat /sys/kernel/debug/clk/clk-pclk/clk_enable_count
    18
    # echo 1214a000.i2c > /sys/bus/platform/drivers/i2c_designware/bind
    # cat /sys/kernel/debug/clk/clk-pclk/clk_enable_count
    20
    # echo 1214a000.i2c > /sys/bus/platform/drivers/i2c_designware/unbind
    # cat /sys/kernel/debug/clk/clk-pclk/clk_enable_count
    20

To ensure that the clocks can be disabled correctly even without
CONFIG_PM=y, should add the following fixes:

- Replace with pm_runtime_put_noidle(), which only decrements the runtime
  PM usage count.
- Call i2c_dw_prepare_clk(false) to explicitly disable the clocks.

Fixes: 7272194ed391f ("i2c-designware: add minimal support for runtime PM")
Co-developed-by: Kohei Ito <ito.kohei@socionext.com>
Signed-off-by: Kohei Ito <ito.kohei@socionext.com>
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
drivers/i2c/busses/i2c-designware-platdrv.c

index be2f9533cef94e3d07cb52401528fe5c1985198b..3223da7018069903a48efea5333f317d0b78d1f2 100644 (file)
@@ -333,9 +333,11 @@ static void dw_i2c_plat_remove(struct platform_device *pdev)
        i2c_dw_disable(dev);
 
        pm_runtime_dont_use_autosuspend(device);
-       pm_runtime_put_sync(device);
+       pm_runtime_put_noidle(device);
        dw_i2c_plat_pm_cleanup(dev);
 
+       i2c_dw_prepare_clk(dev, false);
+
        i2c_dw_remove_lock_support(dev);
 
        reset_control_assert(dev->rst);