/*
 * Copyright (c) 2022 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <string.h>
#include <stdlib.h>

#include <zephyr/toolchain.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/slist.h>
#include <zephyr/sys/byteorder.h>

#include <zephyr/drivers/i3c.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(i3c, CONFIG_I3C_LOG_LEVEL);

void i3c_dump_msgs(const char *name, const struct i3c_msg *msgs, uint8_t num_msgs,
		   struct i3c_device_desc *target)
{
	LOG_DBG("I3C msg: %s, addr=%x", name, target->dynamic_addr);
	for (unsigned int i = 0; i < num_msgs; i++) {
		const struct i3c_msg *msg = &msgs[i];

		LOG_DBG("   %c len=%02x: ", msg->flags & I3C_MSG_READ ? 'R' : 'W', msg->len);
		if (!(msg->flags & I3C_MSG_READ)) {
			LOG_HEXDUMP_DBG(msg->buf, msg->len, "contents:");
		}
	}
}

void i3c_addr_slots_set(struct i3c_addr_slots *slots, uint8_t dev_addr,
			enum i3c_addr_slot_status status)
{
	int bitpos;
	int idx;

	__ASSERT_NO_MSG(slots != NULL);

	if (dev_addr > I3C_MAX_ADDR) {
		/* Invalid address. Do nothing. */
		return;
	}

	bitpos = dev_addr * 2;
	idx = bitpos / BITS_PER_LONG;
	bitpos %= BITS_PER_LONG;

	slots->slots[idx] &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK << bitpos);
	slots->slots[idx] |= status << bitpos;
}

enum i3c_addr_slot_status i3c_addr_slots_status(struct i3c_addr_slots *slots, uint8_t dev_addr)
{
	unsigned long status;
	int bitpos;
	int idx;

	__ASSERT_NO_MSG(slots != NULL);

	if (dev_addr > I3C_MAX_ADDR) {
		/* Invalid address.
		 * Simply says it's reserved so it will not be
		 * used for anything.
		 */
		return I3C_ADDR_SLOT_STATUS_RSVD;
	}

	bitpos = dev_addr * 2;
	idx = bitpos / BITS_PER_LONG;
	bitpos %= BITS_PER_LONG;

	status = slots->slots[idx] >> bitpos;
	status &= I3C_ADDR_SLOT_STATUS_MASK;

	return status;
}

int i3c_addr_slots_init(const struct device *dev)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)dev->data;
	const struct i3c_driver_config *config = (const struct i3c_driver_config *)dev->config;
	int i, ret = 0;
	struct i3c_device_desc *i3c_dev;
	struct i3c_i2c_device_desc *i2c_dev;

	__ASSERT_NO_MSG(dev != NULL);

	(void)memset(&data->attached_dev.addr_slots, 0, sizeof(data->attached_dev.addr_slots));
	sys_slist_init(&data->attached_dev.devices.i3c);
	sys_slist_init(&data->attached_dev.devices.i2c);

	/* Address restrictions (ref 5.1.2.2.5, Specification for I3C v1.1.1) */
	for (i = 0; i <= 7; i++) {
		/* Addresses 0 to 7 are reserved */
		i3c_addr_slots_set(&data->attached_dev.addr_slots, i, I3C_ADDR_SLOT_STATUS_RSVD);

		/*
		 * Addresses within a single bit error of broadcast address
		 * are also reserved.
		 */
		i3c_addr_slots_set(&data->attached_dev.addr_slots, I3C_BROADCAST_ADDR ^ BIT(i),
				   I3C_ADDR_SLOT_STATUS_RSVD);
	}

	/* The broadcast address is reserved */
	i3c_addr_slots_set(&data->attached_dev.addr_slots, I3C_BROADCAST_ADDR,
			   I3C_ADDR_SLOT_STATUS_RSVD);

	/*
	 * Mark all I2C addresses first.
	 */
	for (i = 0; i < config->dev_list.num_i2c; i++) {
		i2c_dev = &config->dev_list.i2c[i];
		ret = i3c_attach_i2c_device(i2c_dev);
		if (ret != 0) {
			/* Address slot is not free */
			ret = -EINVAL;
			goto out;
		}
	}

	/*
	 * If there is a static address for the I3C devices, check
	 * if this address is free, and there is no other devices of
	 * the same (pre-assigned) address on the bus.
	 */
	for (i = 0; i < config->dev_list.num_i3c; i++) {
		i3c_dev = &config->dev_list.i3c[i];
		ret = i3c_attach_i3c_device(i3c_dev);
		if (ret != 0) {
			/* Address slot is not free */
			ret = -EINVAL;
			goto out;
		}
	}

out:
	return ret;
}

bool i3c_addr_slots_is_free(struct i3c_addr_slots *slots, uint8_t dev_addr)
{
	enum i3c_addr_slot_status status;

	__ASSERT_NO_MSG(slots != NULL);

	status = i3c_addr_slots_status(slots, dev_addr);

	return (status == I3C_ADDR_SLOT_STATUS_FREE);
}

uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots, uint8_t start_addr)
{
	uint8_t addr;
	enum i3c_addr_slot_status status;

	/* Addresses 0 to 7 are reserved. So start at 8. */
	for (addr = MAX(start_addr, 8); addr < I3C_MAX_ADDR; addr++) {
		status = i3c_addr_slots_status(slots, addr);
		if (status == I3C_ADDR_SLOT_STATUS_FREE) {
			return addr;
		}
	}

	return 0;
}

struct i3c_device_desc *i3c_dev_list_find(const struct i3c_dev_list *dev_list,
					  const struct i3c_device_id *id)
{
	int i;
	struct i3c_device_desc *ret = NULL;

	__ASSERT_NO_MSG(dev_list != NULL);

	/* this only searches known I3C PIDs */
	for (i = 0; i < dev_list->num_i3c; i++) {
		struct i3c_device_desc *desc = &dev_list->i3c[i];

		if (desc->pid == id->pid) {
			ret = desc;
			break;
		}
	}

	return ret;
}

struct i3c_device_desc *i3c_dev_list_i3c_addr_find(const struct device *dev, uint8_t addr)
{
	struct i3c_device_desc *ret = NULL;
	struct i3c_device_desc *desc;

	__ASSERT_NO_MSG(dev != NULL);

	I3C_BUS_FOR_EACH_I3CDEV(dev, desc) {
		if (desc->dynamic_addr == addr) {
			ret = desc;
			break;
		}
	}

	return ret;
}

struct i3c_device_desc *i3c_dev_list_i3c_static_addr_find(const struct device *dev, uint8_t addr)
{
	struct i3c_device_desc *ret = NULL;
	struct i3c_device_desc *desc;

	__ASSERT_NO_MSG(dev != NULL);

	I3C_BUS_FOR_EACH_I3CDEV(dev, desc) {
		if (desc->static_addr == addr) {
			ret = desc;
			break;
		}
	}

	return ret;
}

struct i3c_i2c_device_desc *i3c_dev_list_i2c_addr_find(const struct device *dev, uint16_t addr)
{
	struct i3c_i2c_device_desc *ret = NULL;
	struct i3c_i2c_device_desc *desc;

	__ASSERT_NO_MSG(dev != NULL);

	I3C_BUS_FOR_EACH_I2CDEV(dev, desc) {
		if (desc->addr == addr) {
			ret = desc;
			break;
		}
	}

	return ret;
}

int i3c_attach_i3c_device(struct i3c_device_desc *target)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
	uint8_t addr = 0;
	int status = 0;
	struct i3c_device_desc *i3c_desc;

	/* check to see if the device has already been attached */
	I3C_BUS_FOR_EACH_I3CDEV(target->bus, i3c_desc) {
		if (i3c_desc == target) {
			return -EALREADY;
		}
	}

	addr = target->dynamic_addr ? target->dynamic_addr : target->static_addr;

	/*
	 * If it has a dynamic addr already assigned or a static address, check that it is free
	 */
	if (addr) {
		if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, addr)) {
			return -EADDRNOTAVAIL;
		}
	}

	sys_slist_append(&data->attached_dev.devices.i3c, &target->node);

	if (api->attach_i3c_device != NULL) {
		status = api->attach_i3c_device(target->bus, target);
	}

	if (addr) {
		i3c_addr_slots_mark_i3c(&data->attached_dev.addr_slots, addr);
	}

	return status;
}

int i3c_reattach_i3c_device(struct i3c_device_desc *target, uint8_t old_dyn_addr)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
	int status = 0;

	if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, target->dynamic_addr)) {
		return -EADDRNOTAVAIL;
	}

	if (api->reattach_i3c_device != NULL) {
		status = api->reattach_i3c_device(target->bus, target, old_dyn_addr);
	}

	if (old_dyn_addr) {
		/* mark the old address as free */
		i3c_addr_slots_mark_free(&data->attached_dev.addr_slots, old_dyn_addr);
	}

	i3c_addr_slots_mark_i3c(&data->attached_dev.addr_slots, target->dynamic_addr);

	return status;
}

int i3c_detach_i3c_device(struct i3c_device_desc *target)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
	int status = 0;

	if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) {
		if (!sys_slist_find_and_remove(&data->attached_dev.devices.i3c, &target->node)) {
			return -EINVAL;
		}
	} else {
		return -EINVAL;
	}

	if (api->detach_i3c_device != NULL) {
		status = api->detach_i3c_device(target->bus, target);
	}

	i3c_addr_slots_mark_free(&data->attached_dev.addr_slots,
				 target->dynamic_addr ? target->dynamic_addr : target->static_addr);

	/* if it was from allocated memory, free it */
	if (i3c_device_desc_in_pool(target)) {
		i3c_device_desc_free(target);
	}

	return status;
}

int i3c_attach_i2c_device(struct i3c_i2c_device_desc *target)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
	int status = 0;
	struct i3c_i2c_device_desc *i3c_i2c_desc;

	/* check to see if the device has already been attached */
	I3C_BUS_FOR_EACH_I2CDEV(target->bus, i3c_i2c_desc) {
		if (i3c_i2c_desc == target) {
			return -EALREADY;
		}
	}

	if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, target->addr)) {
		return -EADDRNOTAVAIL;
	}

	sys_slist_append(&data->attached_dev.devices.i2c, &target->node);

	if (api->attach_i2c_device != NULL) {
		status = api->attach_i2c_device(target->bus, target);
	}

	i3c_addr_slots_mark_i2c(&data->attached_dev.addr_slots, target->addr);

	return status;
}

int i3c_detach_i2c_device(struct i3c_i2c_device_desc *target)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
	int status = 0;

	if (!sys_slist_is_empty(&data->attached_dev.devices.i2c)) {
		if (!sys_slist_find_and_remove(&data->attached_dev.devices.i2c, &target->node)) {
			return -EINVAL;
		}
	} else {
		return -EINVAL;
	}

	if (api->detach_i2c_device != NULL) {
		status = api->detach_i2c_device(target->bus, target);
	}

	i3c_addr_slots_mark_free(&data->attached_dev.addr_slots, target->addr);

	/* if it was from allocated memory, free it */
	if (i3c_i2c_device_desc_in_pool(target)) {
		i3c_i2c_device_desc_free(target);
	}

	return status;
}
#ifdef CONFIG_I3C_TARGET
int i3c_sec_get_basic_info(const struct device *dev, uint8_t dynamic_addr, uint8_t static_addr,
			   uint8_t bcr, uint8_t dcr)
{
	struct i3c_ccc_getpid getpid;
	struct i3c_device_desc temp_desc;
	struct i3c_device_desc *desc;
	struct i3c_device_id id;
	const struct i3c_driver_config *config = dev->config;
	int ret;

	temp_desc.bus = dev;
	temp_desc.dynamic_addr = dynamic_addr;
	temp_desc.bcr = bcr;
	temp_desc.dcr = dcr;
	/* attach it first with a temporary value so we can at least get the pid */
	ret = i3c_attach_i3c_device(&temp_desc);
	if (ret != 0) {
		return ret;
	}

	/* First try to look up if this is a known device in the list by PID */
	ret = i3c_ccc_do_getpid(&temp_desc, &getpid);
	if (ret != 0) {
		return ret;
	}

	id.pid = sys_get_be48(getpid.pid);

	/* try to see if we already have a device statically allocated */
	desc = i3c_dev_list_find(&config->dev_list, &id);
	if (!desc) {
		/* device was not found so allocate a descriptor */
		desc = i3c_device_desc_alloc();
		if (!desc) {
			return -ENOMEM;
		}
		desc->pid = id.pid;
		temp_desc.static_addr = (uint16_t)static_addr;
	}
	desc->dynamic_addr = dynamic_addr;
	desc->bcr = bcr;
	desc->dcr = dcr;

	/* Detach that temporary device */
	ret = i3c_detach_i3c_device(&temp_desc);
	if (ret != 0) {
		return ret;
	}
	ret = i3c_attach_i3c_device(desc);
	if (ret != 0) {
		return ret;
	}

	/* Skip reading BCR and DCR as they came from DEFTGTS */
	ret = i3c_device_adv_info_get(desc);

	return ret;
}

int i3c_sec_i2c_attach(const struct device *dev, uint8_t static_addr, uint8_t lvr)
{
	struct i3c_i2c_device_desc *i2c_desc;
	int ret;

	/* try to see if we already have a device statically allocated */
	i2c_desc = i3c_dev_list_i2c_addr_find(dev, (uint16_t)static_addr);
	if (!i2c_desc) {
		/* device was not found so allocate a descriptor */
		i2c_desc = i3c_i2c_device_desc_alloc();
		if (!i2c_desc) {
			return -ENOMEM;
		}
		*(const struct device **)&i2c_desc->bus = dev;
		i2c_desc->addr = (uint16_t)static_addr;
		i2c_desc->lvr = lvr;
	}

	ret = i3c_attach_i2c_device(i2c_desc);
	return ret;
}

static void i3c_sec_bus_reset(const struct device *dev)
{
	struct i3c_device_desc *i3c_desc;
	struct i3c_i2c_device_desc *i3c_i2c_desc;

	I3C_BUS_FOR_EACH_I3CDEV(dev, i3c_desc) {
		i3c_detach_i3c_device(i3c_desc);
	}

	I3C_BUS_FOR_EACH_I2CDEV(dev, i3c_i2c_desc) {
		i3c_detach_i2c_device(i3c_i2c_desc);
	}
}
#ifdef CONFIG_I3C_USE_IBI
/* call this from a workq after the interrupt from a controller */
void i3c_sec_handoffed(struct k_work *work)
{
	struct i3c_ibi_work *ibi_node = CONTAINER_OF(work, struct i3c_ibi_work, work);
	const struct device *dev = ibi_node->controller;
	struct i3c_driver_data *data = (struct i3c_driver_data *)dev->data;
	struct i3c_ccc_deftgts *deftgts = data->deftgts;
	struct i3c_config_target config_target;
	uint8_t n, cur_dyn_addr;
	int ret;

	if (!deftgts) {
		LOG_ERR("Did not receive DEFTGTS before Handoff");
		return;
	}

	if (!data->deftgts_refreshed) {
		LOG_DBG("Already processed DEFTGTS from previous handoff");
		return;
	}

	/* Forget all devices as another controller made changes */
	i3c_sec_bus_reset(dev);

	/*
	 * Retrieve the active controller information
	 */
	ret = i3c_config_get_target(dev, &config_target);
	if (ret != 0) {
		LOG_ERR("Failed to retrieve active controller info");
		return;
	}

	cur_dyn_addr = config_target.dynamic_addr;

	/* Attach the previous AC */
	ret = i3c_sec_get_basic_info(
		dev, deftgts->active_controller.addr, deftgts->active_controller.static_addr,
		deftgts->active_controller.bcr, deftgts->active_controller.dcr);

	/* Attach all Targets */
	for (n = 0; n < deftgts->count; n++) {
		if (deftgts->targets[n].addr != 0) {
			/* Must be an I3C device and skip itself */
			if (deftgts->targets[n].addr != cur_dyn_addr) {
				ret = i3c_sec_get_basic_info(dev, deftgts->targets[n].addr,
							     deftgts->targets[n].static_addr,
							     deftgts->targets[n].bcr,
							     deftgts->targets[n].dcr);
			}
		} else {
			/* Must be an I2C device */
			ret = i3c_sec_i2c_attach(dev, deftgts->targets[n].static_addr,
						 deftgts->targets[n].lvr);
		}
	}

	/* Set false, so the next handoff doesn't retrigger regathering info */
	data->deftgts_refreshed = false;
}
#endif /* CONFIG_I3C_USE_IBI */
#endif /* CONFIG_I3C_TARGET */

int i3c_dev_list_daa_addr_helper(struct i3c_addr_slots *addr_slots,
				 const struct i3c_dev_list *dev_list, uint64_t pid, bool must_match,
				 bool assigned_okay, struct i3c_device_desc **target, uint8_t *addr)
{
	struct i3c_device_desc *desc;
	const uint16_t vendor_id = (uint16_t)(pid >> 32);
	const uint32_t part_no = (uint32_t)(pid & 0xFFFFFFFFU);
	uint8_t dyn_addr = 0;
	int ret = 0;
	const struct i3c_device_id i3c_id = I3C_DEVICE_ID(pid);

	desc = i3c_dev_list_find(dev_list, &i3c_id);
	/* If a device was not found, try to allocate a descriptor */
	if (desc == NULL) {
		desc = i3c_device_desc_alloc();
	}
	if (must_match && (desc == NULL)) {
		/*
		 * No device descriptor matching incoming PID and
		 * that we want an exact match.
		 */
		ret = -ENODEV;

		LOG_DBG("PID 0x%04x%08x is not in registered device list", vendor_id, part_no);

		goto out;
	}

	if (desc != NULL && desc->dynamic_addr != 0U) {
		if (assigned_okay) {
			/* Return the already assigned address if desired so. */
			dyn_addr = desc->dynamic_addr;
			goto out;
		} else {
			/*
			 * Bail If target already has an assigned address.
			 * This is probably due to having the same PIDs for multiple targets
			 * in the device tree.
			 */
			LOG_ERR("PID 0x%04x%08x already has "
				"dynamic address (0x%02x) assigned",
				vendor_id, part_no, desc->dynamic_addr);
			ret = -EINVAL;
			goto err;
		}
	}

	/*
	 * Use the desired dynamic address as the new dynamic address
	 * if the slot is free.
	 */
	if (desc != NULL && desc->init_dynamic_addr != 0U) {
		if (i3c_addr_slots_is_free(addr_slots, desc->init_dynamic_addr)) {
			dyn_addr = desc->init_dynamic_addr;
			goto out;
		}
	}

	/*
	 * Find the next available address.
	 */
	dyn_addr = i3c_addr_slots_next_free_find(addr_slots, 0);

	if (dyn_addr == 0U) {
		/* No free addresses available */
		LOG_DBG("No more free addresses available.");
		ret = -ENOSPC;
	}

out:
	*addr = dyn_addr;
	*target = desc;

err:
	return ret;
}
#ifdef CONFIG_I3C_TARGET
uint8_t i3c_odd_parity(uint8_t p)
{
	p ^= p >> 4;
	p &= 0xf;
	return (0x9669 >> p) & 1;
}

int i3c_device_controller_handoff(struct i3c_device_desc *target, bool requested)
{
	int ret;
	union i3c_ccc_getstatus status = {0};
	struct i3c_ccc_events i3c_events;

	/*
	 * If the Active Controller intends to pass the Controller Role to a selected Secondary
	 * Controller that did not send a Controller Role Request, then the Active Controller should
	 * verify that the selected Secondary Controller is active and ready to respond to
	 * additional commands
	 */
	if (!requested) {
		ret = i3c_ccc_do_getstatus_fmt1(target, &status);
		if (ret != 0) {
			return ret;
		}

		if (I3C_CCC_GETSTATUS_ACTIVITY_MODE(status.fmt1.status) ==
		    I3C_CCC_GETSTATUS_ACTIVITY_MODE_NCH) {
			return -EBUSY;
		}
	}

	/*
	 * The Active Controller needs to disable Hot-Joins, Target Interrupt Requests, and other
	 * Bus events that could interfere with the Handoff, then it sends the appropriate
	 * Broadcast to disable those events before the Handoff. Once the Handoff is complete, the
	 * new Active Controller should re-enable events that are disabled in this step.
	 */
	i3c_events.events = I3C_CCC_EVT_ALL;
	ret = i3c_ccc_do_events_all_set(target->bus, false, &i3c_events);
	if (ret != 0) {
		return ret;
	}

	/** TODO: reconfigure MLANE if needed */

	/*
	 * If the Active Controller knows that the selected Secondary Controller must be put into a
	 * different Activity State before Handoff, then the Active Controller shall send the
	 * appropriate Broadcast or Direct CCCs to put the Bus (or selected Devices) into a
	 * different Activity State
	 */
	if (target->crhdly1 & I3C_CCC_GETMXDS_CRDHLY1_SET_BUS_ACT_STATE) {
		ret = i3c_ccc_do_entas(
			target, I3C_CCC_GETMXDS_CRDHLY1_CTRL_HANDOFF_ACT_STATE(target->crhdly1));
		if (ret != 0) {
			return ret;
		}
	}

	if ((target->getcaps.getcap3 & I3C_CCC_GETCAPS3_GETSTATUS_DEFINING_BYTE_SUPPORT) &&
	    (target->crcaps.crcaps2 & I3C_CCC_GETCAPS_CRCAPS2_DEEP_SLEEP_CAPABLE)) {
		ret = i3c_ccc_do_getstatus_fmt2(target, &status, GETSTATUS_FORMAT_2_PRECR);
		if (ret != 0) {
			return ret;
		}

		/*
		 * If the Active Controller determines that the indicated Secondary Controller has
		 * been in a “deep sleep” state and may need to be re-synchronized with the most
		 * current list of I3C Targets and Group Addresses, then the Active Controller
		 * should send CCC DEFTGTS and DEFGRPA
		 */
		if (status.fmt2.precr & I3C_CCC_GETSTATUS_PRECR_DEEP_SLEEP_DETECTED) {
			ret = i3c_bus_deftgts(target->bus);
			if (ret != 0) {
				return ret;
			}
			/* TODO: broadcast DEFGRPA when group address support comes */

			/* Check CRCAPS if the device needs additional time to process */
			if (target->crcaps.crcaps2 &
			    I3C_CCC_GETCAPS_CRCAPS2_DELAYED_CONTROLLER_HANDOFF) {
				/*
				 * Afterwards, the Active Controller should poll the Secondary
				 * Controller to ensure that it has successfully processed this data
				 * and indicates that it is ready to accept the Controller Role
				 */
				do {
					ret = i3c_ccc_do_getstatus_fmt2(target, &status,
									GETSTATUS_FORMAT_2_PRECR);
					if (ret != 0) {
						return ret;
					}
				} while (!(status.fmt2.precr &
					   I3C_CCC_GETSTATUS_PRECR_HANDOFF_DELAY_NACK));
			}
		}
	}

	/*
	 * After the Active Controller has prepared for Handoff, the Active Controller shall
	 * then issue a GETACCCR CCC
	 */
	ret = i3c_bus_getacccr(target);
	if (ret != 0) {
		return ret;
	}

	return ret;
}
#endif /* CONFIG_I3C_TARGET */
int i3c_device_basic_info_get(struct i3c_device_desc *target)
{
	int ret;

	/* GETBCR */
	ret = i3c_bus_getbcr(target);
	if (ret != 0) {
		return ret;
	}

	/* GETDCR */
	return i3c_bus_getdcr(target);
}

int i3c_device_adv_info_get(struct i3c_device_desc *target)
{
	struct i3c_ccc_mrl mrl = {0};
	struct i3c_ccc_mwl mwl = {0};
	union i3c_ccc_getcaps caps = {0};
	union i3c_ccc_getmxds mxds = {0};
	int ret = 0;

	/* GETMRL */
	if (i3c_ccc_do_getmrl(target, &mrl) != 0) {
		/* GETMRL may be optionally supported if no settable limit */
		LOG_DBG("%s: No settable limit for GETMRL", target->dev->name);
	}

	/* GETMWL */
	if (i3c_ccc_do_getmwl(target, &mwl) != 0) {
		/* GETMWL may be optionally supported if no settable limit */
		LOG_DBG("%s: No settable limit for GETMWL", target->dev->name);
	}

	/* GETCAPS */
	if (((target->flags & I3C_V1P0_SUPPORT) && (target->bcr & I3C_BCR_ADV_CAPABILITIES)) ||
	    (!(target->flags & I3C_V1P0_SUPPORT))) {
		/*
		 * GETCAPS (GETHDRCAP) is required to be supported for I3C v1.0 targets that support
		 * HDR modes and required if the Target's I3C version is v1.1 or later.
		 * It is also possible for this function to be called on an 'unknown' device such as
		 * from a secondary controller gathering info about a target it found about through
		 * DEFTGTS, and it can't be known ahead of time if it is a v1.0 or v1.1 device.
		 */
		if (i3c_ccc_do_getcaps_fmt1(target, &caps) != 0) {
			LOG_DBG("%s: GETCAPS not received", target->dev->name);
		}
	}

	/* CRCAPS */
	if ((target->getcaps.getcap3 & I3C_CCC_GETCAPS3_GETCAPS_DEFINING_BYTE_SUPPORT) &&
	    (i3c_device_is_controller_capable(target))) {
		ret = i3c_ccc_do_getcaps_fmt2(target, &caps, GETCAPS_FORMAT_2_CRCAPS);
		if (ret != 0) {
			return ret;
		}
	}

	/* GETMXDS */
	if (target->bcr & I3C_BCR_MAX_DATA_SPEED_LIMIT) {
		ret = i3c_ccc_do_getmxds_fmt2(target, &mxds);
		if (ret != 0) {
			return ret;
		}

		/* Get CRHDLY if supported */
		if ((target->data_speed.maxwr & I3C_CCC_GETMXDS_MAXWR_DEFINING_BYTE_SUPPORT) &&
		    (i3c_device_is_controller_capable(target))) {
			ret = i3c_ccc_do_getmxds_fmt3(target, &mxds, GETMXDS_FORMAT_3_CRHDLY);
			if (ret != 0) {
				return ret;
			}

			target->crhdly1 = mxds.fmt3.crhdly1;
		}
	}

	target->data_length.mrl = mrl.len;
	target->data_length.mwl = mwl.len;
	target->data_length.max_ibi = mrl.ibi_len;

	return ret;
}

/**
 * @brief Do SETDASA to set static address as dynamic address.
 *
 * @param dev Pointer to the device driver instance.
 * @param[out] True if DAA is still needed. False if all registered
 *             devices have static addresses.
 *
 * @retval 0 if successful.
 */
static int i3c_bus_prepare_setdasa(const struct device *dev, const struct i3c_dev_list *dev_list,
				   bool *need_daa, bool *need_aasa)
{
	int i, ret;

	*need_daa = false;
	*need_aasa = false;

	/* Loop through the registered I3C devices */
	for (i = 0; i < dev_list->num_i3c; i++) {
		struct i3c_device_desc *desc = &dev_list->i3c[i];
		struct i3c_driver_data *bus_data = (struct i3c_driver_data *)dev->data;
		uint8_t dynamic_addr;

		/*
		 * A device without static address => need to do
		 * dynamic address assignment.
		 */
		if (desc->static_addr == 0U) {
			*need_daa = true;
			continue;
		}

		/*
		 * A device that supports SETAASA and will use the same dynamic
		 * address as its static address if a different dynamic address
		 * is not requested
		 */
		if ((desc->flags & I3C_SUPPORTS_SETAASA) &&
		    ((desc->init_dynamic_addr == 0) ||
		     desc->init_dynamic_addr == desc->static_addr)) {
			*need_aasa = true;
			continue;
		}

		/*
		 * check that initial dynamic address is free before setting it
		 * if configured
		 */
		if ((desc->init_dynamic_addr != 0) &&
		    (desc->init_dynamic_addr != desc->static_addr)) {
			if (!i3c_addr_slots_is_free(&bus_data->attached_dev.addr_slots,
						    desc->init_dynamic_addr)) {
				if (i3c_detach_i3c_device(desc) != 0) {
					LOG_ERR("Failed to detach %s", desc->dev->name);
				}
				continue;
			}
		}

		/*
		 * If the device has a static address, set the dynamic address
		 * to the static address if there is no requested dynamic address.
		 */
		dynamic_addr =
			desc->init_dynamic_addr ? desc->init_dynamic_addr : desc->static_addr;

		ret = i3c_bus_setdasa(desc, dynamic_addr);
		if (ret != 0) {
			LOG_ERR("SETDASA error on address 0x%x (%d)", desc->static_addr, ret);
			/* SETDASA failed, detach it from the controller */
			if (i3c_detach_i3c_device(desc) != 0) {
				LOG_ERR("Failed to detach %s (%d)", desc->dev->name, ret);
			}
		}
	}

	return 0;
}

bool i3c_bus_has_sec_controller(const struct device *dev)
{
	struct i3c_device_desc *i3c_desc;

	I3C_BUS_FOR_EACH_I3CDEV(dev, i3c_desc) {
		if (i3c_device_is_controller_capable(i3c_desc)) {
			return true;
		}
	}

	return false;
}

#ifdef CONFIG_I3C_CONTROLLER
int i3c_bus_rstdaa_all(const struct device *dev)
{
	struct i3c_device_desc *desc;
	int ret;

	ret = i3c_ccc_do_rstdaa_all(dev);
	if (ret != 0) {
		LOG_ERR("%s: RSTDAA error (%d)", dev->name, ret);
		return ret;
	}

	/* reset all devices' DA */
	I3C_BUS_FOR_EACH_I3CDEV(dev, desc) {
		desc->dynamic_addr = 0;
		LOG_DBG("%s: Reset dynamic address for device %s", dev->name, desc->dev->name);
	}

	return ret;
}

