1 /*
2 * Copyright 2020, 2022-2023 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_component_i3c.h"
8
9 /*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12
13 /*******************************************************************************
14 * Prototypes
15 ******************************************************************************/
16
17 /*******************************************************************************
18 * Variables
19 ******************************************************************************/
20
21 /*******************************************************************************
22 * Code
23 ******************************************************************************/
I3C_BusSetAddrSlot(i3c_bus_t * bus,uint8_t addr,i3c_addr_slot_status_t status)24 void I3C_BusSetAddrSlot(i3c_bus_t *bus, uint8_t addr, i3c_addr_slot_status_t status)
25 {
26 uint16_t bitPos = (uint16_t)addr * I3C_BUS_ADDR_SLOTWIDTH;
27 uint32_t *slotPtr;
28
29 if (addr > I3C_BUS_MAX_ADDR)
30 {
31 return;
32 }
33
34 slotPtr = &bus->addrSlots[bitPos / I3C_BUS_ADDR_SLOTDEPTH];
35 *slotPtr &= ~((uint32_t)I3C_BUS_ADDR_SLOTMASK << (bitPos % I3C_BUS_ADDR_SLOTDEPTH));
36 *slotPtr |= (uint32_t)status << (bitPos % I3C_BUS_ADDR_SLOTDEPTH);
37 }
38
I3C_BusInitAddrSlots(i3c_bus_t * bus)39 static void I3C_BusInitAddrSlots(i3c_bus_t *bus)
40 {
41 uint8_t i;
42
43 /* Reserve address 0x0 to 0x7. */
44 for (i = 0; i < 8U; i++)
45 {
46 I3C_BusSetAddrSlot(bus, i, kI3C_Bus_AddrSlot_Reserved);
47 }
48
49 /* Reserve the conditional restriction I3C address. */
50 I3C_BusSetAddrSlot(bus, 0x78U, kI3C_Bus_AddrSlot_Reserved);
51 I3C_BusSetAddrSlot(bus, 0x79U, kI3C_Bus_AddrSlot_Reserved);
52 I3C_BusSetAddrSlot(bus, 0x7BU, kI3C_Bus_AddrSlot_Reserved);
53 I3C_BusSetAddrSlot(bus, 0x7DU, kI3C_Bus_AddrSlot_Reserved);
54
55 /* All are prohibited since I3C targets will interpret an I3C address header with any of these addresses as a
56 * broadcast address with a single-bit error. */
57 I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR1, kI3C_Bus_AddrSlot_Reserved);
58 I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR2, kI3C_Bus_AddrSlot_Reserved);
59 I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR3, kI3C_Bus_AddrSlot_Reserved);
60 I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR4, kI3C_Bus_AddrSlot_Reserved);
61 I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR5, kI3C_Bus_AddrSlot_Reserved);
62 I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR6, kI3C_Bus_AddrSlot_Reserved);
63 I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR7, kI3C_Bus_AddrSlot_Reserved);
64
65 /* Reserve I3C broadcast address. */
66 I3C_BusSetAddrSlot(bus, I3C_BUS_BROADCAST_ADDR, kI3C_Bus_AddrSlot_Reserved);
67 }
68
I3C_BusGetAddrSlotStatus(i3c_bus_t * bus,uint8_t checkAddr)69 static uint8_t I3C_BusGetAddrSlotStatus(i3c_bus_t *bus, uint8_t checkAddr)
70 {
71 uint16_t bitPos = (uint16_t)checkAddr * 2U;
72 uint32_t useStatus = 0;
73
74 if (checkAddr > I3C_BUS_MAX_ADDR)
75 {
76 return (uint8_t)kI3C_Bus_AddrSlot_Reserved;
77 }
78
79 useStatus = bus->addrSlots[bitPos / I3C_BUS_ADDR_SLOTDEPTH];
80 useStatus >>= bitPos % I3C_BUS_ADDR_SLOTDEPTH;
81
82 return (uint8_t)(useStatus & (uint8_t)I3C_BUS_ADDR_SLOTMASK);
83 }
84
I3C_CheckBusMasterOps(i3c_device_hw_ops_t * ops)85 static status_t I3C_CheckBusMasterOps(i3c_device_hw_ops_t *ops)
86 {
87 if ((ops == NULL) || (ops->Init == NULL) || (ops->DoI3CTransfer == NULL) || (ops->DoI2CTransfer == NULL) ||
88 (ops->TransmitCCC == NULL) || (ops->ProceedDAA == NULL))
89 {
90 return kStatus_I3CBus_MasterOpsMissing;
91 }
92
93 return kStatus_Success;
94 }
95
I3C_BusMasterGetMaxReadLength(i3c_device_t * master,i3c_device_information_t * info)96 static status_t I3C_BusMasterGetMaxReadLength(i3c_device_t *master, i3c_device_information_t *info)
97 {
98 i3c_ccc_cmd_t getMRLCmd = {0};
99 status_t result = kStatus_Success;
100
101 getMRLCmd.isRead = true;
102 getMRLCmd.cmdId = I3C_BUS_CCC_GETMRL;
103 getMRLCmd.destAddr = info->dynamicAddr;
104 getMRLCmd.data = malloc(3U);
105 getMRLCmd.dataSize = 3U;
106
107 /*
108 * When the device does not have IBI payload GETMRL only returns 2
109 * bytes of data.
110 */
111 if ((info->bcr & I3C_BUS_DEV_BCR_IBI_PAYLOAD_MASK) == 0U)
112 {
113 getMRLCmd.dataSize -= 1U;
114 }
115
116 result = I3C_BusMasterSendCCC(master, &getMRLCmd);
117
118 uint8_t *pData = getMRLCmd.data;
119 if ((info->bcr & I3C_BUS_DEV_BCR_IBI_PAYLOAD_MASK) != 0U)
120 {
121 info->maxIBILength = pData[2];
122 }
123
124 info->maxReadLength = (uint16_t)pData[0] << 8UL | (uint16_t)pData[1];
125
126 free(getMRLCmd.data);
127
128 return result;
129 }
130
I3C_BusMasterGetMaxWriteLength(i3c_device_t * master,i3c_device_information_t * info)131 static status_t I3C_BusMasterGetMaxWriteLength(i3c_device_t *master, i3c_device_information_t *info)
132 {
133 i3c_ccc_cmd_t getMWLCmd = {0};
134 status_t result = kStatus_Success;
135
136 uint16_t writelen;
137 getMWLCmd.isRead = true;
138 getMWLCmd.cmdId = I3C_BUS_CCC_GETMWL;
139 getMWLCmd.destAddr = info->dynamicAddr;
140 getMWLCmd.data = &writelen;
141 getMWLCmd.dataSize = 2U;
142
143 result = I3C_BusMasterSendCCC(master, &getMWLCmd);
144
145 info->maxWriteLength = writelen;
146
147 return result;
148 }
149
I3C_BusMasterGetHDRCapability(i3c_device_t * master,i3c_device_information_t * info)150 static status_t I3C_BusMasterGetHDRCapability(i3c_device_t *master, i3c_device_information_t *info)
151 {
152 i3c_ccc_cmd_t getHDRCapCmd = {0};
153 status_t result = kStatus_Success;
154
155 uint8_t hdrMode;
156 getHDRCapCmd.isRead = true;
157 getHDRCapCmd.cmdId = I3C_BUS_CCC_GETHDRCAP;
158 getHDRCapCmd.destAddr = info->dynamicAddr;
159 getHDRCapCmd.data = &hdrMode;
160 getHDRCapCmd.dataSize = 1U;
161
162 result = I3C_BusMasterSendCCC(master, &getHDRCapCmd);
163
164 info->hdrMode = hdrMode;
165
166 return result;
167 }
168
I3C_BusMasterGetPID(i3c_device_t * master,i3c_device_information_t * info)169 static status_t I3C_BusMasterGetPID(i3c_device_t *master, i3c_device_information_t *info)
170 {
171 uint8_t pid[6];
172 i3c_ccc_cmd_t getPidCmd = {0};
173 status_t result = kStatus_Success;
174
175 getPidCmd.isRead = true;
176 getPidCmd.cmdId = I3C_BUS_CCC_GETPID;
177 getPidCmd.destAddr = info->dynamicAddr;
178 getPidCmd.data = pid;
179 getPidCmd.dataSize = 6U;
180
181 result = I3C_BusMasterSendCCC(master, &getPidCmd);
182
183 info->vendorID = (((uint16_t)pid[0] << 8U | (uint16_t)pid[1]) & 0xFFFEU) >> 1U;
184 info->partNumber = ((uint32_t)pid[2] << 24U | (uint32_t)pid[3] << 16U | (uint32_t)pid[4] << 8U | (uint32_t)pid[5]);
185
186 return result;
187 }
188
I3C_BusMasterGetBCR(i3c_device_t * master,i3c_device_information_t * info)189 static status_t I3C_BusMasterGetBCR(i3c_device_t *master, i3c_device_information_t *info)
190 {
191 uint8_t bcr;
192 i3c_ccc_cmd_t getBCRCmd = {0};
193 status_t result = kStatus_Success;
194
195 getBCRCmd.isRead = true;
196 getBCRCmd.cmdId = I3C_BUS_CCC_GETBCR;
197 getBCRCmd.destAddr = info->dynamicAddr;
198 getBCRCmd.data = &bcr;
199 getBCRCmd.dataSize = 1U;
200
201 result = I3C_BusMasterSendCCC(master, &getBCRCmd);
202
203 info->bcr = bcr;
204
205 return result;
206 }
207
I3C_BusMasterGetDCR(i3c_device_t * master,i3c_device_information_t * info)208 static status_t I3C_BusMasterGetDCR(i3c_device_t *master, i3c_device_information_t *info)
209 {
210 uint8_t dcr;
211 i3c_ccc_cmd_t getDCRCmd = {0};
212 status_t result = kStatus_Success;
213
214 getDCRCmd.isRead = true;
215 getDCRCmd.cmdId = I3C_BUS_CCC_GETDCR;
216 getDCRCmd.destAddr = info->dynamicAddr;
217 getDCRCmd.data = &dcr;
218 getDCRCmd.dataSize = 1U;
219
220 result = I3C_BusMasterSendCCC(master, &getDCRCmd);
221
222 info->dcr = dcr;
223
224 return result;
225 }
226
I3C_BusMasterAssignDevDynamicAddr(i3c_device_t * masterDev)227 static status_t I3C_BusMasterAssignDevDynamicAddr(i3c_device_t *masterDev)
228 {
229 i3c_bus_t *i3cBus = masterDev->bus;
230 status_t result = kStatus_Success;
231
232 list_handle_t i3cDevList = &(i3cBus->i3cDevList);
233
234 for (list_element_handle_t listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
235 {
236 i3c_device_t *tmpDev = (i3c_device_t *)(void *)listItem;
237 if (tmpDev == masterDev)
238 {
239 continue;
240 }
241 else if ((tmpDev->initDynamicAddr != 0U) && (tmpDev->info.staticAddr != 0U) && (tmpDev->info.dynamicAddr == 0U))
242 {
243 result =
244 I3C_BusMasterSetDynamicAddrFromStaticAddr(masterDev, tmpDev->info.staticAddr, tmpDev->initDynamicAddr);
245
246 if (result != kStatus_Success)
247 {
248 return result;
249 }
250
251 tmpDev->info.dynamicAddr = tmpDev->initDynamicAddr;
252 I3C_BusSetAddrSlot(i3cBus, tmpDev->info.dynamicAddr, kI3C_Bus_AddrSlot_I3CDev);
253
254 /* Retrieve device information. */
255 result = I3C_BusMasterGetDeviceInfo(masterDev, tmpDev->info.dynamicAddr, &tmpDev->info);
256 if (result != kStatus_Success)
257 {
258 return result;
259 }
260 }
261 else
262 {
263 /*Empty else to eliminate MISRA 15.7*/
264 }
265 }
266
267 return result;
268 }
269
I3C_BusMasterAddExistingI3CDevs(i3c_device_t * masterDev)270 static status_t I3C_BusMasterAddExistingI3CDevs(i3c_device_t *masterDev)
271 {
272 i3c_bus_t *i3cBus = masterDev->bus;
273 status_t result = kStatus_Success;
274
275 list_handle_t i3cDevList = &(i3cBus->i3cDevList);
276
277 for (list_element_handle_t listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
278 {
279 i3c_device_t *tmpDev = (i3c_device_t *)(void *)listItem;
280 if (tmpDev == masterDev)
281 {
282 continue;
283 }
284 else if (tmpDev->ibiInfo != NULL)
285 {
286 result = I3C_BusMasterRegisterDevIBI(masterDev, tmpDev, tmpDev->ibiInfo);
287 if (result != kStatus_Success)
288 {
289 return result;
290 }
291 }
292 else
293 {
294 /*Fix MISRA violation 15.7*/
295 }
296 }
297
298 return result;
299 }
300
301 /*!
302 * brief Add exist I3C device in bus to the bus device list.
303 *
304 * This function will simply add the device to the bus device list and set the related address slot.
305 *
306 * param bus Pointer to bus structure.
307 * param dev Pointer to I3C device.
308 */
I3C_BusAddI3CDev(i3c_bus_t * bus,i3c_device_t * dev)309 void I3C_BusAddI3CDev(i3c_bus_t *bus, i3c_device_t *dev)
310 {
311 /* Chain device into i3c_device_list */
312 list_handle_t i3cDevList = &bus->i3cDevList;
313 (void)LIST_AddTail(i3cDevList, &dev->listNode);
314
315 if (dev->info.dynamicAddr != 0U)
316 {
317 /* Set slot status I3C device */
318 I3C_BusSetAddrSlot(bus, dev->info.dynamicAddr, kI3C_Bus_AddrSlot_I3CDev);
319 }
320
321 if (dev->info.staticAddr != 0U)
322 {
323 /* Set slot status I2C device */
324 I3C_BusSetAddrSlot(bus, dev->info.staticAddr, kI3C_Bus_AddrSlot_I2CDev);
325 }
326
327 dev->bus = bus;
328 }
329
330 /*!
331 * brief Add exist I2C device in bus to the bus device list.
332 *
333 * This function will simply add the device to the bus device list and set the related address slot.
334 *
335 * param bus Pointer to bus structure.
336 * param dev Pointer to I2C device.
337 */
I3C_BusAddI2CDev(i3c_bus_t * bus,i2c_device_t * dev)338 void I3C_BusAddI2CDev(i3c_bus_t *bus, i2c_device_t *dev)
339 {
340 /* Chain device into i2c_device_list */
341 dev->bus = bus;
342 list_handle_t i2cDevList = &bus->i2cDevList;
343 (void)LIST_AddTail(i2cDevList, &dev->listNode);
344 /* Set slot status I2C device */
345 I3C_BusSetAddrSlot(bus, dev->staticAddr, kI3C_Bus_AddrSlot_I2CDev);
346 dev->bus = bus;
347 }
348
349 /*!
350 * brief Get valid address slot in the I3C bus.
351 *
352 * This function will search for available address lot in the I3C bus address pool, the search starts from
353 * the startAddr specified by user input, to end address defined in @ref I3C_BUS_MAX_ADDR. Will return the
354 * available address if the related address slot is valid.
355 *
356 * param bus Pointer to bus structure.
357 * param startAddr Start address for address slot searching, end address is defined in @ref I3C_BUS_MAX_ADDR.
358 * return Available address in the bus address pool.
359 */
I3C_BusGetValidAddrSlot(i3c_bus_t * bus,uint8_t startAddr)360 uint8_t I3C_BusGetValidAddrSlot(i3c_bus_t *bus, uint8_t startAddr)
361 {
362 uint8_t validAddr = 0xFF;
363
364 for (validAddr = startAddr; validAddr < I3C_BUS_MAX_ADDR; validAddr++)
365 {
366 if (I3C_BusGetAddrSlotStatus(bus, validAddr) == (uint8_t)kI3C_Bus_AddrSlot_Free)
367 {
368 return validAddr;
369 }
370 }
371
372 return validAddr;
373 }
374
375 /*!
376 * brief Gets the default configuration structure.
377 *
378 * This function initializes the bus configuration structure to a default value. The default
379 * values are:
380 * busConfig->busMode = kI3C_Bus_PureMode;
381 * busConfig->i2cBaudRate = 400000U;
382 * busConfig->i3cOpenDrainBaudRate = 1500000U;
383 * busConfig->i3cPushPullBaudRate = 4000000U;
384 *
385 * param config Pointer to a configuration structure.
386 */
I3C_BusGetDefaultBusConfig(i3c_bus_config_t * busConfig)387 void I3C_BusGetDefaultBusConfig(i3c_bus_config_t *busConfig)
388 {
389 busConfig->busMode = kI3C_Bus_PureMode;
390 busConfig->i2cBaudRate = 400000U;
391 busConfig->i3cOpenDrainBaudRate = 1500000U;
392 busConfig->i3cPushPullBaudRate = 4000000U;
393 }
394
395 /*!
396 * brief Creates I3C bus structure.
397 *
398 * This function creates the bus structure with input bus configuration. Address pool set up and device
399 * list initialize process will be also done in this function call.
400 *
401 * param bus Pointer to bus structure.
402 * param busConfig Pointer to the bus configuration structure.
403 */
I3C_BusCreate(i3c_bus_t * bus,const i3c_bus_config_t * busConfig)404 void I3C_BusCreate(i3c_bus_t *bus, const i3c_bus_config_t *busConfig)
405 {
406 assert(bus != NULL);
407
408 (void)memset(bus, 0, sizeof(*bus));
409
410 LIST_Init(&bus->i2cDevList, 0);
411 LIST_Init(&bus->i3cDevList, 0);
412 I3C_BusInitAddrSlots(bus);
413 bus->busMode = busConfig->busMode;
414 bus->i2cBaudRate = busConfig->i2cBaudRate;
415 bus->i3cOpenDrainBaudRate = busConfig->i3cOpenDrainBaudRate;
416 bus->i3cPushPullBaudRate = busConfig->i3cPushPullBaudRate;
417 }
418
419 /*!
420 * brief Create I3C master structure on bus.
421 *
422 * This function will create I3C master bus structure, initialize the master according to bus characteristics, install
423 * device information and device control information.
424 *
425 * param masterDev Pointer to device structure creating as master.
426 * param bus Pointer to bus structure.
427 * param devInfo Pointer to device information structure.
428 * param masterControlInfo Pointer to master control information structure.
429 */
I3C_BusMasterCreate(i3c_device_t * masterDev,i3c_bus_t * bus,i3c_device_information_t * devInfo,i3c_device_control_info_t * masterControlInfo)430 status_t I3C_BusMasterCreate(i3c_device_t *masterDev,
431 i3c_bus_t *bus,
432 i3c_device_information_t *devInfo,
433 i3c_device_control_info_t *masterControlInfo)
434 {
435 status_t result = kStatus_Success;
436
437 (void)memset(masterDev, 0, sizeof(*masterDev));
438
439 masterDev->info = *devInfo;
440 result = I3C_CheckBusMasterOps(masterControlInfo->funcs);
441
442 if (result != kStatus_Success)
443 {
444 return result;
445 }
446
447 masterDev->devControlInfo = masterControlInfo;
448 masterDev->bus = bus;
449
450 /* call master init to initialize master */
451 result = masterControlInfo->funcs->Init(masterDev);
452
453 if (result != kStatus_Success)
454 {
455 return result;
456 }
457
458 if (!masterControlInfo->isSecondary)
459 {
460 bus->currentMaster = masterDev;
461 /* Add masterDev to bus i3c device list */
462 I3C_BusAddI3CDev(bus, masterDev);
463
464 /* Execute reset DAA CCC command to reset all i3c device dynamic address */
465 result = I3C_BusMasterResetDAA(masterDev, I3C_BUS_BROADCAST_ADDR);
466 if (result != kStatus_Success)
467 {
468 return result;
469 }
470
471 /* Master assign slave with init dynamic address. */
472 result = I3C_BusMasterAssignDevDynamicAddr(masterDev);
473 if (result != kStatus_Success)
474 {
475 return result;
476 }
477
478 result = I3C_BusMasterAddExistingI3CDevs(masterDev);
479 if (result != kStatus_Success)
480 {
481 return result;
482 }
483
484 /* Disable all events before start doing DAA. */
485 result = I3C_BusMasterDisableEvents(masterDev, I3C_BUS_BROADCAST_ADDR,
486 ((uint8_t)kI3C_EventMR | (uint8_t)kI3C_EventHJ | (uint8_t)kI3C_EventIBI));
487 if (result != kStatus_Success)
488 {
489 return result;
490 }
491
492 /* Start to do DAA */
493 result = I3C_BusMasterDoDAA(masterDev);
494 if (result != kStatus_Success)
495 {
496 return result;
497 }
498
499 /* Enable all events before start doing DAA. */
500 result = I3C_BusMasterEnableEvents(masterDev, I3C_BUS_BROADCAST_ADDR,
501 ((uint8_t)kI3C_EventMR | (uint8_t)kI3C_EventHJ | (uint8_t)kI3C_EventIBI));
502 if (result != kStatus_Success)
503 {
504 return result;
505 }
506 }
507
508 return result;
509 }
510
511 /*!
512 * brief Bus master transfer CCC frame.
513 *
514 * Bus master call this function to transfer CCC frame, CCC frame command and data is prepared in @ref i3c_ccc_cmd_t
515 * structure.
516 *
517 * param masterDev Pointer to I3C master device.
518 * param command Pointer to ccc frame.
519 */
I3C_BusMasterSendCCC(i3c_device_t * masterDev,i3c_ccc_cmd_t * command)520 status_t I3C_BusMasterSendCCC(i3c_device_t *masterDev, i3c_ccc_cmd_t *command)
521 {
522 i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
523
524 if (masterDev != masterDev->bus->currentMaster)
525 {
526 return kStatus_I3CBus_NotCurrentMaster;
527 }
528
529 if (masterControlInfo->isSecondary)
530 {
531 return kStatus_I3CBus_Success;
532 }
533
534 if (NULL == masterControlInfo->funcs->TransmitCCC)
535 {
536 return kStatus_I3CBus_MasterOpsUnsupport;
537 }
538
539 return masterControlInfo->funcs->TransmitCCC(masterDev, command);
540 }
541
542 /*!
543 * brief Bus master reset dynamic assigned address.
544 *
545 * Bus master call this function to reset dynamic assigned address, the operation could be done to all connected I3C
546 * devices by using slave address I3C_BUS_BROADCAST_ADDR or to a specific connected device by using the device's dynamic
547 * address.
548 *
549 * param masterDev Pointer to I3C master device.
550 * param slaveAddr Slave address, use I3C_BUS_BROADCAST_ADDR as broadcast address.
551 */
I3C_BusMasterResetDAA(i3c_device_t * masterDev,uint8_t slaveAddr)552 status_t I3C_BusMasterResetDAA(i3c_device_t *masterDev, uint8_t slaveAddr)
553 {
554 i3c_bus_t *i3cBus = masterDev->bus;
555 uint8_t addrStat;
556 status_t result;
557
558 if (masterDev != masterDev->bus->currentMaster)
559 {
560 return kStatus_I3CBus_NotCurrentMaster;
561 }
562
563 addrStat = I3C_BusGetAddrSlotStatus(i3cBus, slaveAddr);
564 if ((slaveAddr != I3C_BUS_BROADCAST_ADDR) && (addrStat != (uint8_t)kI3C_Bus_AddrSlot_I3CDev))
565 {
566 return kStatus_I3CBus_MasterOpsFailure;
567 }
568
569 i3c_ccc_cmd_t rstDaaCmd = {0};
570
571 rstDaaCmd.isRead = false;
572 rstDaaCmd.destAddr = slaveAddr;
573 rstDaaCmd.cmdId = I3C_BUS_CCC_RSTDAA((slaveAddr != I3C_BUS_BROADCAST_ADDR));
574
575 result = I3C_BusMasterSendCCC(masterDev, &rstDaaCmd);
576 if (result == kStatus_Success)
577 {
578 if (slaveAddr != I3C_BUS_BROADCAST_ADDR)
579 {
580 /* Do not free current Controller's dynamic address. */
581 if (masterDev->info.dynamicAddr != slaveAddr)
582 {
583 I3C_BusSetAddrSlot(i3cBus, slaveAddr, kI3C_Bus_AddrSlot_Free);
584 }
585 }
586 else
587 {
588 for (uint8_t i = 0; i <= I3C_BUS_MAX_ADDR; i++)
589 {
590 addrStat = I3C_BusGetAddrSlotStatus(i3cBus, i);
591 if ((addrStat == (uint8_t)kI3C_Bus_AddrSlot_I3CDev) && (masterDev->info.dynamicAddr != i))
592 {
593 I3C_BusSetAddrSlot(i3cBus, i, kI3C_Bus_AddrSlot_Free);
594 }
595 }
596 }
597 }
598
599 return result;
600 }
601
602 /*!
603 * brief Bus master do dynamic address assignment.
604 *
605 * Bus master call this function to do dynamic address assignment to the I3C devices connected on bus.
606 *
607 * param masterDev Pointer to I3C master device.
608 */
I3C_BusMasterDoDAA(i3c_device_t * masterDev)609 status_t I3C_BusMasterDoDAA(i3c_device_t *masterDev)
610 {
611 i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
612 i3c_bus_t *i3cBus = masterDev->bus;
613 status_t result = kStatus_Success;
614
615 if (masterDev != i3cBus->currentMaster)
616 {
617 return kStatus_I3CBus_NotCurrentMaster;
618 }
619
620 result = masterControlInfo->funcs->ProceedDAA(masterDev);
621 if (result != kStatus_Success)
622 {
623 return result;
624 }
625
626 /* Send defslvs command on bus if there's secondary master */
627 bool isSend = false;
628 list_handle_t i3cDevList = &(i3cBus->i3cDevList);
629
630 for (list_element_handle_t listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
631 {
632 i3c_device_t *tmpDev = (i3c_device_t *)(void *)listItem;
633 if (tmpDev == masterDev)
634 {
635 continue;
636 }
637 else if ((tmpDev->info.bcr & I3C_BUS_DEV_BCR_DEV_ROLE_MASK) ==
638 I3C_BUS_DEV_BCR_DEV_ROLE(I3C_BUS_DEV_BCR_DEV_MASTER))
639 {
640 isSend = true;
641 break;
642 }
643 else
644 {
645 /*Empty else to eliminate MISRA 15.7*/
646 }
647 }
648
649 if (isSend)
650 {
651 result = I3C_BusMasterSendSlavesList(masterDev);
652 }
653
654 return result;
655 }
656
657 /*!
658 * brief Bus master set device dynamic address from static address.
659 *
660 * Bus master call this function to execute SETDASA CCC command to set device dynamic address from static address.
661 *
662 * param masterDev Pointer to I3C master device.
663 * param staticAddr Device static address.
664 * param initDynamicAddr Device initialized dynamic address.
665 */
I3C_BusMasterSetDynamicAddrFromStaticAddr(i3c_device_t * master,uint8_t staticAddr,uint8_t initDynamicAddr)666 status_t I3C_BusMasterSetDynamicAddrFromStaticAddr(i3c_device_t *master, uint8_t staticAddr, uint8_t initDynamicAddr)
667 {
668 i3c_ccc_cmd_t setdasaCCC = {0};
669 status_t result = kStatus_Success;
670 uint8_t dynamicAddr = initDynamicAddr << 1;
671
672 setdasaCCC.cmdId = I3C_BUS_CCC_SETDASA;
673 setdasaCCC.destAddr = staticAddr;
674 setdasaCCC.data = &dynamicAddr;
675 setdasaCCC.dataSize = 1U;
676 setdasaCCC.isRead = false;
677
678 result = I3C_BusMasterSendCCC(master, &setdasaCCC);
679
680 return result;
681 }
682
683 /*!
684 * brief Bus master send slave list on bus.
685 *
686 * Bus master call this function to send slave list on bus to notify the secondary master.
687 *
688 * param masterDev Pointer to I3C master device.
689 */
I3C_BusMasterSendSlavesList(i3c_device_t * masterDev)690 status_t I3C_BusMasterSendSlavesList(i3c_device_t *masterDev)
691 {
692 i3c_bus_t *i3cBus = masterDev->bus;
693
694 if (masterDev != i3cBus->currentMaster)
695 {
696 return kStatus_I3CBus_NotCurrentMaster;
697 }
698
699 list_element_handle_t listItem;
700 list_handle_t i2cDevList = &(i3cBus->i2cDevList);
701 list_handle_t i3cDevList = &(i3cBus->i3cDevList);
702
703 i3c_ccc_cmd_t defSlavesCmd = {0};
704 defSlavesCmd.isRead = false;
705 defSlavesCmd.destAddr = I3C_BUS_BROADCAST_ADDR;
706 defSlavesCmd.cmdId = I3C_BUS_CCC_DEFSLVS;
707 uint8_t devCount = 1;
708 status_t result = kStatus_Success;
709
710 for (listItem = i2cDevList->head; listItem != NULL; listItem = listItem->next)
711 {
712 devCount++;
713 }
714
715 for (listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
716 {
717 i3c_device_t *i3cDev = (i3c_device_t *)(void *)listItem;
718 if (i3cDev == masterDev)
719 {
720 continue;
721 }
722 else
723 {
724 devCount++;
725 }
726 }
727
728 defSlavesCmd.dataSize = (uint16_t)sizeof(i3c_ccc_dev_t) * (uint16_t)devCount + 1U;
729 defSlavesCmd.data = malloc(defSlavesCmd.dataSize);
730
731 uint8_t *pData = defSlavesCmd.data;
732
733 *pData = devCount;
734 i3c_ccc_dev_t *masterInfo = (i3c_ccc_dev_t *)(void *)&pData[1];
735 masterInfo->bcr = masterDev->info.bcr;
736 masterInfo->dcr = masterDev->info.dcr;
737 masterInfo->dynamicAddr = masterDev->info.dynamicAddr << 1U;
738 masterInfo->staticAddr = (I3C_BUS_BROADCAST_ADDR << 1U);
739
740 i3c_ccc_dev_t *slaveInfo = (i3c_ccc_dev_t *)((uint32_t)&pData[1] + sizeof(i3c_ccc_dev_t));
741 for (listItem = i2cDevList->head; listItem != NULL; listItem = listItem->next)
742 {
743 slaveInfo->lvr = ((i2c_device_t *)(void *)listItem)->lvr;
744 slaveInfo->staticAddr = (((i2c_device_t *)(void *)listItem)->staticAddr << 1U);
745 slaveInfo++;
746 }
747
748 for (listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
749 {
750 i3c_device_t *i3cDev = (i3c_device_t *)(void *)listItem;
751 if (i3cDev == masterDev)
752 {
753 continue;
754 }
755
756 slaveInfo->dcr = i3cDev->info.dcr;
757 slaveInfo->dynamicAddr = i3cDev->info.dynamicAddr << 1U;
758 slaveInfo->bcr = i3cDev->info.bcr;
759 slaveInfo->staticAddr = i3cDev->info.staticAddr << 1U;
760 slaveInfo++;
761 }
762
763 result = I3C_BusMasterSendCCC(masterDev, &defSlavesCmd);
764
765 free(defSlavesCmd.data);
766
767 return result;
768 }
769
770 /*!
771 * brief Bus master enable events.
772 *
773 * Bus master call this function to enable events on bus.
774 *
775 * param masterDev Pointer to I3C master device.
776 * param slaveAddr Slave address, use I3C_BUS_BROADCAST_ADDR as broadcast address.
777 * param busEvents Logic OR or member in @ref _i3c_bus_events.
778 */
I3C_BusMasterEnableEvents(i3c_device_t * masterDev,uint8_t slaveAddr,uint8_t busEvents)779 status_t I3C_BusMasterEnableEvents(i3c_device_t *masterDev, uint8_t slaveAddr, uint8_t busEvents)
780 {
781 i3c_ccc_cmd_t enEventsCmd = {0};
782 status_t result = kStatus_Success;
783
784 enEventsCmd.isRead = false;
785 enEventsCmd.cmdId = I3C_BUS_CCC_ENEC((slaveAddr != I3C_BUS_BROADCAST_ADDR));
786 enEventsCmd.destAddr = slaveAddr;
787 enEventsCmd.data = &busEvents;
788 enEventsCmd.dataSize = 1U;
789
790 result = I3C_BusMasterSendCCC(masterDev, &enEventsCmd);
791
792 return result;
793 }
794
795 /*!
796 * brief Bus master disable events.
797 *
798 * Bus master call this function to disable events on bus.
799 *
800 * param masterDev Pointer to I3C master device.
801 * param slaveAddr Slave address, use I3C_BUS_BROADCAST_ADDR as broadcast address.
802 * param busEvents Logic OR or member in @ref _i3c_bus_events.
803 */
I3C_BusMasterDisableEvents(i3c_device_t * masterDev,uint8_t slaveAddr,uint8_t busEvents)804 status_t I3C_BusMasterDisableEvents(i3c_device_t *masterDev, uint8_t slaveAddr, uint8_t busEvents)
805 {
806 i3c_ccc_cmd_t disEventsCmd = {0};
807 status_t result = kStatus_Success;
808
809 disEventsCmd.isRead = false;
810 disEventsCmd.cmdId = I3C_BUS_CCC_DISEC((slaveAddr != I3C_BUS_BROADCAST_ADDR));
811 disEventsCmd.destAddr = slaveAddr;
812 disEventsCmd.data = &busEvents;
813 disEventsCmd.dataSize = 1U;
814
815 result = I3C_BusMasterSendCCC(masterDev, &disEventsCmd);
816
817 return result;
818 }
819
820 /*!
821 * brief Bus master get device information for a specific I3C device.
822 *
823 * Bus master call this function to get device information for a specific I3C device.
824 *
825 * param masterDev Pointer to I3C master device.
826 * param slaveAddr Slave address, dynamic assigned address for a device.
827 * param devInfo Input pointer to structure i3c_device_information_t to store the read out device information.
828 */
I3C_BusMasterGetDeviceInfo(i3c_device_t * masterDev,uint8_t slaveAddr,i3c_device_information_t * devInfo)829 status_t I3C_BusMasterGetDeviceInfo(i3c_device_t *masterDev, uint8_t slaveAddr, i3c_device_information_t *devInfo)
830 {
831 status_t result = kStatus_Success;
832
833 devInfo->dynamicAddr = slaveAddr;
834
835 result = I3C_BusMasterGetPID(masterDev, devInfo);
836 if (result != kStatus_Success)
837 {
838 return result;
839 }
840
841 result = I3C_BusMasterGetBCR(masterDev, devInfo);
842 if (result != kStatus_Success)
843 {
844 return result;
845 }
846
847 result = I3C_BusMasterGetDCR(masterDev, devInfo);
848 if (result != kStatus_Success)
849 {
850 return result;
851 }
852
853 result = I3C_BusMasterGetMaxReadLength(masterDev, devInfo);
854 if (result != kStatus_Success)
855 {
856 return result;
857 }
858 result = I3C_BusMasterGetMaxWriteLength(masterDev, devInfo);
859 if (result != kStatus_Success)
860 {
861 return result;
862 }
863
864 if ((devInfo->bcr & I3C_BUS_DEV_BCR_MODE_MASK) != 0U)
865 {
866 result = I3C_BusMasterGetHDRCapability(masterDev, devInfo);
867 if (result != kStatus_Success)
868 {
869 return result;
870 }
871 }
872
873 return result;
874 }
875
I3C_BusMasterRegisterDevIBI(i3c_device_t * masterDev,i3c_device_t * i3cDev,i3c_device_ibi_info_t * devIbiInfo)876 status_t I3C_BusMasterRegisterDevIBI(i3c_device_t *masterDev, i3c_device_t *i3cDev, i3c_device_ibi_info_t *devIbiInfo)
877 {
878 i3c_bus_t *i3cBus = masterDev->bus;
879
880 if (masterDev != i3cBus->currentMaster)
881 {
882 return kStatus_I3CBus_NotCurrentMaster;
883 }
884
885 i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
886 i3cDev->ibiInfo = devIbiInfo;
887
888 if (I3C_BusGetAddrSlotStatus(i3cBus, i3cDev->info.dynamicAddr) == (uint8_t)kI3C_Bus_AddrSlot_I3CDev)
889 {
890 masterControlInfo->funcs->RegisterIBI(masterDev, i3cDev->info.dynamicAddr);
891 }
892 else
893 {
894 return kStatus_I3CBus_InvalidOps;
895 }
896
897 return kStatus_Success;
898 }
899 /*!
900 * brief Bus master handle in-band-interrupt event.
901 *
902 * Bus master call this function to handle in-band-interrupt event.
903 *
904 * param masterDev Pointer to I3C master device.
905 * param ibiAddress slave address which requests the IBI.
906 * param ibiData Pointer to the ibi data buffer.
907 * param payloadSize ibi data buffer size.
908 */
I3C_BusMasterHandleIBI(i3c_device_t * masterDev,uint8_t ibiAddress,void * ibiData,uint32_t payloadSize)909 status_t I3C_BusMasterHandleIBI(i3c_device_t *masterDev, uint8_t ibiAddress, void *ibiData, uint32_t payloadSize)
910 {
911 i3c_bus_t *i3cBus = masterDev->bus;
912
913 if (masterDev != i3cBus->currentMaster)
914 {
915 return kStatus_I3CBus_NotCurrentMaster;
916 }
917
918 list_element_handle_t listItem;
919 list_handle_t i3cDevList = &(i3cBus->i3cDevList);
920 i3c_device_t *i3cDev = NULL;
921
922 for (listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
923 {
924 i3cDev = (i3c_device_t *)(void *)listItem;
925 if (i3cDev == masterDev)
926 {
927 continue;
928 }
929
930 if (i3cDev->info.dynamicAddr == ibiAddress)
931 {
932 break;
933 }
934 }
935
936 if (i3cDev != NULL)
937 {
938 assert(i3cDev->ibiInfo != NULL);
939 assert(i3cDev->ibiInfo->maxPayloadLength >= payloadSize);
940 assert(i3cDev->ibiInfo->ibiHandler != NULL);
941
942 i3cDev->ibiInfo->ibiHandler(i3cDev, ibiData, payloadSize);
943 }
944
945 return kStatus_Success;
946 }
947
948 /*!
949 * brief Bus master do data transfer to I2C device.
950 *
951 * Bus master call this function to transfer data to connected I2C device.
952 *
953 * param masterDev Pointer to I3C master device.
954 * param i2cDev Pointer to the I2C device master do transfer.
955 * param xfer Pointer to bus transfer.
956 */
I3C_BusMasterDoTransferToI2CDev(i3c_device_t * masterDev,i2c_device_t * i2cDev,i3c_bus_transfer_t * xfer)957 status_t I3C_BusMasterDoTransferToI2CDev(i3c_device_t *masterDev, i2c_device_t *i2cDev, i3c_bus_transfer_t *xfer)
958 {
959 i3c_bus_t *i3cBus = masterDev->bus;
960
961 if (masterDev != i3cBus->currentMaster)
962 {
963 return kStatus_I3CBus_NotCurrentMaster;
964 }
965
966 status_t result = kStatus_Success;
967 i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
968
969 if (I3C_BusGetAddrSlotStatus(i3cBus, i2cDev->staticAddr) == (uint8_t)kI3C_Bus_AddrSlot_I2CDev)
970 {
971 result = masterControlInfo->funcs->DoI2CTransfer(i2cDev, xfer);
972 }
973 else
974 {
975 result = kStatus_I3CBus_InvalidOps;
976 }
977
978 return result;
979 }
980
981 /*!
982 * brief Bus master do data transfer to I3C device.
983 *
984 * Bus master call this function to transfer data to connected I3C device.
985 *
986 * param masterDev Pointer to I3C master device.
987 * param i3cDev Pointer to the I3C device master do transfer.
988 * param xfer Pointer to bus transfer.
989 */
I3C_BusMasterDoTransferToI3CDev(i3c_device_t * masterDev,i3c_device_t * i3cDev,i3c_bus_transfer_t * xfer)990 status_t I3C_BusMasterDoTransferToI3CDev(i3c_device_t *masterDev, i3c_device_t *i3cDev, i3c_bus_transfer_t *xfer)
991 {
992 i3c_bus_t *i3cBus = masterDev->bus;
993
994 if (masterDev != i3cBus->currentMaster)
995 {
996 return kStatus_I3CBus_NotCurrentMaster;
997 }
998
999 status_t result = kStatus_Success;
1000 i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
1001
1002 if (I3C_BusGetAddrSlotStatus(i3cBus, i3cDev->info.dynamicAddr) == (uint8_t)kI3C_Bus_AddrSlot_I3CDev)
1003 {
1004 result = masterControlInfo->funcs->DoI3CTransfer(i3cDev, xfer);
1005 }
1006 else
1007 {
1008 result = kStatus_I3CBus_InvalidOps;
1009 }
1010
1011 return result;
1012 }
1013
1014 /*!
1015 * brief Create I2C slave structure on bus.
1016 *
1017 * This function will create I2C device bus structure, initialize the slave according to bus characteristics, install
1018 * device information including static address, lvr and device control information.
1019 *
1020 * param i2cDev Pointer to device structure creating as I2C device.
1021 * param bus Pointer to bus structure.
1022 * param staticAddr Static address of the I2C device
1023 * param lvr legacy virtual register value of the device.
1024 * param devControlInfo Pointer to device control information structure.
1025 */
I3C_BusI2CSlaveCreate(i2c_device_t * i2cDev,i3c_bus_t * bus,uint8_t staticAddr,uint8_t lvr,i2c_device_control_info_t * devControlInfo)1026 status_t I3C_BusI2CSlaveCreate(
1027 i2c_device_t *i2cDev, i3c_bus_t *bus, uint8_t staticAddr, uint8_t lvr, i2c_device_control_info_t *devControlInfo)
1028 {
1029 (void)memset(i2cDev, 0, sizeof(*i2cDev));
1030
1031 i2cDev->bus = bus;
1032 i2cDev->staticAddr = staticAddr;
1033 i2cDev->lvr = lvr;
1034 i2cDev->devControlInfo = devControlInfo;
1035
1036 i3c_device_t *masterDev = NULL;
1037 status_t result = kStatus_Success;
1038
1039 if (bus != NULL)
1040 {
1041 masterDev = (i3c_device_t *)bus->currentMaster;
1042 }
1043
1044 if (masterDev != NULL)
1045 {
1046 /*Add device to bus i2c device list */
1047 I3C_BusAddI2CDev(bus, i2cDev);
1048 }
1049
1050 if ((devControlInfo != NULL) && (devControlInfo->funcs != NULL) && (devControlInfo->funcs->Init != NULL))
1051 {
1052 result = devControlInfo->funcs->Init(i2cDev);
1053 }
1054
1055 return result;
1056 }
1057
1058 /*!
1059 * brief Create I3C slave structure on bus.
1060 *
1061 * This function will create I3C device bus structure, initialize the slave according to bus characteristics, install
1062 * device information and device control information.
1063 *
1064 * param i3cDev Pointer to device structure creating as I3C device.
1065 * param bus Pointer to bus structure.
1066 * param devInfo Pointer to device information structure
1067 * param devControlInfo Pointer to device control information structure.
1068 */
I3C_BusI3CSlaveCreate(i3c_device_t * i3cDev,i3c_bus_t * bus,i3c_device_information_t * devInfo,i3c_device_ibi_info_t * ibiInfo,i3c_device_control_info_t * devControlInfo)1069 status_t I3C_BusI3CSlaveCreate(i3c_device_t *i3cDev,
1070 i3c_bus_t *bus,
1071 i3c_device_information_t *devInfo,
1072 i3c_device_ibi_info_t *ibiInfo,
1073 i3c_device_control_info_t *devControlInfo)
1074 {
1075 (void)memset(i3cDev, 0, sizeof(*i3cDev));
1076
1077 i3cDev->bus = bus;
1078 i3cDev->ibiInfo = ibiInfo;
1079 i3cDev->info = *devInfo;
1080 i3cDev->devControlInfo = devControlInfo;
1081 status_t result = kStatus_Success;
1082
1083 i3c_device_t *masterDev = NULL;
1084
1085 if (bus != NULL)
1086 {
1087 masterDev = (i3c_device_t *)bus->currentMaster;
1088 }
1089
1090 if (masterDev != NULL)
1091 {
1092 /*Add device to bus i3c device list */
1093 I3C_BusAddI3CDev(bus, i3cDev);
1094 }
1095
1096 if ((devControlInfo != NULL) && (devControlInfo->funcs != NULL) && (devControlInfo->funcs->Init != NULL))
1097 {
1098 result = devControlInfo->funcs->Init(i3cDev);
1099 }
1100
1101 return result;
1102 }
1103
1104 /*!
1105 * brief I3C slave device request Hot Join on bus.
1106 *
1107 * param i3cDev Pointer to device structure creating as I3C device.
1108 */
I3C_BusSlaveRequestHotJoin(i3c_device_t * i3cDev)1109 status_t I3C_BusSlaveRequestHotJoin(i3c_device_t *i3cDev)
1110 {
1111 status_t result = kStatus_Success;
1112
1113 if ((i3cDev->devControlInfo != NULL) && (i3cDev->devControlInfo->funcs != NULL) &&
1114 (i3cDev->devControlInfo->funcs->HotJoin != NULL))
1115 {
1116 i3cDev->devControlInfo->funcs->HotJoin(i3cDev);
1117 }
1118 else
1119 {
1120 result = kStatus_I3CBus_SlaveOpsNotSupported;
1121 }
1122
1123 return result;
1124 }
1125
1126 /*!
1127 * brief I3C slave device request mastership on bus.
1128 *
1129 * param i3cDev Pointer to device structure creating as I3C device.
1130 */
I3C_BusSlaveRequestMasterShip(i3c_device_t * i3cDev)1131 status_t I3C_BusSlaveRequestMasterShip(i3c_device_t *i3cDev)
1132 {
1133 status_t result = kStatus_Success;
1134
1135 if ((i3cDev->devControlInfo != NULL) && (i3cDev->devControlInfo->funcs != NULL) &&
1136 (i3cDev->devControlInfo->funcs->RequestMastership != NULL))
1137 {
1138 i3cDev->devControlInfo->funcs->RequestMastership(i3cDev);
1139 }
1140 else
1141 {
1142 result = kStatus_I3CBus_SlaveOpsNotSupported;
1143 }
1144
1145 return result;
1146 }
1147
1148 /*!
1149 * brief I3C slave request IBI events.
1150 *
1151 * param i3cDev Pointer to device structure creating as I3C device.
1152 * param data Pointer to data buffer to be sent in IBI event.
1153 * param dataSize data size of IBI data.
1154 */
I3C_BusSlaveRequestIBI(i3c_device_t * i3cDev,void * data,size_t dataSize)1155 status_t I3C_BusSlaveRequestIBI(i3c_device_t *i3cDev, void *data, size_t dataSize)
1156 {
1157 status_t result = kStatus_Success;
1158
1159 if ((i3cDev->devControlInfo != NULL) && (i3cDev->devControlInfo->funcs != NULL) &&
1160 (i3cDev->devControlInfo->funcs->RequestMastership != NULL))
1161 {
1162 i3cDev->devControlInfo->funcs->RequestIBI(i3cDev, data, dataSize);
1163 }
1164 else
1165 {
1166 result = kStatus_I3CBus_SlaveOpsNotSupported;
1167 }
1168
1169 return result;
1170 }
1171