diff --git a/drivers/i3c/i3c_common.c b/drivers/i3c/i3c_common.c index 9e3783876b8..7f580f4059e 100644 --- a/drivers/i3c/i3c_common.c +++ b/drivers/i3c/i3c_common.c @@ -453,37 +453,35 @@ err: int i3c_device_basic_info_get(struct i3c_device_desc *target) { int ret; - uint8_t tmp_bcr; - struct i3c_ccc_getbcr bcr = {0}; struct i3c_ccc_getdcr dcr = {0}; - struct i3c_ccc_mrl mrl = {0}; - struct i3c_ccc_mwl mwl = {0}; - union i3c_ccc_getcaps caps = {0}; - union i3c_ccc_getmxds mxds = {0}; - - /* - * Since some CCC functions requires BCR to function - * correctly, we save the BCR here and update the BCR - * in the descriptor. If any following operations fails, - * we can restore the BCR. - */ - tmp_bcr = target->bcr; /* GETBCR */ ret = i3c_ccc_do_getbcr(target, &bcr); if (ret != 0) { - goto out; + return ret; } - target->bcr = bcr.bcr; - /* GETDCR */ ret = i3c_ccc_do_getdcr(target, &dcr); if (ret != 0) { - goto out; + return ret; } + target->bcr = bcr.bcr; + target->dcr = dcr.dcr; + + return 0; +} + +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; + /* GETMRL */ if (i3c_ccc_do_getmrl(target, &mrl) != 0) { /* GETMRL may be optionally supported if no settable limit */ @@ -505,10 +503,8 @@ int i3c_device_basic_info_get(struct i3c_device_desc *target) * set, then it is expected for GETCAPS to always be supported. Otherwise, then it's a I3C * v1.0 device without any HDR modes so do not treat as an error if no valid response. */ - if (ret == 0) { - memcpy(&target->getcaps, &caps, sizeof(target->getcaps)); - } else if ((ret != 0) && (target->bcr & I3C_BCR_ADV_CAPABILITIES)) { - goto out; + if ((ret != 0) && (target->bcr & I3C_BCR_ADV_CAPABILITIES)) { + return ret; } else { ret = 0; } @@ -517,24 +513,21 @@ int i3c_device_basic_info_get(struct i3c_device_desc *target) if (target->bcr & I3C_BCR_MAX_DATA_SPEED_LIMIT) { ret = i3c_ccc_do_getmxds_fmt2(target, &mxds); if (ret != 0) { - goto out; + return ret; } - - target->data_speed.maxrd = mxds.fmt2.maxrd; - target->data_speed.maxwr = mxds.fmt2.maxwr; - target->data_speed.max_read_turnaround = sys_get_le24(mxds.fmt2.maxrdturn); } - target->dcr = dcr.dcr; + /* Some values may not have been read, but set them back to 0 */ + memcpy(&target->getcaps, &caps, sizeof(target->getcaps)); + + target->data_speed.maxrd = mxds.fmt2.maxrd; + target->data_speed.maxwr = mxds.fmt2.maxwr; + target->data_speed.max_read_turnaround = sys_get_le24(mxds.fmt2.maxrdturn); + target->data_length.mrl = mrl.len; target->data_length.mwl = mwl.len; target->data_length.max_ibi = mrl.ibi_len; -out: - if (ret != 0) { - /* Restore BCR is any CCC fails. */ - target->bcr = tmp_bcr; - } return ret; } @@ -824,9 +817,14 @@ int i3c_bus_init(const struct device *dev, const struct i3c_dev_list *dev_list) continue; } - ret = i3c_device_basic_info_get(desc); + /* + * 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 basic device info for 0x%02x", + 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", diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index bf3535f7041..864eef353e8 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -2106,8 +2106,6 @@ int i3c_bus_init(const struct device *dev, * This retrieves some basic information: * * Bus Characteristics Register (GETBCR) * * Device Characteristics Register (GETDCR) - * * Max Read Length (GETMRL) - * * Max Write Length (GETMWL) * from the device and update the corresponding fields of the device * descriptor. * @@ -2121,6 +2119,63 @@ int i3c_bus_init(const struct device *dev, */ int i3c_device_basic_info_get(struct i3c_device_desc *target); +/** + * @brief Get advanced information from device and update device descriptor. + * + * This retrieves some information: + * * Max Read Length (GETMRL) + * * Max Write Length (GETMWL) + * * Get Capabilities (GETCAPS) + * * Max Device Speed (GETMXDS) (if applicable) + * from the device and update the corresponding fields of the device + * descriptor. + * + * This only updates the field(s) in device descriptor + * only if CCC operations succeed. + * + * @note This should only be called after i3c_device_basic_info_get() or + * if the BCR was already obtained through ENTDAA, DEFTGTS, or GETBCR. + * + * @param[in,out] target I3C target device descriptor. + * + * @retval 0 if successful. + * @retval -EIO General Input/Output error. + */ +int i3c_device_adv_info_get(struct i3c_device_desc *target); + +/** + * @brief Get all information from device and update device descriptor. + * + * This retrieves all information: + * * Bus Characteristics Register (GETBCR) + * * Device Characteristics Register (GETDCR) + * * Max Read Length (GETMRL) + * * Max Write Length (GETMWL) + * * Get Capabilities (GETCAPS) + * * Max Device Speed (GETMXDS) (if applicable) + * from the device and update the corresponding fields of the device + * descriptor. + * + * This only updates the field(s) in device descriptor + * only if CCC operations succeed. + * + * @param[in,out] target I3C target device descriptor. + * + * @retval 0 if successful. + * @retval -EIO General Input/Output error. + */ +static inline int i3c_device_info_get(struct i3c_device_desc *target) +{ + int rc; + + rc = i3c_device_basic_info_get(target); + if (rc != 0) { + return rc; + } + + return i3c_device_adv_info_get(target); +} + /** * @brief Check if the bus has a secondary controller. *