int i3c_bus_setdasa(struct i3c_device_desc *desc, uint8_t dynamic_addr)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)desc->bus->data;
	struct i3c_ccc_address dyn_addr;
	int ret;

	/* check if the addressed is free, if the requested DA is different from the SA */
	if (desc->static_addr != dynamic_addr) {
		if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, dynamic_addr)) {
			LOG_ERR("%s: Address 0x%02x is already in use.", desc->bus->name,
				dynamic_addr);
			return -EADDRNOTAVAIL;
		}
	}

	/*
	 * Note that the 7-bit address needs to start at bit 1
	 * (aka left-justified). So shift left by 1;
	 */
	dyn_addr.addr = dynamic_addr << 1;

	ret = i3c_ccc_do_setdasa(desc, dyn_addr);
	if (ret != 0) {
		LOG_ERR("%s: %s: SETDASA error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* update the target's dynamic address */
	desc->dynamic_addr = dynamic_addr;
	if (desc->dynamic_addr != desc->static_addr) {
		ret = i3c_reattach_i3c_device(desc, desc->static_addr);
		if (ret < 0) {
			LOG_ERR("%s: %s: unable to reattach device (%d)", desc->bus->name,
				desc->dev->name, ret);
			return ret;
		}
	}
	LOG_DBG("%s: %s: SETDASA to 0x%02x", desc->bus->name, desc->dev->name, desc->dynamic_addr);

	return ret;
}

int i3c_bus_setnewda(struct i3c_device_desc *desc, uint8_t dynamic_addr)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)desc->bus->data;
	struct i3c_ccc_address dyn_addr;
	uint8_t old_da;
	int ret;

	/* check if the addressed is free, also a 'clown' could set the same DA */
	if (desc->dynamic_addr != dynamic_addr) {
		if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, dynamic_addr)) {
			LOG_ERR("%s: Address 0x%02x is already in use.", desc->bus->name,
				dynamic_addr);
			return -EADDRNOTAVAIL;
		}
	}

	/*
	 * Note that the 7-bit address needs to start at bit 1
	 * (aka left-justified). So shift left by 1;
	 */
	dyn_addr.addr = dynamic_addr << 1;

	ret = i3c_ccc_do_setnewda(desc, dyn_addr);
	if (ret != 0) {
		LOG_ERR("%s: %s: SETNEWDA error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* update the target's dynamic address */
	old_da = desc->dynamic_addr;
	desc->dynamic_addr = dynamic_addr;
	/* reattach device address */
	ret = i3c_reattach_i3c_device(desc, old_da);
	if (ret != 0) {
		LOG_ERR("%s: %s: unable to reattach device", desc->bus->name, desc->dev->name);
		return ret;
	}
	LOG_DBG("%s: %s: SETNEWDA to 0x%02x", desc->bus->name, desc->dev->name, desc->dynamic_addr);

	return ret;
}

int i3c_bus_setaasa(const struct device *dev)
{
	struct i3c_device_desc *desc;
	int ret;

	ret = i3c_ccc_do_setaasa_all(dev);
	if (ret != 0) {
		LOG_ERR("%s: unable to send CCC SETAASA", dev->name);
		return ret;
	}

	/*
	 * set all devices DA to SA if it is known that it supports SETAASA and doesn't currently
	 * have a dynamic address
	 */
	I3C_BUS_FOR_EACH_I3CDEV(dev, desc) {
		if ((desc->flags & I3C_SUPPORTS_SETAASA) && (desc->dynamic_addr == 0) &&
		    (desc->static_addr != 0)) {
			desc->dynamic_addr = desc->static_addr;
			LOG_DBG("%s: %s: SETAASA to 0x%02x", dev->name, desc->dev->name,
				desc->dynamic_addr);
		}
	}

	return ret;
}

int i3c_bus_getbcr(struct i3c_device_desc *desc)
{
	struct i3c_ccc_getbcr getbcr;
	int ret;

	ret = i3c_ccc_do_getbcr(desc, &getbcr);
	if (ret != 0) {
		LOG_ERR("%s: %s: GETBCR error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* update the target's BCR */
	desc->bcr = getbcr.bcr;
	LOG_DBG("%s: %s: GETBCR 0x%02x", desc->bus->name, desc->dev->name, desc->bcr);

	return ret;
}

int i3c_bus_getdcr(struct i3c_device_desc *desc)
{
	struct i3c_ccc_getdcr getdcr;
	int ret;

	ret = i3c_ccc_do_getdcr(desc, &getdcr);
	if (ret != 0) {
		LOG_ERR("%s: %s: GETDCR error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* update the target's DCR */
	desc->dcr = getdcr.dcr;
	LOG_DBG("%s: %s: GETDCR 0x%02x", desc->bus->name, desc->dev->name, desc->dcr);

	return ret;
}

int i3c_bus_getpid(struct i3c_device_desc *desc)
{
	struct i3c_ccc_getpid getpid;
	int ret;

	ret = i3c_ccc_do_getpid(desc, &getpid);
	if (ret != 0) {
		LOG_ERR("%s: %s: GETPID error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* update the target's PID */
	desc->pid = sys_get_be48(getpid.pid);
	LOG_DBG("%s: %s: GETPID 0x%012llx", desc->bus->name, desc->dev->name,
		sys_get_be48(getpid.pid));

	return ret;
}

int i3c_bus_getmrl(struct i3c_device_desc *desc)
{
	struct i3c_ccc_mrl mrl;
	int ret;

	ret = i3c_ccc_do_getmrl(desc, &mrl);
	if (ret != 0) {
		LOG_ERR("%s: %s: GETMRL error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* update the target's MRL */
	desc->data_length.mrl = mrl.len;
	if (desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) {
		desc->data_length.max_ibi = mrl.ibi_len;
		LOG_DBG("%s: %s: GETMRL 0x%04x IBI len 0x%02x", desc->bus->name, desc->dev->name,
			desc->data_length.mrl, desc->data_length.max_ibi);
	} else {
		desc->data_length.max_ibi = 0;
		LOG_DBG("%s: %s: GETMRL 0x%04x", desc->bus->name, desc->dev->name,
			desc->data_length.mrl);
	}

	return ret;
}

int i3c_bus_getmwl(struct i3c_device_desc *desc)
{
	struct i3c_ccc_mwl mwl;
	int ret;

	ret = i3c_ccc_do_getmwl(desc, &mwl);
	if (ret != 0) {
		LOG_ERR("%s: %s: GETMWL error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* update the target's MWL */
	desc->data_length.mwl = mwl.len;
	LOG_DBG("%s: %s: GETMWL 0x%04x", desc->bus->name, desc->dev->name, desc->data_length.mwl);

	return ret;
}

int i3c_bus_setmrl(struct i3c_device_desc *desc, uint16_t mrl, uint8_t ibi_len)
{
	struct i3c_ccc_mrl mrl_cmd;
	int ret;

	mrl_cmd.len = mrl;

	ret = i3c_ccc_do_setmrl(desc, &mrl_cmd);
	if (ret != 0) {
		LOG_ERR("%s: %s: SETMRL error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	desc->data_length.mrl = mrl_cmd.len;
	if (desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) {
		desc->data_length.max_ibi = ibi_len;
		LOG_DBG("%s: %s: SETMRL 0x%04x IBI len 0x%04x", desc->bus->name, desc->dev->name,
			desc->data_length.mrl, desc->data_length.max_ibi);
	} else {
		desc->data_length.max_ibi = 0;
		LOG_DBG("%s: %s: SETMRL 0x%04x", desc->bus->name, desc->dev->name,
			desc->data_length.mrl);
	}

	return ret;
}

int i3c_bus_setmwl(struct i3c_device_desc *desc, uint16_t mwl)
{
	struct i3c_ccc_mwl mwl_cmd;
	int ret;

	mwl_cmd.len = mwl;

	ret = i3c_ccc_do_setmwl(desc, &mwl_cmd);
	if (ret != 0) {
		LOG_ERR("%s: %s: SETMWL error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	desc->data_length.mwl = mwl_cmd.len;
	LOG_DBG("%s: %s: SETMWL 0x%04x", desc->bus->name, desc->dev->name, desc->data_length.mwl);

	return ret;
}

int i3c_bus_setmrl_all(const struct device *dev, uint16_t mrl, uint8_t ibi_len, bool has_ibi_size)
{
	struct i3c_device_desc *desc;
	const struct i3c_ccc_mrl setmrl = {
		.len = mrl,
		.ibi_len = ibi_len,
	};
	int ret;

	ret = i3c_ccc_do_setmrl_all(dev, &setmrl, has_ibi_size);
	if (ret < 0) {
		LOG_ERR("%s: SETMRL error (%d)", dev->name, ret);
		return ret;
	}

	I3C_BUS_FOR_EACH_I3CDEV(dev, desc) {
		desc->data_length.mrl = setmrl.len;
		/*
		 * Set mrl ibi len, if payload has data bytes and ibi len was transmitted
		 * otherwise, set to 0, or leave as is if ibi len was not transmitted
		 */
		if (has_ibi_size) {
			if (desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) {
				desc->data_length.max_ibi = setmrl.ibi_len;
				LOG_DBG("%s: %s: SETMRL 0x%04x IBI len 0x%02x", desc->bus->name,
					desc->dev->name, desc->data_length.mrl,
					desc->data_length.max_ibi);
			} else {
				desc->data_length.max_ibi = 0;
				LOG_DBG("%s: %s: SETMRL 0x%04x", desc->bus->name, desc->dev->name,
					desc->data_length.mrl);
			}
		}
	}

	return ret;
}

int i3c_bus_setmwl_all(const struct device *dev, uint16_t mwl)
{
	const struct i3c_ccc_mwl setmwl = {
		.len = mwl,
	};
	struct i3c_device_desc *desc;
	int ret;

	ret = i3c_ccc_do_setmwl_all(dev, &setmwl);
	if (ret < 0) {
		LOG_ERR("%s: unable to send CCC SETMWL BC.", dev->name);
		return ret;
	}

	I3C_BUS_FOR_EACH_I3CDEV(dev, desc) {
		desc->data_length.mwl = setmwl.len;
		LOG_DBG("%s: %s: SETMWL 0x%04x", desc->bus->name, desc->dev->name,
			desc->data_length.mwl);
	}

	return ret;
}
#ifdef CONFIG_I3C_TARGET
int i3c_bus_getacccr(struct i3c_device_desc *desc)
{
	struct i3c_ccc_address handoff_address;
	int ret;

	ret = i3c_ccc_do_getacccr(desc, &handoff_address);
	if (ret != 0) {
		LOG_ERR("%s: %s: GETACCCR error (%d)", desc->bus->name, desc->dev->name, ret);
		return ret;
	}

	/* Verify Odd Parity and Correct Dynamic Address Reply */
	if ((i3c_odd_parity(handoff_address.addr >> 1) != (handoff_address.addr & BIT(0))) ||
	    (handoff_address.addr >> 1 != desc->dynamic_addr)) {
		LOG_ERR("%s: %s: GETACCCR invalid response", desc->bus->name, desc->dev->name);
		return -EPROTO;
	}

	return ret;
}

int i3c_bus_deftgts(const struct device *dev)
{
	struct i3c_driver_data *data = (struct i3c_driver_data *)dev->data;
	struct i3c_config_target config_target;
	struct i3c_ccc_deftgts *deftgts;
	struct i3c_device_desc *i3c_desc;
	struct i3c_i2c_device_desc *i3c_i2c_desc;
	int ret;
	uint8_t n = 0;
	size_t num_of_targets = sys_slist_len(&data->attached_dev.devices.i3c) +
				sys_slist_len(&data->attached_dev.devices.i2c);
	size_t data_len = sizeof(uint8_t) + sizeof(struct i3c_ccc_deftgts_active_controller) +
			  (num_of_targets * sizeof(struct i3c_ccc_deftgts_target));

	/*
	 * Retrieve the active controller information
	 */
	ret = i3c_config_get(dev, I3C_CONFIG_TARGET, &config_target);
	if (ret != 0) {
		LOG_ERR("Failed to retrieve active controller info");
		return ret;
	}

	/* Allocate memory for the struct with enough space for the targets */
	deftgts = malloc(data_len);
	if (!deftgts) {
		return -ENOMEM;
	}

	/*
	 * Write the total number of I3C and I2C targets to the payload
	 */
	deftgts->count = num_of_targets;

	/*
	 * Add the active controller information to the payload
	 */
	deftgts->active_controller.addr = config_target.dynamic_addr << 1;
	deftgts->active_controller.dcr = config_target.dcr;
	deftgts->active_controller.bcr = config_target.bcr;
	deftgts->active_controller.static_addr = I3C_BROADCAST_ADDR << 1;

	/*
	 * Loop through each attached I3C device and add it to the payload
	 */
	I3C_BUS_FOR_EACH_I3CDEV(dev, i3c_desc) {
		deftgts->targets[n].addr = i3c_desc->dynamic_addr << 1;
		deftgts->targets[n].dcr = i3c_desc->dcr;
		deftgts->targets[n].bcr = i3c_desc->bcr;
		deftgts->targets[n].static_addr = i3c_desc->static_addr << 1;
		n++;
	}

	/*
	 * Loop through each attached I2C device and add it to the payload
	 */
	I3C_BUS_FOR_EACH_I2CDEV(dev, i3c_i2c_desc) {
		deftgts->targets[n].addr = 0;
		deftgts->targets[n].lvr = i3c_i2c_desc->lvr;
		deftgts->targets[n].bcr = 0;
		deftgts->targets[n].static_addr = (uint8_t)(i3c_i2c_desc->addr << 1);
		n++;
	}

	/* TODO: add support for Group Addr in DEFTGTS when that comes */

	ret = i3c_ccc_do_deftgts_all(dev, deftgts);

	free(deftgts);

	return ret;
}
#endif /* CONFIG_I3C_TARGET */
#endif /* CONFIG_I3C_CONTROLLER */
int i3c_bus_init(const struct device *dev, const struct i3c_dev_list *dev_list)
{
	int i, ret = 0;
	bool need_daa = true;
	bool need_aasa = true;
	struct i3c_ccc_events i3c_events;
	struct i3c_config_controller ctrl_cfg;
	uint32_t prev_od_high_ns;

	/* Retrieve the active controller configuration */
	ret = i3c_config_get_controller(dev, &ctrl_cfg);
	if (ret != 0) {
		LOG_ERR("%s: Failed to retrieve controller configuration", dev->name);
		return ret;
	}

	/* Set OD high period for first broadcast message.
	 * The Controller uses this timing to send the
	 * first Broadcast Address, in order to disable the
	 * I2C Spike Filter for applicable I3C Basic Target Devices.
	 * Ref Section 4.3.2.2.2 and Table 49 of
	 * MIPI ALLIANCE Specification for I3C Basic Version 1.2
	 */
	prev_od_high_ns = ctrl_cfg.scl_od_min.high_ns;
	ctrl_cfg.scl_od_min.high_ns = MAX(I3C_OD_FIRST_BC_THIGH_MIN_NS,
					ctrl_cfg.scl_od_min.high_ns);

	ret = i3c_configure_controller(dev, &ctrl_cfg);
	if (ret != 0) {
		LOG_ERR("%s: Open Drain Slow speed set failed", dev->name);
		return ret;
	}

#ifdef CONFIG_I3C_INIT_RSTACT
	/*
	 * Reset all connected targets. Also reset dynamic
	 * addresses for all devices as we have no idea what
	 * dynamic addresses the connected devices have
	 * (e.g. assigned during previous power cycle).
	 *
	 * Note that we ignore error for both RSTACT and RSTDAA
	 * as there may not be any connected devices responding
	 * to these CCCs.
	 */
	if (i3c_ccc_do_rstact_all(dev, I3C_CCC_RSTACT_RESET_WHOLE_TARGET) != 0) {
		/*
		 * Reset Whole Target support is not required so
		 * if there is any NACK, we want to at least reset
		 * the I3C peripheral of targets.
		 */
		LOG_DBG("Broadcast RSTACT (whole target) was NACK.");

		if (i3c_ccc_do_rstact_all(dev, I3C_CCC_RSTACT_PERIPHERAL_ONLY) != 0) {
			LOG_DBG("Broadcast RSTACT (peripehral) was NACK.");
		}
	}
#endif

	if (i3c_bus_rstdaa_all(dev) != 0) {
		LOG_DBG("Broadcast RSTDAA was NACK.");
	}

	/* Set previously stored OD high period back */
	ctrl_cfg.scl_od_min.high_ns = prev_od_high_ns;
	ret = i3c_configure_controller(dev, &ctrl_cfg);
	if (ret != 0) {
		LOG_ERR("%s: Open Drain Normal speed set failed", dev->name);
		return ret;
	}

	/*
	 * Disable all events from targets to avoid them
	 * interfering with bus initialization,
	 * especially during DAA.
	 */
	i3c_events.events = I3C_CCC_EVT_ALL;
	ret = i3c_ccc_do_events_all_set(dev, false, &i3c_events);
	if (ret != 0) {
		LOG_DBG("Broadcast DISEC was NACK.");
	}

	/*
	 * Set static addresses as dynamic addresses.
	 */
	ret = i3c_bus_prepare_setdasa(dev, dev_list, &need_daa, &need_aasa);
	if (ret != 0) {
		goto err_out;
	}

	/*
	 * Perform Set All Addresses to Static Address if possible.
	 */
	if (need_aasa) {
		ret = i3c_bus_setaasa(dev);
		if (ret != 0) {
			LOG_ERR("failed to perform setaasa");
		}
	}

	/*
	 * Perform Dynamic Address Assignment if needed.
	 */
	if (need_daa) {
		ret = i3c_do_daa(dev);
		if (ret != 0) {
			/*
			 * Spec says to try once more
			 * if DAA fails the first time.
			 */
			ret = i3c_do_daa(dev);
			if (ret != 0) {
				/*
				 * Failure to finish dynamic address assignment
				 * is not the end of world... hopefully.
				 * Continue on so the devices already have
				 * addresses can still function.
				 */
				LOG_ERR("DAA was not successful.");
			}
		}
	}

	/*
	 * Loop through the registered I3C devices to retrieve
	 * basic target information.
	 */
	for (i = 0; i < dev_list->num_i3c; i++) {
		struct i3c_device_desc *desc = &dev_list->i3c[i];

		if (desc->dynamic_addr == 0U) {
			continue;
		}

		/*
		 * If static address is 0, then it is assumed that BCR
		 * and DCR were already read through ENTDAA
		 */
		ret = (desc->static_addr == 0) ? i3c_device_adv_info_get(desc)
					       : i3c_device_info_get(desc);
		if (ret != 0) {
			LOG_ERR("Error getting device info for 0x%02x", desc->static_addr);
		} else {
			LOG_DBG("Target 0x%02x, BCR 0x%02x, DCR 0x%02x, MRL %d, MWL %d, IBI %d",
				desc->dynamic_addr, desc->bcr, desc->dcr, desc->data_length.mrl,
				desc->data_length.mwl, desc->data_length.max_ibi);
		}
	}
#ifdef CONFIG_I3C_TARGET
	if (i3c_bus_has_sec_controller(dev)) {
		ret = i3c_bus_deftgts(dev);
		if (ret != 0) {
			LOG_ERR("Error sending DEFTGTS");
		}
	}
#endif /* CONFIG_I3C_TARGET */
	/*
	 * Only re-enable Hot-Join from targets.
	 * Target interrupts will be enabled when IBI is enabled.
	 */
	i3c_events.events = I3C_CCC_EVT_HJ;
	ret = i3c_ccc_do_events_all_set(dev, true, &i3c_events);
	if (ret != 0) {
		LOG_DBG("Broadcast ENEC was NACK.");
	}

err_out:
	return ret;
}
