[PATCH 1/3] i3c: master: Add i3c_master_restore_daa() for post-hibernation address recovery

Frank Li Frank.li at nxp.com
Fri Jan 16 07:29:59 PST 2026


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 at 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 at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c



More information about the linux-i3c mailing list