]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
i3c: mipi-i3c-hci: Allow parent to manage runtime PM
authorAdrian Hunter <adrian.hunter@intel.com>
Fri, 6 Mar 2026 08:53:36 +0000 (10:53 +0200)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Sun, 12 Apr 2026 14:32:46 +0000 (16:32 +0200)
Some platforms implement the MIPI I3C HCI Multi-Bus Instance capability,
where a single parent device hosts multiple I3C controller instances.  In
such designs, the parent - not the individual child instances - may need to
coordinate runtime PM so that all controllers runtime PM callbacks are
invoked in a controlled and synchronized manner.

For example, if the parent enables IBI-wakeup when transitioning into a
low-power state, every bus instance must remain able to receive IBIs up
until that point.  This requires deferring the individual controllers'
runtime suspend callbacks (which disable bus activity) until the parent
decides it is safe for all instances to suspend together.

To support this usage model:

  * Export the low-level runtime PM suspend and resume helpers so that
    the parent can explicitly invoke them.

  * Add a new quirk, HCI_QUIRK_RPM_PARENT_MANAGED, allowing platforms to
    bypass per-instance runtime PM callbacks and delegate control to the
    parent device.

  * Move DEFAULT_AUTOSUSPEND_DELAY_MS into the header so it can be shared
    by parent-managed PM implementations.

The new quirk allows platforms with multi-bus parent-managed PM
infrastructure to correctly coordinate runtime PM across all I3C HCI
instances.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260306085338.62955-4-adrian.hunter@intel.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/i3c/master/mipi-i3c-hci/core.c
drivers/i3c/master/mipi-i3c-hci/hci.h

index 54d5492545ef4f136ac2c79cb043ef3367604d73..d803c0b7a64e4d2b23fc7b26a76f3f5b8a1dbba4 100644 (file)
@@ -759,7 +759,7 @@ static int i3c_hci_reset_and_init(struct i3c_hci *hci)
        return 0;
 }
 
-static int i3c_hci_runtime_suspend(struct device *dev)
+int i3c_hci_rpm_suspend(struct device *dev)
 {
        struct i3c_hci *hci = dev_get_drvdata(dev);
        int ret;
@@ -776,8 +776,9 @@ static int i3c_hci_runtime_suspend(struct device *dev)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(i3c_hci_rpm_suspend);
 
-static int i3c_hci_runtime_resume(struct device *dev)
+int i3c_hci_rpm_resume(struct device *dev)
 {
        struct i3c_hci *hci = dev_get_drvdata(dev);
        int ret;
@@ -800,6 +801,27 @@ static int i3c_hci_runtime_resume(struct device *dev)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(i3c_hci_rpm_resume);
+
+static int i3c_hci_runtime_suspend(struct device *dev)
+{
+       struct i3c_hci *hci = dev_get_drvdata(dev);
+
+       if (hci->quirks & HCI_QUIRK_RPM_PARENT_MANAGED)
+               return 0;
+
+       return i3c_hci_rpm_suspend(dev);
+}
+
+static int i3c_hci_runtime_resume(struct device *dev)
+{
+       struct i3c_hci *hci = dev_get_drvdata(dev);
+
+       if (hci->quirks & HCI_QUIRK_RPM_PARENT_MANAGED)
+               return 0;
+
+       return i3c_hci_rpm_resume(dev);
+}
 
 static int i3c_hci_suspend(struct device *dev)
 {
@@ -844,8 +866,6 @@ 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)
 {
        struct i3c_hci *hci = dev_get_drvdata(dev);
index 02cab3b3bc6f3dc666a42518c90f764f7763fc74..f17f43494c1b5245458f481490345856cc5be4e1 100644 (file)
@@ -151,6 +151,7 @@ struct i3c_hci_dev_data {
 #define HCI_QUIRK_RESP_BUF_THLD                BIT(4)  /* Set resp buf thld to 0 for AMD platforms */
 #define HCI_QUIRK_RPM_ALLOWED          BIT(5)  /* Runtime PM allowed */
 #define HCI_QUIRK_RPM_IBI_ALLOWED      BIT(6)  /* IBI and Hot-Join allowed while runtime suspended */
+#define HCI_QUIRK_RPM_PARENT_MANAGED   BIT(7)  /* Runtime PM managed by parent device */
 
 /* global functions */
 void mipi_i3c_hci_resume(struct i3c_hci *hci);
@@ -161,4 +162,9 @@ void amd_set_resp_buf_thld(struct i3c_hci *hci);
 void i3c_hci_sync_irq_inactive(struct i3c_hci *hci);
 int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
 
+#define DEFAULT_AUTOSUSPEND_DELAY_MS 1000
+
+int i3c_hci_rpm_suspend(struct device *dev);
+int i3c_hci_rpm_resume(struct device *dev);
+
 #endif