* [PATCH 0/3] i3c: mipi-i3c-hci-pci: Add System Suspend support
@ 2026-01-16 15:12 Adrian Hunter
2026-01-16 15:12 ` [PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery Adrian Hunter
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Adrian Hunter @ 2026-01-16 15:12 UTC (permalink / raw)
To: alexandre.belloni; +Cc: Frank.Li, Wolfram Sang, linux-i3c
Hi
Here are 3 small patches to add System Suspend support to
mipi-i3c-hci and mipi-i3c-hci-pci.
Adrian Hunter (3):
i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery
i3c: mipi-i3c-hci: Add optional System Suspend support
i3c: mipi-i3c-hci-pci: Add System Suspend support
drivers/i3c/master.c | 60 ++++++++++++++++------
drivers/i3c/master/mipi-i3c-hci/core.c | 53 +++++++++++++++++++
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 7 +++
include/linux/i3c/master.h | 1 +
4 files changed, 104 insertions(+), 17 deletions(-)
Regards
Adrian
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery
2026-01-16 15:12 [PATCH 0/3] i3c: mipi-i3c-hci-pci: Add System Suspend support Adrian Hunter
@ 2026-01-16 15:12 ` Adrian Hunter
2026-01-16 15:29 ` Frank Li
2026-01-16 15:12 ` [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support Adrian Hunter
2026-01-16 15:12 ` [PATCH 3/3] i3c: mipi-i3c-hci-pci: Add " Adrian Hunter
2 siblings, 1 reply; 10+ messages in thread
From: Adrian Hunter @ 2026-01-16 15:12 UTC (permalink / raw)
To: alexandre.belloni; +Cc: Frank.Li, Wolfram Sang, linux-i3c
After system hibernation, I3C Dynamic Addresses may be reassigned at boot
and no longer match the values recorded before suspend. Introduce
i3c_master_restore_daa() to handle this situation.
The restore procedure is straightforward: issue a Reset Dynamic Address
Assignment (RSTDAA), then run the standard DAA sequence. The existing DAA
logic already supports detecting and updating devices whose dynamic
addresses differ from previously known values.
Refactor the DAA implementation by introducing a shared helper used by both
i3c_master_do_daa() and the new restore function, and correct the
kernel-doc in the process.
Export i3c_master_restore_daa() so that master drivers can invoke it from
their PM restore callbacks.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/i3c/master.c | 60 +++++++++++++++++++++++++++-----------
include/linux/i3c/master.h | 1 +
2 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 594d61edcef4..1ba5d08365b4 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -1734,23 +1734,9 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
}
}
-/**
- * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
- * @master: master doing the DAA
- *
- * This function is instantiating an I3C device object and adding it to the
- * I3C device list. All device information are automatically retrieved using
- * standard CCC commands.
- *
- * The I3C device object is returned in case the master wants to attach
- * private data to it using i3c_dev_set_master_data().
- *
- * This function must be called with the bus lock held in write mode.
- *
- * Return: a 0 in case of success, an negative error code otherwise.
- */
-int i3c_master_do_daa(struct i3c_master_controller *master)
+static int __i3c_master_do_daa(struct i3c_master_controller *master, bool reset)
{
+ int rstret;
int ret;
ret = i3c_master_rpm_get(master);
@@ -1758,7 +1744,13 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
return ret;
i3c_bus_maintenance_lock(&master->bus);
+
+ rstret = i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
+ if (rstret == I3C_ERROR_M2)
+ rstret = 0;
+
ret = master->ops->do_daa(master);
+
i3c_bus_maintenance_unlock(&master->bus);
if (ret)
@@ -1769,10 +1761,44 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
i3c_bus_normaluse_unlock(&master->bus);
out:
i3c_master_rpm_put(master);
- return ret;
+
+ return rstret ?: ret;
+}
+
+/**
+ * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
+ * @master: master doing the DAA
+ *
+ * This function instantiates I3C device objects and adds them to the
+ * I3C device list. All device information is automatically retrieved using
+ * standard CCC commands.
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+int i3c_master_do_daa(struct i3c_master_controller *master)
+{
+ return __i3c_master_do_daa(master, false);
}
EXPORT_SYMBOL_GPL(i3c_master_do_daa);
+/**
+ * i3c_master_restore_daa() - Restore Dynamic Addresses
+ * @master: controller
+ *
+ * After System Hibernation, Dynamic Addresses can have been reassigned at boot
+ * time to different values. A simple strategy is followed to handle that.
+ * Perform a Reset of Dynamic Address (RSTDAA) followed by the normal DAA
+ * procedure which has provision for reassigning addresses that differ from the
+ * previously recorded addresses.
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+int i3c_master_restore_daa(struct i3c_master_controller *master)
+{
+ return __i3c_master_do_daa(master, true);
+}
+EXPORT_SYMBOL_GPL(i3c_master_restore_daa);
+
/**
* i3c_master_dma_map_single() - Map buffer for single DMA transfer
* @dev: device object of a device doing DMA
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index c1ec597f655c..ea757b92e440 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -598,6 +598,7 @@ int i3c_master_get_free_addr(struct i3c_master_controller *master,
int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
u8 addr);
int i3c_master_do_daa(struct i3c_master_controller *master);
+int i3c_master_restore_daa(struct i3c_master_controller *master);
struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *ptr,
size_t len, bool force_bounce,
enum dma_data_direction dir);
--
2.51.0
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support
2026-01-16 15:12 [PATCH 0/3] i3c: mipi-i3c-hci-pci: Add System Suspend support Adrian Hunter
2026-01-16 15:12 ` [PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery Adrian Hunter
@ 2026-01-16 15:12 ` Adrian Hunter
2026-01-16 15:37 ` Frank Li
2026-01-19 6:31 ` David Nyström
2026-01-16 15:12 ` [PATCH 3/3] i3c: mipi-i3c-hci-pci: Add " Adrian Hunter
2 siblings, 2 replies; 10+ messages in thread
From: Adrian Hunter @ 2026-01-16 15:12 UTC (permalink / raw)
To: alexandre.belloni; +Cc: Frank.Li, Wolfram Sang, linux-i3c
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_restore_daa() helper 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>
---
drivers/i3c/master/mipi-i3c-hci/core.c | 53 ++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 02c5a133e329..b972d8bc81e6 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -769,6 +769,53 @@ 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 restore)
+{
+ 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;
+
+ if (restore)
+ ret = i3c_master_restore_daa(&hci->master);
+ else
+ ret = i3c_master_do_daa(&hci->master);
+
+ 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 +992,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)
};
--
2.51.0
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] i3c: mipi-i3c-hci-pci: Add System Suspend support
2026-01-16 15:12 [PATCH 0/3] i3c: mipi-i3c-hci-pci: Add System Suspend support Adrian Hunter
2026-01-16 15:12 ` [PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery Adrian Hunter
2026-01-16 15:12 ` [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support Adrian Hunter
@ 2026-01-16 15:12 ` Adrian Hunter
2 siblings, 0 replies; 10+ messages in thread
From: Adrian Hunter @ 2026-01-16 15:12 UTC (permalink / raw)
To: alexandre.belloni; +Cc: Frank.Li, Wolfram Sang, linux-i3c
Assign the driver PM operations pointer, which is necessary for the PCI
subsystem to put the device into a low power state. Refer to
pci_pm_suspend_noirq() which bails out if the pointer is NULL, before
it has the opportunity to call pci_prepare_to_sleep().
No other actions are necessary as the mipi-i3c-hci driver takes care of
controller state.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
index 1b38771667e5..0f05a15c14c7 100644
--- a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
+++ b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
@@ -320,6 +320,10 @@ static void mipi_i3c_hci_pci_remove(struct pci_dev *pci)
mfd_remove_devices(&pci->dev);
}
+/* PM ops must exist for PCI to put a device to a low power state */
+static const struct dev_pm_ops mipi_i3c_hci_pci_pm_ops = {
+};
+
static const struct pci_device_id mipi_i3c_hci_pci_devices[] = {
/* Wildcat Lake-U */
{ PCI_VDEVICE(INTEL, 0x4d7c), (kernel_ulong_t)&intel_mi_1_info},
@@ -342,6 +346,9 @@ static struct pci_driver mipi_i3c_hci_pci_driver = {
.id_table = mipi_i3c_hci_pci_devices,
.probe = mipi_i3c_hci_pci_probe,
.remove = mipi_i3c_hci_pci_remove,
+ .driver = {
+ .pm = pm_ptr(&mipi_i3c_hci_pci_pm_ops)
+ },
};
module_pci_driver(mipi_i3c_hci_pci_driver);
--
2.51.0
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery
2026-01-16 15:12 ` [PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery Adrian Hunter
@ 2026-01-16 15:29 ` Frank Li
0 siblings, 0 replies; 10+ messages in thread
From: Frank Li @ 2026-01-16 15:29 UTC (permalink / raw)
To: Adrian Hunter; +Cc: alexandre.belloni, Wolfram Sang, linux-i3c
On Fri, Jan 16, 2026 at 05:12:35PM +0200, Adrian Hunter wrote:
> After system hibernation, I3C Dynamic Addresses may be reassigned at boot
> and no longer match the values recorded before suspend. Introduce
> i3c_master_restore_daa() to handle this situation.
>
> The restore procedure is straightforward: issue a Reset Dynamic Address
> Assignment (RSTDAA), then run the standard DAA sequence. The existing DAA
> logic already supports detecting and updating devices whose dynamic
> addresses differ from previously known values.
>
> Refactor the DAA implementation by introducing a shared helper used by both
> i3c_master_do_daa() and the new restore function, and correct the
> kernel-doc in the process.
>
> Export i3c_master_restore_daa() so that master drivers can invoke it from
> their PM restore callbacks.
It is good. I3C Hub also need it.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> drivers/i3c/master.c | 60 +++++++++++++++++++++++++++-----------
> include/linux/i3c/master.h | 1 +
> 2 files changed, 44 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 594d61edcef4..1ba5d08365b4 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -1734,23 +1734,9 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> }
> }
>
> -/**
> - * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
> - * @master: master doing the DAA
> - *
> - * This function is instantiating an I3C device object and adding it to the
> - * I3C device list. All device information are automatically retrieved using
> - * standard CCC commands.
> - *
> - * The I3C device object is returned in case the master wants to attach
> - * private data to it using i3c_dev_set_master_data().
> - *
> - * This function must be called with the bus lock held in write mode.
> - *
> - * Return: a 0 in case of success, an negative error code otherwise.
> - */
> -int i3c_master_do_daa(struct i3c_master_controller *master)
> +static int __i3c_master_do_daa(struct i3c_master_controller *master, bool reset)
> {
> + int rstret;
> int ret;
>
> ret = i3c_master_rpm_get(master);
> @@ -1758,7 +1744,13 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
> return ret;
>
> i3c_bus_maintenance_lock(&master->bus);
> +
> + rstret = i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
> + if (rstret == I3C_ERROR_M2)
> + rstret = 0;
looks like you missed check 'reset' parameter.
Frank
> +
> ret = master->ops->do_daa(master);
> +
> i3c_bus_maintenance_unlock(&master->bus);
>
> if (ret)
> @@ -1769,10 +1761,44 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
> i3c_bus_normaluse_unlock(&master->bus);
> out:
> i3c_master_rpm_put(master);
> - return ret;
> +
> + return rstret ?: ret;
> +}
> +
> +/**
> + * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
> + * @master: master doing the DAA
> + *
> + * This function instantiates I3C device objects and adds them to the
> + * I3C device list. All device information is automatically retrieved using
> + * standard CCC commands.
> + *
> + * Return: a 0 in case of success, an negative error code otherwise.
> + */
> +int i3c_master_do_daa(struct i3c_master_controller *master)
> +{
> + return __i3c_master_do_daa(master, false);
> }
> EXPORT_SYMBOL_GPL(i3c_master_do_daa);
>
> +/**
> + * i3c_master_restore_daa() - Restore Dynamic Addresses
> + * @master: controller
> + *
> + * After System Hibernation, Dynamic Addresses can have been reassigned at boot
> + * time to different values. A simple strategy is followed to handle that.
> + * Perform a Reset of Dynamic Address (RSTDAA) followed by the normal DAA
> + * procedure which has provision for reassigning addresses that differ from the
> + * previously recorded addresses.
> + *
> + * Return: a 0 in case of success, an negative error code otherwise.
> + */
> +int i3c_master_restore_daa(struct i3c_master_controller *master)
> +{
> + return __i3c_master_do_daa(master, true);
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_restore_daa);
> +
> /**
> * i3c_master_dma_map_single() - Map buffer for single DMA transfer
> * @dev: device object of a device doing DMA
> diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> index c1ec597f655c..ea757b92e440 100644
> --- a/include/linux/i3c/master.h
> +++ b/include/linux/i3c/master.h
> @@ -598,6 +598,7 @@ int i3c_master_get_free_addr(struct i3c_master_controller *master,
> int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> u8 addr);
> int i3c_master_do_daa(struct i3c_master_controller *master);
> +int i3c_master_restore_daa(struct i3c_master_controller *master);
> struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *ptr,
> size_t len, bool force_bounce,
> enum dma_data_direction dir);
> --
> 2.51.0
>
>
> --
> linux-i3c mailing list
> linux-i3c@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support
2026-01-16 15:12 ` [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support Adrian Hunter
@ 2026-01-16 15:37 ` Frank Li
2026-01-19 6:31 ` David Nyström
1 sibling, 0 replies; 10+ messages in thread
From: Frank Li @ 2026-01-16 15:37 UTC (permalink / raw)
To: Adrian Hunter; +Cc: alexandre.belloni, Wolfram Sang, linux-i3c
On Fri, Jan 16, 2026 at 05:12:36PM +0200, Adrian Hunter wrote:
> 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_restore_daa() helper 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>
> ---
> drivers/i3c/master/mipi-i3c-hci/core.c | 53 ++++++++++++++++++++++++++
> 1 file changed, 53 insertions(+)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index 02c5a133e329..b972d8bc81e6 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -769,6 +769,53 @@ 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 restore)
> +{
> + 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;
> +
> + if (restore)
> + ret = i3c_master_restore_daa(&hci->master);
Is it simpler if design API like
i3c_master_do_daa_ext(&hci->master, restore);
Frank
> + else
> + ret = i3c_master_do_daa(&hci->master);
> +
> + 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 +992,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)
> };
>
> --
> 2.51.0
>
>
> --
> linux-i3c mailing list
> linux-i3c@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support
2026-01-16 15:12 ` [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support Adrian Hunter
2026-01-16 15:37 ` Frank Li
@ 2026-01-19 6:31 ` David Nyström
2026-01-19 6:49 ` Adrian Hunter
1 sibling, 1 reply; 10+ messages in thread
From: David Nyström @ 2026-01-19 6:31 UTC (permalink / raw)
To: Adrian Hunter; +Cc: alexandre.belloni, Frank.Li, Wolfram Sang, linux-i3c
On Fri, 16 Jan 2026, Adrian Hunter wrote:
> 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_restore_daa() helper which additionally handles the case where
> devices are assigned different dynamic addresses after a hibernation boot.
Why do you make this distinction ?
RSTDAA+DAA during boot is motivated by that uboot might have assigned
addresses.
Why would we need to behave differently in suspend and suspend-to-disk?
Its fair to assume that I3C devices might have been powered off in suspend
too, right ?
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> drivers/i3c/master/mipi-i3c-hci/core.c | 53 ++++++++++++++++++++++++++
> 1 file changed, 53 insertions(+)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index 02c5a133e329..b972d8bc81e6 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -769,6 +769,53 @@ 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 restore)
> +{
> + 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;
> +
> + if (restore)
> + ret = i3c_master_restore_daa(&hci->master);
> + else
> + ret = i3c_master_do_daa(&hci->master);
> +
> + 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 +992,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)
> };
>
> --
> 2.51.0
>
>
> --
> linux-i3c mailing list
> linux-i3c@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c
>
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support
2026-01-19 6:31 ` David Nyström
@ 2026-01-19 6:49 ` Adrian Hunter
2026-01-19 7:39 ` David Nyström
0 siblings, 1 reply; 10+ messages in thread
From: Adrian Hunter @ 2026-01-19 6:49 UTC (permalink / raw)
To: David Nyström; +Cc: alexandre.belloni, Frank.Li, Wolfram Sang, linux-i3c
On 19/01/2026 08:31, David Nyström wrote:
>
>
> On Fri, 16 Jan 2026, Adrian Hunter wrote:
>
>> 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_restore_daa() helper which additionally handles the case where
>> devices are assigned different dynamic addresses after a hibernation boot.
>
> Why do you make this distinction ?
> RSTDAA+DAA during boot is motivated by that uboot might have assigned addresses.
> Why would we need to behave differently in suspend and suspend-to-disk?
Because, in the case of suspend-to-disk, there is a complete
boot process in between.
> Its fair to assume that I3C devices might have been powered off in suspend too, right ?
Hibernation is quite different. Briefly:
Entry
ops->freeze
create image
ops->thaw
write image
ops->poweroff
Exit
boot <- address assignment not guaranteed to be the same as previous boot
ops->freeze
restore image
ops->restore <- deal with I3C devices that may have different addresses
>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>> drivers/i3c/master/mipi-i3c-hci/core.c | 53 ++++++++++++++++++++++++++
>> 1 file changed, 53 insertions(+)
>>
>> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
>> index 02c5a133e329..b972d8bc81e6 100644
>> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
>> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
>> @@ -769,6 +769,53 @@ 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 restore)
>> +{
>> + 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;
>> +
>> + if (restore)
>> + ret = i3c_master_restore_daa(&hci->master);
>> + else
>> + ret = i3c_master_do_daa(&hci->master);
>> +
>> + 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 +992,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)
>> };
>>
>> --
>> 2.51.0
>>
>>
>> --
>> linux-i3c mailing list
>> linux-i3c@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-i3c
>>
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support
2026-01-19 6:49 ` Adrian Hunter
@ 2026-01-19 7:39 ` David Nyström
2026-01-19 9:15 ` Adrian Hunter
0 siblings, 1 reply; 10+ messages in thread
From: David Nyström @ 2026-01-19 7:39 UTC (permalink / raw)
To: Adrian Hunter
Cc: David Nyström, alexandre.belloni, Frank.Li, Wolfram Sang,
linux-i3c
[-- Attachment #1: Type: text/plain, Size: 4538 bytes --]
On Mon, 19 Jan 2026, Adrian Hunter wrote:
> On 19/01/2026 08:31, David Nyström wrote:
>>
>>
>> On Fri, 16 Jan 2026, Adrian Hunter wrote:
>>
>>> 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_restore_daa() helper which additionally handles the case where
>>> devices are assigned different dynamic addresses after a hibernation boot.
>>
>> Why do you make this distinction ?
>> RSTDAA+DAA during boot is motivated by that uboot might have assigned addresses.
>> Why would we need to behave differently in suspend and suspend-to-disk?
>
> Because, in the case of suspend-to-disk, there is a complete
> boot process in between.
>
>> Its fair to assume that I3C devices might have been powered off in suspend too, right ?
>
> Hibernation is quite different. Briefly:
>
> Entry
> ops->freeze
> create image
> ops->thaw
> write image
> ops->poweroff
>
> Exit
> boot <- address assignment not guaranteed to be the same as previous boot
> ops->freeze
> restore image
> ops->restore <- deal with I3C devices that may have different addresses
OK, so bootloader might have messed things up for us again.
Thanks for elaborating.
>>
>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>> ---
>>> drivers/i3c/master/mipi-i3c-hci/core.c | 53 ++++++++++++++++++++++++++
>>> 1 file changed, 53 insertions(+)
>>>
>>> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
>>> index 02c5a133e329..b972d8bc81e6 100644
>>> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
>>> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
>>> @@ -769,6 +769,53 @@ 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 restore)
>>> +{
>>> + 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;
>>> +
>>> + if (restore)
>>> + ret = i3c_master_restore_daa(&hci->master);
>>> + else
>>> + ret = i3c_master_do_daa(&hci->master);
>>> +
>>> + 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 +992,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)
>>> };
>>>
>>> --
>>> 2.51.0
>>>
>>>
>>> --
>>> linux-i3c mailing list
>>> linux-i3c@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-i3c
>>>
>
>
> --
> linux-i3c mailing list
> linux-i3c@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c
>
[-- Attachment #2: Type: text/plain, Size: 111 bytes --]
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support
2026-01-19 7:39 ` David Nyström
@ 2026-01-19 9:15 ` Adrian Hunter
0 siblings, 0 replies; 10+ messages in thread
From: Adrian Hunter @ 2026-01-19 9:15 UTC (permalink / raw)
To: David Nyström; +Cc: alexandre.belloni, Frank.Li, Wolfram Sang, linux-i3c
On 19/01/2026 09:39, David Nyström wrote:
>
>
> On Mon, 19 Jan 2026, Adrian Hunter wrote:
>
>> On 19/01/2026 08:31, David Nyström wrote:
>>>
>>>
>>> On Fri, 16 Jan 2026, Adrian Hunter wrote:
>>>
>>>> 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_restore_daa() helper which additionally handles the case where
>>>> devices are assigned different dynamic addresses after a hibernation boot.
>>>
>>> Why do you make this distinction ?
>>> RSTDAA+DAA during boot is motivated by that uboot might have assigned addresses.
>>> Why would we need to behave differently in suspend and suspend-to-disk?
>>
>> Because, in the case of suspend-to-disk, there is a complete
>> boot process in between.
>>
>>> Its fair to assume that I3C devices might have been powered off in suspend too, right ?
>>
>> Hibernation is quite different. Briefly:
>>
>> Entry
>> ops->freeze
>> create image
>> ops->thaw
>> write image
>> ops->poweroff
>>
>> Exit
>> boot <- address assignment not guaranteed to be the same as previous boot
>> ops->freeze
>> restore image
>> ops->restore <- deal with I3C devices that may have different addresses
>
> OK, so bootloader might have messed things up for us again.
No, it is the kernel that cannot guarantee that an I3C device
will have the same dynamic address from one boot to the next.
Generally, the same address will be assigned. However the
case I have experienced is the first I3C device does not come
back after hibernation, and all the subsequent devices are given
different addresses, and then none of them work.
> Thanks for elaborating.
>
>>>
>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>> ---
>>>> drivers/i3c/master/mipi-i3c-hci/core.c | 53 ++++++++++++++++++++++++++
>>>> 1 file changed, 53 insertions(+)
>>>>
>>>> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
>>>> index 02c5a133e329..b972d8bc81e6 100644
>>>> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
>>>> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
>>>> @@ -769,6 +769,53 @@ 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 restore)
>>>> +{
>>>> + 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;
>>>> +
>>>> + if (restore)
>>>> + ret = i3c_master_restore_daa(&hci->master);
>>>> + else
>>>> + ret = i3c_master_do_daa(&hci->master);
>>>> +
>>>> + 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 +992,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)
>>>> };
>>>>
>>>> --
>>>> 2.51.0
>>>>
>>>>
>>>> --
>>>> linux-i3c mailing list
>>>> linux-i3c@lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/linux-i3c
>>>>
>>
>>
>> --
>> linux-i3c mailing list
>> linux-i3c@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-i3c
>>
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-03-11 22:01 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-16 15:12 [PATCH 0/3] i3c: mipi-i3c-hci-pci: Add System Suspend support Adrian Hunter
2026-01-16 15:12 ` [PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery Adrian Hunter
2026-01-16 15:29 ` Frank Li
2026-01-16 15:12 ` [PATCH 2/3] i3c: mipi-i3c-hci: Add optional System Suspend support Adrian Hunter
2026-01-16 15:37 ` Frank Li
2026-01-19 6:31 ` David Nyström
2026-01-19 6:49 ` Adrian Hunter
2026-01-19 7:39 ` David Nyström
2026-01-19 9:15 ` Adrian Hunter
2026-01-16 15:12 ` [PATCH 3/3] i3c: mipi-i3c-hci-pci: Add " Adrian Hunter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox