/* * Copyright (c) 2022 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include LOG_MODULE_DECLARE(i3c, CONFIG_I3C_LOG_LEVEL); int i3c_ccc_do_getbcr(struct i3c_device_desc *target, struct i3c_ccc_getbcr *bcr) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(bcr != NULL); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &bcr->bcr; ccc_tgt_payload.data_len = sizeof(bcr->bcr); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETBCR; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_getdcr(struct i3c_device_desc *target, struct i3c_ccc_getdcr *dcr) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(dcr != NULL); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &dcr->dcr; ccc_tgt_payload.data_len = sizeof(dcr->dcr); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETDCR; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_getpid(struct i3c_device_desc *target, struct i3c_ccc_getpid *pid) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(pid != NULL); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &pid->pid[0]; ccc_tgt_payload.data_len = sizeof(pid->pid); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETPID; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_rstact_all(const struct device *controller, enum i3c_ccc_rstact_defining_byte action) { struct i3c_ccc_payload ccc_payload; uint8_t def_byte; __ASSERT_NO_MSG(controller != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_RSTACT(true); def_byte = (uint8_t)action; ccc_payload.ccc.data = &def_byte; ccc_payload.ccc.data_len = 1U; return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_rstact(const struct i3c_device_desc *target, enum i3c_ccc_rstact_defining_byte action, bool get, uint8_t *data) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t def_byte; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_tgt_payload.addr = target->dynamic_addr; if (get) { __ASSERT_NO_MSG(data != NULL); ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = data; ccc_tgt_payload.data_len = sizeof(*data); } else { ccc_tgt_payload.rnw = 0; } ccc_payload.ccc.id = I3C_CCC_RSTACT(false); def_byte = (uint8_t)action; ccc_payload.ccc.data = &def_byte; ccc_payload.ccc.data_len = 1U; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_rstdaa_all(const struct device *controller) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(controller != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_RSTDAA; return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_setdasa(const struct i3c_device_desc *target, struct i3c_ccc_address da) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); if ((target->static_addr == 0U) || (target->dynamic_addr != 0U)) { return -EINVAL; } ccc_tgt_payload.addr = target->static_addr; ccc_tgt_payload.rnw = 0; ccc_tgt_payload.data = (uint8_t *)&da.addr; ccc_tgt_payload.data_len = 1; memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_SETDASA; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_setnewda(const struct i3c_device_desc *target, struct i3c_ccc_address new_da) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); if (target->dynamic_addr == 0U) { return -EINVAL; } ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 0; ccc_tgt_payload.data = (uint8_t *)&new_da.addr; ccc_tgt_payload.data_len = 1; memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_SETNEWDA; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_events_all_set(const struct device *controller, bool enable, struct i3c_ccc_events *events) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(controller != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = enable ? I3C_CCC_ENEC(true) : I3C_CCC_DISEC(true); ccc_payload.ccc.data = &events->events; ccc_payload.ccc.data_len = sizeof(events->events); return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_events_set(struct i3c_device_desc *target, bool enable, struct i3c_ccc_events *events) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); if (target->dynamic_addr == 0U) { return -EINVAL; } ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 0; ccc_tgt_payload.data = &events->events; ccc_tgt_payload.data_len = sizeof(events->events); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = enable ? I3C_CCC_ENEC(false) : I3C_CCC_DISEC(false); ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_entas(const struct i3c_device_desc *target, uint8_t as) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(as <= 3); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 0; ccc_payload.ccc.id = I3C_CCC_ENTAS(as, false); ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_entas_all(const struct device *controller, uint8_t as) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(controller != NULL); __ASSERT_NO_MSG(as <= 3); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_ENTAS(as, true); return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_setmwl_all(const struct device *controller, const struct i3c_ccc_mwl *mwl) { struct i3c_ccc_payload ccc_payload; uint8_t data[2]; __ASSERT_NO_MSG(controller != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_SETMWL(true); ccc_payload.ccc.data = &data[0]; ccc_payload.ccc.data_len = sizeof(data); /* The actual data is MSB first. So order the data. */ sys_put_be16(mwl->len, data); return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_setmwl(const struct i3c_device_desc *target, const struct i3c_ccc_mwl *mwl) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t data[2]; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 0; ccc_tgt_payload.data = &data[0]; ccc_tgt_payload.data_len = sizeof(data); ccc_payload.ccc.id = I3C_CCC_SETMWL(false); ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; /* The actual length is MSB first. So order the data. */ sys_put_be16(mwl->len, data); return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_getmwl(const struct i3c_device_desc *target, struct i3c_ccc_mwl *mwl) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t data[2]; int ret; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(mwl != NULL); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &data[0]; ccc_tgt_payload.data_len = sizeof(data); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETMWL; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; ret = i3c_do_ccc(target->bus, &ccc_payload); if (ret == 0) { /* The actual length is MSB first. So order the data. */ mwl->len = sys_get_be16(data); } return ret; } int i3c_ccc_do_setmrl_all(const struct device *controller, const struct i3c_ccc_mrl *mrl, bool has_ibi_size) { struct i3c_ccc_payload ccc_payload; uint8_t data[3]; __ASSERT_NO_MSG(controller != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_SETMRL(true); ccc_payload.ccc.data = &data[0]; ccc_payload.ccc.data_len = has_ibi_size ? 3 : 2; /* The actual length is MSB first. So order the data. */ sys_put_be16(mrl->len, data); if (has_ibi_size) { data[2] = mrl->ibi_len; } return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_setmrl(const struct i3c_device_desc *target, const struct i3c_ccc_mrl *mrl) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t data[3]; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 0; ccc_tgt_payload.data = &data[0]; ccc_payload.ccc.id = I3C_CCC_SETMRL(false); ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; /* The actual length is MSB first. So order the data. */ sys_put_be16(mrl->len, data); if ((target->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) == I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) { ccc_tgt_payload.data_len = 3; data[2] = mrl->ibi_len; } else { ccc_tgt_payload.data_len = 2; } return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_getmrl(const struct i3c_device_desc *target, struct i3c_ccc_mrl *mrl) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t data[3]; bool has_ibi_sz; int ret; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(mrl != NULL); has_ibi_sz = (target->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) == I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE; ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &data[0]; ccc_tgt_payload.data_len = has_ibi_sz ? 3 : 2; memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETMRL; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; ret = i3c_do_ccc(target->bus, &ccc_payload); if (ret == 0) { /* The actual length is MSB first. So order the data. */ mrl->len = sys_get_be16(data); if (has_ibi_sz) { mrl->ibi_len = data[2]; } } return ret; } int i3c_ccc_do_enttm(const struct device *controller, enum i3c_ccc_enttm_defbyte defbyte) { struct i3c_ccc_payload ccc_payload; uint8_t def_byte; __ASSERT_NO_MSG(controller != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_ENTTM; def_byte = (uint8_t)defbyte; ccc_payload.ccc.data = &def_byte; ccc_payload.ccc.data_len = 1U; return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_deftgts_all(const struct device *controller, struct i3c_ccc_deftgts *deftgts) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(controller != NULL); __ASSERT_NO_MSG(deftgts != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_DEFTGTS; ccc_payload.ccc.data = (uint8_t *)deftgts; ccc_payload.ccc.data_len = sizeof(uint8_t) + sizeof(struct i3c_ccc_deftgts_active_controller) + (deftgts->count * sizeof(struct i3c_ccc_deftgts_target)); return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_getstatus(const struct i3c_device_desc *target, union i3c_ccc_getstatus *status, enum i3c_ccc_getstatus_fmt fmt, enum i3c_ccc_getstatus_defbyte defbyte) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t defining_byte; uint8_t data[2]; int ret; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(status != NULL); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &data[0]; if (fmt == GETSTATUS_FORMAT_1) { ccc_tgt_payload.data_len = 2; } else if (fmt == GETSTATUS_FORMAT_2) { switch (defbyte) { case GETSTATUS_FORMAT_2_TGTSTAT: __fallthrough; case GETSTATUS_FORMAT_2_PRECR: ccc_tgt_payload.data_len = 2; break; default: ret = -EINVAL; goto out; } } else { ret = -EINVAL; goto out; } memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETSTATUS; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; if (fmt == GETSTATUS_FORMAT_2) { defining_byte = (uint8_t)defbyte; ccc_payload.ccc.data = &defining_byte; ccc_payload.ccc.data_len = 1; } ret = i3c_do_ccc(target->bus, &ccc_payload); if (ret == 0) { /* Received data is MSB first. So order the data. */ if (fmt == GETSTATUS_FORMAT_1) { status->fmt1.status = sys_get_be16(data); } else if (fmt == GETSTATUS_FORMAT_2) { switch (defbyte) { case GETSTATUS_FORMAT_2_TGTSTAT: __fallthrough; case GETSTATUS_FORMAT_2_PRECR: status->fmt2.raw_u16 = sys_get_be16(data); break; default: break; } } } out: return ret; } int i3c_ccc_do_getcaps(const struct i3c_device_desc *target, union i3c_ccc_getcaps *caps, enum i3c_ccc_getcaps_fmt fmt, enum i3c_ccc_getcaps_defbyte defbyte) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t defining_byte; uint8_t data[4]; uint8_t len; int ret; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(caps != NULL); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &data[0]; if (fmt == GETCAPS_FORMAT_1) { /* Could be 1-4 Data Bytes Returned */ ccc_tgt_payload.data_len = 4; } else if (fmt == GETCAPS_FORMAT_2) { switch (defbyte) { case GETCAPS_FORMAT_2_CRCAPS: __fallthrough; case GETCAPS_FORMAT_2_VTCAPS: /* Could be 1-2 Data Bytes Returned*/ ccc_tgt_payload.data_len = 2; break; case GETCAPS_FORMAT_2_TGTCAPS: __fallthrough; case GETCAPS_FORMAT_2_TESTPAT: /* Could be 1-4 Data Bytes Returned */ ccc_tgt_payload.data_len = 4; break; default: ret = -EINVAL; goto out; } } else { ret = -EINVAL; goto out; } memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETCAPS; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; if (fmt == GETCAPS_FORMAT_2) { defining_byte = (uint8_t)defbyte; ccc_payload.ccc.data = &defining_byte; ccc_payload.ccc.data_len = 1; } ret = i3c_do_ccc(target->bus, &ccc_payload); if (ret == 0) { /* GETCAPS will return a variable length */ len = ccc_tgt_payload.num_xfer; if (fmt == GETCAPS_FORMAT_1) { memcpy(caps->fmt1.getcaps, data, len); /* for values not received, assume default (1'b0) */ memset(&caps->fmt1.getcaps[len], 0, sizeof(caps->fmt1.getcaps) - len); } else if (fmt == GETCAPS_FORMAT_2) { switch (defbyte) { case GETCAPS_FORMAT_2_CRCAPS: memcpy(caps->fmt2.crcaps, data, len); /* for values not received, assume default (1'b0) */ memset(&caps->fmt2.crcaps[len], 0, sizeof(caps->fmt2.crcaps) - len); break; case GETCAPS_FORMAT_2_VTCAPS: memcpy(caps->fmt2.vtcaps, data, len); /* for values not received, assume default (1'b0) */ memset(&caps->fmt2.vtcaps[len], 0, sizeof(caps->fmt2.vtcaps) - len); break; case GETCAPS_FORMAT_2_TGTCAPS: memcpy(caps->fmt2.tgtcaps, data, len); /* for values not received, assume default (1'b0) */ memset(&caps->fmt2.tgtcaps[len], 0, sizeof(caps->fmt2.tgtcaps) - len); break; case GETCAPS_FORMAT_2_TESTPAT: /* should always be 4 data bytes */ caps->fmt2.testpat = sys_get_be32(data); break; default: break; } } } out: return ret; } int i3c_ccc_do_setvendor(const struct i3c_device_desc *target, uint8_t id, uint8_t *payload, size_t len) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(target != NULL); /* CCC must be between 0xE0 and 0xFE, the total range of this is 0x1E */ if (id > 0x1E) { return -EINVAL; } memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_VENDOR(false, id); ccc_payload.ccc.data = payload; ccc_payload.ccc.data_len = len; return i3c_do_ccc(target->bus, &ccc_payload); } int i3c_ccc_do_getvendor(const struct i3c_device_desc *target, uint8_t id, uint8_t *payload, size_t len, size_t *num_xfer) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; int ret; __ASSERT_NO_MSG(target != NULL); /* CCC must be between 0xE0 and 0xFE, the total range of this is 0x1E */ if (id > 0x1E) { return -EINVAL; } ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = payload; ccc_tgt_payload.data_len = len; memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_VENDOR(false, id); ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; ret = i3c_do_ccc(target->bus, &ccc_payload); if (ret == 0) { *num_xfer = ccc_tgt_payload.num_xfer; } return ret; } int i3c_ccc_do_getvendor_defbyte(const struct i3c_device_desc *target, uint8_t id, uint8_t defbyte, uint8_t *payload, size_t len, size_t *num_xfer) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; int ret; __ASSERT_NO_MSG(target != NULL); /* CCC must be between 0xE0 and 0xFE, the total range of this is 0x1E */ if (id > 0x1E) { return -EINVAL; } ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = payload; ccc_tgt_payload.data_len = len; memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_VENDOR(false, id); ccc_payload.ccc.data = &defbyte; ccc_payload.ccc.data_len = 1; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; ret = i3c_do_ccc(target->bus, &ccc_payload); if (ret == 0) { *num_xfer = ccc_tgt_payload.num_xfer; } return ret; } int i3c_ccc_do_setvendor_all(const struct device *controller, uint8_t id, uint8_t *payload, size_t len) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(controller != NULL); /* CCC must be between 0x61 and 0x7F, the total range of this is 0x1E */ if (id > 0x1E) { return -EINVAL; } memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_VENDOR(true, id); ccc_payload.ccc.data = payload; ccc_payload.ccc.data_len = len; return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_setaasa_all(const struct device *controller) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(controller != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_SETAASA; return i3c_do_ccc(controller, &ccc_payload); } int i3c_ccc_do_getmxds(const struct i3c_device_desc *target, union i3c_ccc_getmxds *mxds, enum i3c_ccc_getmxds_fmt fmt, enum i3c_ccc_getmxds_defbyte defbyte) { struct i3c_ccc_payload ccc_payload; struct i3c_ccc_target_payload ccc_tgt_payload; uint8_t defining_byte; uint8_t data[5]; uint8_t len; int ret; __ASSERT_NO_MSG(target != NULL); __ASSERT_NO_MSG(target->bus != NULL); __ASSERT_NO_MSG(mxds != NULL); ccc_tgt_payload.addr = target->dynamic_addr; ccc_tgt_payload.rnw = 1; ccc_tgt_payload.data = &data[0]; if ((fmt == GETMXDS_FORMAT_1) || (fmt == GETMXDS_FORMAT_2)) { /* Could be 2 or 5 Data Bytes Returned */ ccc_tgt_payload.data_len = sizeof(((union i3c_ccc_getmxds *)0)->fmt2); } else if (fmt == GETMXDS_FORMAT_3) { switch (defbyte) { case GETMXDS_FORMAT_3_WRRDTURN: /* Could be 2 or 5 Data Bytes Returned */ ccc_tgt_payload.data_len = sizeof(((union i3c_ccc_getmxds *)0)->fmt3.wrrdturn); break; case GETMXDS_FORMAT_3_CRHDLY: /* Only 1 Byte returned */ ccc_tgt_payload.data_len = sizeof(((union i3c_ccc_getmxds *)0)->fmt3.crhdly1); break; default: ret = -EINVAL; goto out; } } else { ret = -EINVAL; goto out; } memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_GETMXDS; ccc_payload.targets.payloads = &ccc_tgt_payload; ccc_payload.targets.num_targets = 1; if (fmt == GETMXDS_FORMAT_3) { defining_byte = (uint8_t)defbyte; ccc_payload.ccc.data = &defining_byte; ccc_payload.ccc.data_len = 1; } ret = i3c_do_ccc(target->bus, &ccc_payload); if (ret == 0) { /* GETMXDS will return a variable length */ len = ccc_tgt_payload.num_xfer; if ((fmt == GETMXDS_FORMAT_1) || (fmt == GETMXDS_FORMAT_2)) { if (len == sizeof(((union i3c_ccc_getmxds *)0)->fmt1)) { mxds->fmt1.maxwr = data[0]; mxds->fmt1.maxrd = data[1]; /* It is unknown wither format 1 or format 2 is returned ahead of * time */ memset(&mxds->fmt2.maxrdturn, 0, sizeof(mxds->fmt2.maxrdturn)); } else if (len == sizeof(((union i3c_ccc_getmxds *)0)->fmt2)) { mxds->fmt2.maxwr = data[0]; mxds->fmt2.maxrd = data[1]; memcpy(&mxds->fmt2.maxrdturn, &data[2], sizeof(mxds->fmt2.maxrdturn)); } } else if (fmt == GETMXDS_FORMAT_3) { switch (defbyte) { case GETMXDS_FORMAT_3_WRRDTURN: memcpy(mxds->fmt3.wrrdturn, data, len); /* for values not received, assume default (1'b0) */ memset(&mxds->fmt3.wrrdturn[len], 0, sizeof(mxds->fmt3.wrrdturn) - len); break; case GETMXDS_FORMAT_3_CRHDLY: mxds->fmt3.crhdly1 = data[0]; break; default: break; } } } out: return ret; } int i3c_ccc_do_setbuscon(const struct device *controller, uint8_t *context, uint16_t length) { struct i3c_ccc_payload ccc_payload; __ASSERT_NO_MSG(controller != NULL); __ASSERT_NO_MSG(context != NULL); memset(&ccc_payload, 0, sizeof(ccc_payload)); ccc_payload.ccc.id = I3C_CCC_SETBUSCON; ccc_payload.ccc.data = context; ccc_payload.ccc.data_len = length; return i3c_do_ccc(controller, &ccc_payload); }