[PATCH v5 1/4] i2c: designware: Introduce shutdown exported function

From: William A. Kennington III

Date: Mon May 11 2026 - 16:07:17 EST


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@xxxxxxxxxxxxxxx>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
---
drivers/i2c/busses/i2c-designware-common.c | 24 ++++++++++++++++++++++++
drivers/i2c/busses/i2c-designware-core.h | 1 +
2 files changed, 25 insertions(+)

diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 4dc57fd56170..ef618d3e1ace 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -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");
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9d8d104cc391..c71aa2dd368d 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -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)

--
2.54.0.563.g4f69b47b94-goog