Skip to content

Commit 9a258d1

Browse files
ahunter6alexandrebelloni
authored andcommitted
i3c: mipi-i3c-hci: Fallback to software reset when bus disable fails
Disruption of the MIPI I3C HCI controller's internal state can cause i3c_hci_bus_disable() to fail when attempting to shut down the bus. In the code paths where bus disable is invoked - bus clean-up and runtime suspend - the controller does not need to remain operational afterward, so a full controller reset is a safe recovery mechanism. Add a fallback to issue a software reset when disabling the bus fails. This ensures the bus is reliably halted even if the controller's state machine is stuck or unresponsive. The fallback is used both during bus clean-up and in the runtime suspend path. In the latter case, ensure interrupts are quiesced after reset. Fixes: 9ad9a52 ("i3c/master: introduce the mipi-i3c-hci driver") Cc: stable@vger.kernel.org Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260306072451.11131-15-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent c6396b8 commit 9a258d1

1 file changed

Lines changed: 35 additions & 30 deletions

File tree

  • drivers/i3c/master/mipi-i3c-hci

drivers/i3c/master/mipi-i3c-hci/core.c

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,34 @@ static int i3c_hci_bus_disable(struct i3c_hci *hci)
181181
return ret;
182182
}
183183

184+
static int i3c_hci_software_reset(struct i3c_hci *hci)
185+
{
186+
u32 regval;
187+
int ret;
188+
189+
/*
190+
* SOFT_RST must be clear before we write to it.
191+
* Then we must wait until it clears again.
192+
*/
193+
ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
194+
!(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
195+
if (ret) {
196+
dev_err(&hci->master.dev, "%s: Software reset stuck\n", __func__);
197+
return ret;
198+
}
199+
200+
reg_write(RESET_CONTROL, SOFT_RST);
201+
202+
ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
203+
!(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
204+
if (ret) {
205+
dev_err(&hci->master.dev, "%s: Software reset failed\n", __func__);
206+
return ret;
207+
}
208+
209+
return 0;
210+
}
211+
184212
void i3c_hci_sync_irq_inactive(struct i3c_hci *hci)
185213
{
186214
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)
196224
{
197225
struct i3c_hci *hci = to_i3c_hci(m);
198226

199-
i3c_hci_bus_disable(hci);
227+
if (i3c_hci_bus_disable(hci))
228+
i3c_hci_software_reset(hci);
200229
hci->io->cleanup(hci);
201230
}
202231

@@ -626,34 +655,6 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
626655
return result;
627656
}
628657

629-
static int i3c_hci_software_reset(struct i3c_hci *hci)
630-
{
631-
u32 regval;
632-
int ret;
633-
634-
/*
635-
* SOFT_RST must be clear before we write to it.
636-
* Then we must wait until it clears again.
637-
*/
638-
ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
639-
!(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
640-
if (ret) {
641-
dev_err(&hci->master.dev, "%s: Software reset stuck\n", __func__);
642-
return ret;
643-
}
644-
645-
reg_write(RESET_CONTROL, SOFT_RST);
646-
647-
ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
648-
!(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
649-
if (ret) {
650-
dev_err(&hci->master.dev, "%s: Software reset failed\n", __func__);
651-
return ret;
652-
}
653-
654-
return 0;
655-
}
656-
657658
static inline bool is_version_1_1_or_newer(struct i3c_hci *hci)
658659
{
659660
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)
764765
int ret;
765766

766767
ret = i3c_hci_bus_disable(hci);
767-
if (ret)
768+
if (ret) {
769+
/* Fall back to software reset to disable the bus */
770+
ret = i3c_hci_software_reset(hci);
771+
i3c_hci_sync_irq_inactive(hci);
768772
return ret;
773+
}
769774

770775
hci->io->suspend(hci);
771776

0 commit comments

Comments
 (0)