]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
i2c: designware: Introduce shutdown exported function
authorWilliam A. Kennington III <william@wkennington.com>
Wed, 27 May 2026 20:09:49 +0000 (20:09 +0000)
committerAndi Shyti <andi.shyti@kernel.org>
Thu, 28 May 2026 22:39:00 +0000 (00:39 +0200)
Introduce an exported shutdown function to safely shutdown the
DesignWare I2C controller.

This shutdown hook gracefully sets the target disable bit before disabling
the controller. This guarantees that any incoming requests from the
controller are immediately NACKed during shutdown, preventing the bus from
hanging.

Signed-off-by: William A. Kennington III <william@wkennington.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Link: https://lore.kernel.org/r/20260527-dw-i2c-v5-1-3483057f8d67@wkennington.com
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-core.h

index 4bb0abda0a91a43bafcb9a086fb370a8832d9aa6..d792c65d46ae313d69ec0ab951f7312a4a8407ea 100644 (file)
@@ -1028,5 +1028,29 @@ EXPORT_GPL_DEV_PM_OPS(i2c_dw_dev_pm_ops) = {
        RUNTIME_PM_OPS(i2c_dw_runtime_suspend, i2c_dw_runtime_resume, NULL)
 };
 
+void i2c_dw_shutdown(struct dw_i2c_dev *dev)
+{
+       unsigned int con;
+
+       /*
+        * We only need to handle shutdown for target mode to ensure
+        * we NACK any incoming controller requests. Controller mode cleanup
+        * is handled after each transfer in i2c_dw_xfer().
+        */
+       if (dev->mode != DW_IC_SLAVE)
+               return;
+
+       /*
+        * To quickly NACK the controller during shutdown, we set the target
+        * disable bit while the controller is still enabled.
+        */
+       regmap_read(dev->map, DW_IC_CON, &con);
+       con |= DW_IC_CON_SLAVE_DISABLE;
+       regmap_write(dev->map, DW_IC_CON, con);
+
+       i2c_dw_disable(dev);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_shutdown);
+
 MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
 MODULE_LICENSE("GPL");
index 9d8d104cc3911f9e556fb3b33ebf1c2e84e428ff..c71aa2dd368d5f79e10445f949334d1ca9d7e95f 100644 (file)
@@ -417,6 +417,7 @@ static inline void i2c_dw_configure(struct dw_i2c_dev *dev)
 
 int i2c_dw_probe(struct dw_i2c_dev *dev);
 int i2c_dw_init(struct dw_i2c_dev *dev);
+void i2c_dw_shutdown(struct dw_i2c_dev *dev);
 void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode);
 
 #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)