i2c: designware: Introduce shutdown exported function

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
This commit is contained in:
William A. Kennington III 2026-05-27 20:09:49 +00:00 committed by Andi Shyti
parent 24435f4c8c
commit 199a0fd953
No known key found for this signature in database
GPG Key ID: DA78056626D32D6E
2 changed files with 25 additions and 0 deletions

View 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");

View 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)