diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index d5e91af7d569..284f3ed7af8c 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -181,6 +181,34 @@ static int i3c_hci_bus_disable(struct i3c_hci *hci) return ret; } +static int i3c_hci_software_reset(struct i3c_hci *hci) +{ + u32 regval; + int ret; + + /* + * SOFT_RST must be clear before we write to it. + * Then we must wait until it clears again. + */ + ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval, + !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC); + if (ret) { + dev_err(&hci->master.dev, "%s: Software reset stuck\n", __func__); + return ret; + } + + reg_write(RESET_CONTROL, SOFT_RST); + + ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval, + !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC); + if (ret) { + dev_err(&hci->master.dev, "%s: Software reset failed\n", __func__); + return ret; + } + + return 0; +} + void i3c_hci_sync_irq_inactive(struct i3c_hci *hci) { struct platform_device *pdev = to_platform_device(hci->master.dev.parent); @@ -196,7 +224,8 @@ static void i3c_hci_bus_cleanup(struct i3c_master_controller *m) { struct i3c_hci *hci = to_i3c_hci(m); - i3c_hci_bus_disable(hci); + if (i3c_hci_bus_disable(hci)) + i3c_hci_software_reset(hci); hci->io->cleanup(hci); } @@ -626,34 +655,6 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) return result; } -static int i3c_hci_software_reset(struct i3c_hci *hci) -{ - u32 regval; - int ret; - - /* - * SOFT_RST must be clear before we write to it. - * Then we must wait until it clears again. - */ - ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval, - !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC); - if (ret) { - dev_err(&hci->master.dev, "%s: Software reset stuck\n", __func__); - return ret; - } - - reg_write(RESET_CONTROL, SOFT_RST); - - ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval, - !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC); - if (ret) { - dev_err(&hci->master.dev, "%s: Software reset failed\n", __func__); - return ret; - } - - return 0; -} - static inline bool is_version_1_1_or_newer(struct i3c_hci *hci) { return hci->version_major > 1 || (hci->version_major == 1 && hci->version_minor > 0); @@ -764,8 +765,12 @@ static int i3c_hci_runtime_suspend(struct device *dev) int ret; ret = i3c_hci_bus_disable(hci); - if (ret) + if (ret) { + /* Fall back to software reset to disable the bus */ + ret = i3c_hci_software_reset(hci); + i3c_hci_sync_irq_inactive(hci); return ret; + } hci->io->suspend(hci);