summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2026-01-23 08:33:24 +0200
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2026-01-31 00:02:24 +0100
commitc3357bdd9be9cd9e34e46fe100e1d425503d4acf (patch)
tree886d4e1e4e36ec0339b265d15923ed77ec0c2348 /drivers
parentc481ef12e713fb7c292d04f53b3532ac0804ab3d (diff)
i3c: mipi-i3c-hci: Add optional System Suspend support
Add system suspend callbacks. Implement them by forcing runtime PM. Consequently bail out if Runtime PM is not allowed. On resume from System Suspend (suspend to RAM), rerun Dynamic Address Assignment to restore addresses for devices that may have lost power. On resume from System Hibernation (suspend to disk), use the new i3c_master_do_daa_ext() helper with 'rstdaa' set to true, which additionally handles the case where devices are assigned different dynamic addresses after a hibernation boot. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260123063325.8210-3-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/core.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 02c5a133e329..e925584113d1 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -769,6 +769,49 @@ static int i3c_hci_runtime_resume(struct device *dev)
return 0;
}
+static int i3c_hci_suspend(struct device *dev)
+{
+ struct i3c_hci *hci = dev_get_drvdata(dev);
+
+ if (!(hci->quirks & HCI_QUIRK_RPM_ALLOWED))
+ return 0;
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int i3c_hci_resume_common(struct device *dev, bool rstdaa)
+{
+ struct i3c_hci *hci = dev_get_drvdata(dev);
+ int ret;
+
+ if (!(hci->quirks & HCI_QUIRK_RPM_ALLOWED))
+ return 0;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ ret = i3c_master_do_daa_ext(&hci->master, rstdaa);
+ if (ret)
+ dev_err(dev, "Dynamic Address Assignment failed on resume, error %d\n", ret);
+
+ /*
+ * I3C devices may have retained their dynamic address anyway. Do not
+ * fail the resume because of DAA error.
+ */
+ return 0;
+}
+
+static int i3c_hci_resume(struct device *dev)
+{
+ return i3c_hci_resume_common(dev, false);
+}
+
+static int i3c_hci_restore(struct device *dev)
+{
+ return i3c_hci_resume_common(dev, true);
+}
+
#define DEFAULT_AUTOSUSPEND_DELAY_MS 1000
static void i3c_hci_rpm_enable(struct device *dev)
@@ -945,6 +988,12 @@ static const struct platform_device_id i3c_hci_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, i3c_hci_driver_ids);
static const struct dev_pm_ops i3c_hci_pm_ops = {
+ .suspend = pm_sleep_ptr(i3c_hci_suspend),
+ .resume = pm_sleep_ptr(i3c_hci_resume),
+ .freeze = pm_sleep_ptr(i3c_hci_suspend),
+ .thaw = pm_sleep_ptr(i3c_hci_resume),
+ .poweroff = pm_sleep_ptr(i3c_hci_suspend),
+ .restore = pm_sleep_ptr(i3c_hci_restore),
RUNTIME_PM_OPS(i3c_hci_runtime_suspend, i3c_hci_runtime_resume, NULL)
};