diff --git a/drivers/i3c/i3c_ccc.c b/drivers/i3c/i3c_ccc.c index da914a233b7..a19184ce053 100644 --- a/drivers/i3c/i3c_ccc.c +++ b/drivers/i3c/i3c_ccc.c @@ -130,7 +130,8 @@ int i3c_ccc_do_setdasa(const struct i3c_device_desc *target) * Note that the 7-bit address needs to start at bit 1 * (aka left-justified). So shift left by 1; */ - dyn_addr = target->static_addr << 1; + dyn_addr = (target->init_dynamic_addr ? + target->init_dynamic_addr : target->static_addr) << 1; ccc_tgt_payload.addr = target->static_addr; ccc_tgt_payload.rnw = 0; diff --git a/drivers/i3c/i3c_common.c b/drivers/i3c/i3c_common.c index fea6634bb28..7f00217440b 100644 --- a/drivers/i3c/i3c_common.c +++ b/drivers/i3c/i3c_common.c @@ -402,23 +402,13 @@ static int i3c_bus_setdasa(const struct device *dev, continue; } - /* - * If there is a desired dynamic address and it is - * not the same as the static address, wait till - * ENTDAA to do address assignment as this is - * no longer SETDASA. - */ - if ((desc->init_dynamic_addr != 0U) && - (desc->init_dynamic_addr != desc->static_addr)) { - *need_daa = true; - continue; - } - LOG_DBG("SETDASA for 0x%x", desc->static_addr); ret = i3c_ccc_do_setdasa(desc); if (ret == 0) { - desc->dynamic_addr = desc->static_addr; + desc->dynamic_addr = (desc->init_dynamic_addr ? desc->init_dynamic_addr + : desc->static_addr); + i3c_reattach_i3c_device(desc, desc->static_addr); } else { LOG_ERR("SETDASA error on address 0x%x (%d)", desc->static_addr, ret); diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index 3f6fb332fc3..57501de7979 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -487,6 +487,23 @@ __subsystem struct i3c_driver_api { */ int (*recover_bus)(const struct device *dev); + /** + * I3C Address Update + * + * Optional Controller only API. + * + * @see i3c_reattach_i3c_device + * + * @param dev Pointer to controller device driver instance. + * @param target Pointer to target device descriptor. + * @param old_dyn_addr Old dynamic address + * + * @return @see i3c_reattach_i3c_device + */ + int (*reattach_i3c_device)(const struct device *dev, + struct i3c_device_desc *target, + uint8_t old_dyn_addr); + /** * Perform Dynamic Address Assignment via ENTDAA. * @@ -1083,6 +1100,37 @@ static inline int i3c_recover_bus(const struct device *dev) return api->recover_bus(dev); } +/** + * @brief Reattach I3C device + * + * called after every time an I3C device has its address + * changed. It can be because the device has been powered + * down and has lost its address, or it can happen when a + * device had a static address and has been assigned a + * dynamic address with SETDASA or a dynamic address has + * been updated with SETNEWDA. + * This method is optional. + * + * @param target Pointer to the target device descriptor + * @param old_dyn_addr The old dynamic address of target device, 0 if + * there was no old dynamic address + * + * @retval 0 If successful. + * @retval -EINVAL If address is not available + */ +static inline int i3c_reattach_i3c_device(struct i3c_device_desc *target, + uint8_t old_dyn_addr) +{ + const struct i3c_driver_api *api = + (const struct i3c_driver_api *)target->bus->api; + + if (api->reattach_i3c_device == NULL) { + return -ENOSYS; + } + + return api->reattach_i3c_device(target->bus, target, old_dyn_addr); +} + /** * @brief Perform Dynamic Address Assignment on the I3C bus. *