1 /*
2 * Copyright 2018-2024 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_i3c.h"
8 #if !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
9 #include "fsl_reset.h"
10 #endif
11 #include <stdlib.h>
12 #include <string.h>
13
14 /*******************************************************************************
15 * Definitions
16 ******************************************************************************/
17
18 /* Component ID definition, used by tools. */
19 #ifndef FSL_COMPONENT_ID
20 #define FSL_COMPONENT_ID "platform.drivers.i3c"
21 #endif
22
23 #define I3C_BROADCASE_ADDR (0x7EU)
24
25 #define NSEC_PER_SEC (1000000000UL)
26 #define FSL_I3C_ERROR_RATE_MAX (10U)
27 #define FSL_I3C_PPBAUD_DIV_MAX ((I3C_MCONFIG_PPBAUD_MASK >> I3C_MCONFIG_PPBAUD_SHIFT) + 1U)
28 #define FSL_I3C_ODBAUD_DIV_MAX ((I3C_MCONFIG_ODBAUD_MASK >> I3C_MCONFIG_ODBAUD_SHIFT) + 1U)
29 #define FSL_I3C_I2CBAUD_DIV_MAX (((I3C_MCONFIG_I2CBAUD_MASK >> I3C_MCONFIG_I2CBAUD_SHIFT) + 1U) / 2U)
30
31 /*! @brief Common sets of flags used by the driver. */
32 enum _i3c_flag_constants
33 {
34 /*! All flags which are cleared by the driver upon starting a transfer. */
35 kMasterClearFlags = kI3C_MasterSlaveStartFlag | kI3C_MasterControlDoneFlag | kI3C_MasterCompleteFlag |
36 kI3C_MasterArbitrationWonFlag | kI3C_MasterSlave2MasterFlag | kI3C_MasterErrorFlag,
37
38 /*! IRQ sources enabled by the non-blocking transactional API. */
39 kMasterIrqFlags = kI3C_MasterSlaveStartFlag | kI3C_MasterControlDoneFlag | kI3C_MasterCompleteFlag |
40 kI3C_MasterRxReadyFlag /* | kI3C_MasterTxReadyFlag */ | kI3C_MasterArbitrationWonFlag |
41 kI3C_MasterErrorFlag | kI3C_MasterSlave2MasterFlag,
42
43 /*! Errors to check for. */
44 kMasterErrorFlags = kI3C_MasterErrorNackFlag | kI3C_MasterErrorWriteAbortFlag |
45 #if !defined(FSL_FEATURE_I3C_HAS_NO_MERRWARN_TERM) || (!FSL_FEATURE_I3C_HAS_NO_MERRWARN_TERM)
46 kI3C_MasterErrorTermFlag |
47 #endif
48 kI3C_MasterErrorParityFlag | kI3C_MasterErrorCrcFlag | kI3C_MasterErrorReadFlag |
49 kI3C_MasterErrorWriteFlag | kI3C_MasterErrorMsgFlag | kI3C_MasterErrorInvalidReqFlag |
50 kI3C_MasterErrorTimeoutFlag,
51 /*! All flags which are cleared by the driver upon starting a transfer. */
52 kSlaveClearFlags = kI3C_SlaveBusStartFlag | kI3C_SlaveMatchedFlag | kI3C_SlaveBusStopFlag,
53
54 /*! IRQ sources enabled by the non-blocking transactional API. */
55 kSlaveIrqFlags = kI3C_SlaveBusStartFlag | kI3C_SlaveMatchedFlag | kI3C_SlaveBusStopFlag | kI3C_SlaveRxReadyFlag |
56 kI3C_SlaveDynamicAddrChangedFlag | kI3C_SlaveReceivedCCCFlag | kI3C_SlaveErrorFlag |
57 kI3C_SlaveHDRCommandMatchFlag | kI3C_SlaveCCCHandledFlag | kI3C_SlaveEventSentFlag,
58
59 /*! Errors to check for. */
60 kSlaveErrorFlags = kI3C_SlaveErrorOverrunFlag | kI3C_SlaveErrorUnderrunFlag | kI3C_SlaveErrorUnderrunNakFlag |
61 kI3C_SlaveErrorTermFlag | kI3C_SlaveErrorInvalidStartFlag | kI3C_SlaveErrorSdrParityFlag |
62 kI3C_SlaveErrorHdrParityFlag | kI3C_SlaveErrorHdrCRCFlag | kI3C_SlaveErrorS0S1Flag |
63 kI3C_SlaveErrorOverreadFlag | kI3C_SlaveErrorOverwriteFlag,
64 };
65
66 /*! @brief States for the state machine used by transactional APIs. */
67 enum _i3c_transfer_states
68 {
69 kIdleState = 0,
70 kIBIWonState,
71 kSlaveStartState,
72 kSendCommandState,
73 kWaitRepeatedStartCompleteState,
74 kTransferDataState,
75 kStopState,
76 kWaitForCompletionState,
77 };
78
79 /*!
80 * @brief Used for conversion between `uint8_t*` and `uint32_t`.
81 */
82 typedef union i3c_puint8_to_u32
83 {
84 uint8_t *puint8;
85 uint32_t u32;
86 const uint8_t *cpuint8;
87 } i3c_puint8_to_u32_t;
88
89 /*
90 * <! Structure definition for variables that passed as parameters in I3C_RunTransferStateMachine.
91 * The structure is private.
92 */
93 typedef struct _i3c_state_machine_param
94 {
95 bool state_complete;
96 size_t txCount;
97 size_t rxCount;
98 uint32_t status;
99 status_t result;
100 i3c_master_state_t masterState;
101 } i3c_master_state_machine_param_t;
102
103 /*
104 * <! Structure definition for variables that passed as parameters in I3C_SlaveTransferHandleIRQ.
105 * The structure is private.
106 */
107 typedef struct _i3c_transfer_handleIrq_param
108 {
109 size_t txCount;
110 size_t rxCount;
111 uint32_t flags;
112 uint32_t pendingInts;
113 uint32_t enabledInts;
114 } i3c_slave_handleIrq_param_t;
115
116 /*******************************************************************************
117 * Prototypes
118 ******************************************************************************/
119
120 /* Not static so it can be used from fsl_i3c_dma.c. */
121 static status_t I3C_MasterWaitForTxReady(I3C_Type *base, uint8_t byteCounts);
122 /*******************************************************************************
123 * Variables
124 ******************************************************************************/
125
126 /*! @brief Array to map I3C instance number to base pointer. */
127 static I3C_Type *const kI3cBases[] = I3C_BASE_PTRS;
128
129 /*! @brief Array to map I3C instance number to IRQ number. */
130 IRQn_Type const kI3cIrqs[] = I3C_IRQS;
131
132 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
133 /*! @brief Array to map I3C instance number to clock gate enum. */
134 static clock_ip_name_t const kI3cClocks[] = I3C_CLOCKS;
135 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
136
137 #if !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
138 /*! @brief Pointers to I3C resets for each instance. */
139 static const reset_ip_name_t kI3cResets[] = I3C_RSTS;
140 #endif
141
142 static i3c_device_info_t devList[I3C_MAX_DEVCNT]; /*!< I3C slave record list */
143 static uint8_t usedDevCount = 0;
144
145 /*! @brief Pointer to master IRQ handler for each instance. */
146 i3c_master_isr_t s_i3cMasterIsr;
147
148 /*! @brief Pointers to master handles for each instance. */
149 void *s_i3cMasterHandle[ARRAY_SIZE(kI3cBases)];
150
151 /*! @brief Pointer to slave IRQ handler for each instance. */
152 i3c_slave_isr_t s_i3cSlaveIsr;
153
154 /*! @brief Pointers to slave handles for each instance. */
155 void *s_i3cSlaveHandle[ARRAY_SIZE(kI3cBases)];
156
157 /*!
158 * @brief introduce function I3C_TransferStateMachineIBIWonState.
159 * This function was deal with init function I3C_RunTransferStateMachine`s variable.
160 *
161 * @param base The I3C peripheral base address.
162 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
163 * @param stateParams Pass the address of the parent function variable.
164 */
165 static void I3C_TransferStateMachineIBIWonState(I3C_Type *base,
166 i3c_master_handle_t *handle,
167 i3c_master_state_machine_param_t *stateParams);
168
169 /*!
170 * @brief introduce function static bool I3C_TransferStateMachineSendCommandState.
171 * This function was deal with when state is stop.
172 *
173 * @param base The I3C peripheral base address.
174 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
175 * @param stateParams Pass the address of the parent function variable.
176 */
177 static void I3C_TransferStateMachineSendCommandState(I3C_Type *base,
178 i3c_master_handle_t *handle,
179 i3c_master_state_machine_param_t *stateParams);
180
181 /*!
182 * @brief introduce function I3C_TransferStateMachineWaitRepeatedStartCompleteState.
183 * This function was deal with Wait Repeated Start Complete State.
184 *
185 * @param base The I3C peripheral base address.
186 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
187 * @param stateParams Pass the address of the parent function variable.
188 */
189 static void I3C_TransferStateMachineWaitRepeatedStartCompleteState(I3C_Type *base,
190 i3c_master_handle_t *handle,
191 i3c_master_state_machine_param_t *stateParams);
192
193 /*!
194 * @brief introduce function I3C_TransferStateMachineTransferDataState.
195 * This function was deal with Transfer Data State.
196 *
197 * @param base The I3C peripheral base address.
198 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
199 * @param stateParams Pass the address of the parent function variable.
200 */
201 static void I3C_TransferStateMachineTransferDataState(I3C_Type *base,
202 i3c_master_handle_t *handle,
203 i3c_master_state_machine_param_t *stateParams);
204 /*!
205 * @brief introduce function I3C_TransferStateMachineWaitForCompletionState.
206 * This function was deal with Wait For Completion State.
207 *
208 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
209 * @param stateParams Pass the address of the parent function variable.
210 */
211 static void I3C_TransferStateMachineWaitForCompletionState(i3c_master_handle_t *handle,
212 i3c_master_state_machine_param_t *stateParams);
213
214 /*!
215 * @brief introduce function I3C_TransferStateMachineStopState.
216 * This function was deal with Stop State.
217 *
218 * @param base The I3C peripheral base address.
219 * @param stateParams Pass the address of the parent function variable.
220 */
221 static void I3C_TransferStateMachineStopState(I3C_Type *base,
222 i3c_master_handle_t *handle,
223 i3c_master_state_machine_param_t *stateParams);
224
225 /*!
226 * @brief introduce function I3C_SlaveTransferHandleGetStatusFlags.
227 * This function was deal get status flag.
228 *
229 * @param base The I3C peripheral base address.
230 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
231 * @param stateParams Pass the address of the parent function variable.
232 *
233 * @return default true when No abnormality.
234 * @return true when error.
235 */
236 static bool I3C_SlaveTransferHandleGetStatusFlags(I3C_Type *base,
237 i3c_slave_handle_t *handle,
238 i3c_slave_handleIrq_param_t *stateParams);
239 /*!
240 * @brief introduce function I3C_SlaveTransferHandleBusStart.
241 * This function was deal start Bus.
242 *
243 * @param base The I3C peripheral base address.
244 * @param xfer address to xfer.
245 * @param pendingInts address to pendingInts.
246 */
247 static void I3C_SlaveTransferHandleBusStart(I3C_Type *base, i3c_slave_transfer_t *xfer, uint32_t *pendingInts);
248
249 /*!
250 * @brief introduce function I3C_SlaveTransferHandleEventSent.
251 * This function was deal sent event.
252 *
253 * @param base The I3C peripheral base address.
254 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
255 * @param xfer address to xfer.
256 */
257 static void I3C_SlaveTransferHandleEventSent(I3C_Type *base, i3c_slave_handle_t *handle, i3c_slave_transfer_t *xfer);
258
259 /*!
260 * @brief introduce function I3C_SlaveTransferHandleReceivedCCC.
261 * This function was deal Received.
262 *
263 * @param base The I3C peripheral base address.
264 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
265 * @param xfer address to xfer.
266 */
267 static void I3C_SlaveTransferHandleReceivedCCC(I3C_Type *base, i3c_slave_handle_t *handle, i3c_slave_transfer_t *xfer);
268
269 /*!
270 * @brief introduce function I3C_SlaveTransferHandleBusStop.
271 * This function was deal stop Bus.
272 *
273 * @param base The I3C peripheral base address.
274 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
275 * @param stateParams Pass the address of the parent function variable.
276 */
277 static void I3C_SlaveTransferHandleBusStop(I3C_Type *base,
278 i3c_slave_handle_t *handle,
279 i3c_slave_handleIrq_param_t *stateParams);
280
281 /*!
282 * @brief introduce function I3C_SlaveTransferHandleMatched.
283 * This function was deal matched.
284 *
285 * @param base The I3C peripheral base address.
286 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
287 * @param xfer address to xfer.
288 */
289 static void I3C_SlaveTransferHandleMatched(I3C_Type *base, i3c_slave_handle_t *handle, i3c_slave_transfer_t *xfer);
290
291 /*!
292 * @brief introduce function I3C_SlaveTransferHandleTxReady.
293 * This function was deal when Tx was ready.
294 *
295 * @param base The I3C peripheral base address.
296 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
297 * @param stateParams Pass the address of the parent function variable.
298 */
299 static void I3C_SlaveTransferHandleTxReady(I3C_Type *base,
300 i3c_slave_handle_t *handle,
301 i3c_slave_handleIrq_param_t *stateParams);
302
303 /*!
304 * @brief introduce function I3C_SlaveTransferHandleRxReadyy.
305 * This function was deal with when Rx was ready.
306 *
307 * @param base The I3C peripheral base address.
308 * @param handle handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
309 * @param stateParams Pass the address of the parent function variable.
310 */
311 static void I3C_SlaveTransferHandleRxReady(I3C_Type *base,
312 i3c_slave_handle_t *handle,
313 i3c_slave_handleIrq_param_t *stateParams);
314
315 /*******************************************************************************
316 * Code
317 ******************************************************************************/
318
319 /*!
320 * @brief Returns an instance number given a base address.
321 *
322 * If an invalid base address is passed, debug builds will assert. Release builds will just return
323 * instance number 0.
324 *
325 * @param base The I3C peripheral base address.
326 * @return I3C instance number starting from 0.
327 */
I3C_GetInstance(I3C_Type * base)328 uint32_t I3C_GetInstance(I3C_Type *base)
329 {
330 uint32_t instance;
331 for (instance = 0; instance < ARRAY_SIZE(kI3cBases); ++instance)
332 {
333 if (MSDK_REG_SECURE_ADDR(kI3cBases[instance]) == MSDK_REG_SECURE_ADDR(base))
334 {
335 break;
336 }
337 }
338
339 assert(instance < ARRAY_SIZE(kI3cBases));
340
341 return instance;
342 }
343
344 /*!
345 * @brief Convert provided flags to status code, and clear any errors if present.
346 * @param base The I3C peripheral base address.
347 * @param status Current status flags value that will be checked.
348 * @retval #kStatus_Success
349 * @retval #kStatus_I3C_Nak
350 * @retval #kStatus_I3C_WriteAbort
351 * @retval #kStatus_I3C_Term
352 * @retval #kStatus_I3C_HdrParityError
353 * @retval #kStatus_I3C_CrcError
354 * @retval #kStatus_I3C_ReadFifoError
355 * @retval #kStatus_I3C_WriteFifoError
356 * @retval #kStatus_I3C_MsgError
357 * @retval #kStatus_I3C_InvalidReq
358 * @retval #kStatus_I3C_Timeout
359 */
360 /* Not static so it can be used from fsl_i3c_edma.c. */
I3C_MasterCheckAndClearError(I3C_Type * base,uint32_t status)361 status_t I3C_MasterCheckAndClearError(I3C_Type *base, uint32_t status)
362 {
363 status_t result = kStatus_Success;
364
365 /* Check for error. These errors cause a stop to automatically be sent. We must */
366 /* clear the errors before a new transfer can start. */
367 status &= (uint32_t)kMasterErrorFlags;
368
369 #if defined(I3C_DMA_IGNORE_FIFO_ERROR)
370 status &= ~((uint32_t)kI3C_MasterErrorWriteFlag | (uint32_t)kI3C_MasterErrorReadFlag);
371 I3C_MasterClearErrorStatusFlags(base, ((uint32_t)kI3C_MasterErrorWriteFlag | (uint32_t)kI3C_MasterErrorReadFlag));
372 #endif
373
374 if (0UL != (status))
375 {
376 /* Select the correct error code. Ordered by severity, with bus issues first. */
377 if (0UL != (status & (uint32_t)kI3C_MasterErrorTimeoutFlag))
378 {
379 result = kStatus_I3C_Timeout;
380 }
381 else if (0UL != (status & (uint32_t)kI3C_MasterErrorNackFlag))
382 {
383 result = kStatus_I3C_Nak;
384 }
385 else if (0UL != (status & (uint32_t)kI3C_MasterErrorWriteAbortFlag))
386 {
387 result = kStatus_I3C_WriteAbort;
388 }
389 #if !defined(FSL_FEATURE_I3C_HAS_NO_MERRWARN_TERM) || (!FSL_FEATURE_I3C_HAS_NO_MERRWARN_TERM)
390 else if (0UL != (status & (uint32_t)kI3C_MasterErrorTermFlag))
391 {
392 result = kStatus_I3C_Term;
393 }
394 #endif
395 else if (0UL != (status & (uint32_t)kI3C_MasterErrorParityFlag))
396 {
397 result = kStatus_I3C_HdrParityError;
398 }
399 else if (0UL != (status & (uint32_t)kI3C_MasterErrorCrcFlag))
400 {
401 result = kStatus_I3C_CrcError;
402 }
403 else if (0UL != (status & (uint32_t)kI3C_MasterErrorMsgFlag))
404 {
405 result = kStatus_I3C_MsgError;
406 }
407 else if (0UL != (status & (uint32_t)kI3C_MasterErrorReadFlag))
408 {
409 result = kStatus_I3C_ReadFifoError;
410 }
411 else if (0UL != (status & (uint32_t)kI3C_MasterErrorWriteFlag))
412 {
413 result = kStatus_I3C_WriteFifoError;
414 }
415 else if (0UL != (status & (uint32_t)kI3C_MasterErrorInvalidReqFlag))
416 {
417 result = kStatus_I3C_InvalidReq;
418 }
419 else
420 {
421 assert(false);
422 }
423
424 /* Clear the flags. */
425 I3C_MasterClearErrorStatusFlags(base, status);
426
427 /* Reset fifos. These flags clear automatically. */
428 base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
429 }
430
431 return result;
432 }
433
I3C_MasterWaitForCtrlDone(I3C_Type * base,bool waitIdle)434 status_t I3C_MasterWaitForCtrlDone(I3C_Type *base, bool waitIdle)
435 {
436 status_t result = kStatus_Success;
437 uint32_t status, errStatus;
438 #if I3C_RETRY_TIMES
439 uint32_t waitTimes = I3C_RETRY_TIMES;
440 #endif
441
442 #if I3C_RETRY_TIMES
443 while ((result == kStatus_Success) && (--waitTimes))
444 #else
445 while (result == kStatus_Success)
446 #endif
447 {
448 status = I3C_MasterGetStatusFlags(base);
449 errStatus = I3C_MasterGetErrorStatusFlags(base);
450 /* Check for error flags. */
451 result = I3C_MasterCheckAndClearError(base, errStatus);
452 /* Check if the control finishes. */
453 if (0UL != (status & (uint32_t)kI3C_MasterControlDoneFlag))
454 {
455 I3C_MasterClearStatusFlags(base, (uint32_t)kI3C_MasterControlDoneFlag);
456 if (!waitIdle)
457 {
458 break;
459 }
460 }
461 /* kI3C_MasterControlDoneFlag only indicates ACK got, need to wait for SDA high. */
462 if (waitIdle && I3C_MasterGetState(base) == kI3C_MasterStateIdle)
463 {
464 break;
465 }
466 }
467
468 #if I3C_RETRY_TIMES
469 if (waitTimes == 0)
470 {
471 return kStatus_I3C_Timeout;
472 }
473 #endif
474
475 return result;
476 }
477
I3C_MasterWaitForTxReady(I3C_Type * base,uint8_t byteCounts)478 static status_t I3C_MasterWaitForTxReady(I3C_Type *base, uint8_t byteCounts)
479 {
480 uint32_t errStatus;
481 status_t result;
482 size_t txCount;
483 size_t txFifoSize =
484 2UL << ((base->SCAPABILITIES & I3C_SCAPABILITIES_FIFOTX_MASK) >> I3C_SCAPABILITIES_FIFOTX_SHIFT);
485
486 #if I3C_RETRY_TIMES
487 uint32_t waitTimes = I3C_RETRY_TIMES;
488 #endif
489 do
490 {
491 /* Get the number of words in the tx fifo and compute empty slots. */
492 I3C_MasterGetFifoCounts(base, NULL, &txCount);
493 txCount = txFifoSize - txCount;
494
495 /* Check for error flags. */
496 errStatus = I3C_MasterGetErrorStatusFlags(base);
497 result = I3C_MasterCheckAndClearError(base, errStatus);
498 if (kStatus_Success != result)
499 {
500 return result;
501 }
502 #if I3C_RETRY_TIMES
503 } while ((txCount < byteCounts) && (--waitTimes));
504
505 if (waitTimes == 0)
506 {
507 return kStatus_I3C_Timeout;
508 }
509 #else
510 } while (txCount < byteCounts);
511 #endif
512
513 return kStatus_Success;
514 }
515
I3C_MasterWaitForComplete(I3C_Type * base,bool waitIdle)516 static status_t I3C_MasterWaitForComplete(I3C_Type *base, bool waitIdle)
517 {
518 uint32_t status, errStatus;
519 status_t result = kStatus_Success;
520 #if I3C_RETRY_TIMES
521 uint32_t waitTimes = I3C_RETRY_TIMES;
522 #endif
523 do
524 {
525 status = I3C_MasterGetStatusFlags(base);
526 errStatus = I3C_MasterGetErrorStatusFlags(base);
527 result = I3C_MasterCheckAndClearError(base, errStatus);
528 #if I3C_RETRY_TIMES
529 } while (((status & (uint32_t)kI3C_MasterCompleteFlag) != (uint32_t)kI3C_MasterCompleteFlag) &&
530 (result == kStatus_Success) && --waitTimes);
531 #else
532 } while (((status & (uint32_t)kI3C_MasterCompleteFlag) != (uint32_t)kI3C_MasterCompleteFlag) &&
533 (result == kStatus_Success));
534 #endif
535
536 I3C_MasterClearStatusFlags(base, (uint32_t)kI3C_MasterCompleteFlag);
537
538 #if I3C_RETRY_TIMES
539 if (waitTimes == 0UL)
540 {
541 return kStatus_I3C_Timeout;
542 }
543 #endif
544
545 if (waitIdle)
546 {
547 #if I3C_RETRY_TIMES
548 while ((I3C_MasterGetState(base) != kI3C_MasterStateIdle) && --waitTimes)
549 #else
550 while (I3C_MasterGetState(base) != kI3C_MasterStateIdle)
551 #endif
552 {
553 }
554 }
555
556 return result;
557 }
558
559 /*!
560 * @brief Convert provided flags to status code, and clear any errors if present.
561 * @param base The I3C peripheral base address.
562 * @param status Current status flags value that will be checked.
563 * @retval #kStatus_Success
564 * @retval #kStatus_I3C_OverrunError
565 * @retval #kStatus_I3C_UnderrunError
566 * @retval #kStatus_I3C_UnderrunNak
567 * @retval #kStatus_I3C_Term
568 * @retval #kStatus_I3C_InvalidStart
569 * @retval #kStatus_I3C_SdrParityError
570 * @retval #kStatus_I3C_HdrParityError
571 * @retval #kStatus_I3C_CrcError
572 * @retval #kStatus_I3C_S0S1Error
573 * @retval #kStatus_I3C_ReadFifoError
574 * @retval #kStatus_I3C_WriteFifoError
575 */
I3C_SlaveCheckAndClearError(I3C_Type * base,uint32_t status)576 status_t I3C_SlaveCheckAndClearError(I3C_Type *base, uint32_t status)
577 {
578 status_t result = kStatus_Success;
579
580 /* Check for error. These errors cause a stop to automatically be sent. We must */
581 /* clear the errors before a new transfer can start. */
582 status &= (uint32_t)kSlaveErrorFlags;
583
584 #if defined(I3C_DMA_IGNORE_FIFO_ERROR)
585 status &= ~((uint32_t)kI3C_SlaveErrorUnderrunFlag | (uint32_t)kI3C_SlaveErrorOverwriteFlag);
586 I3C_SlaveClearErrorStatusFlags(base,
587 ((uint32_t)kI3C_SlaveErrorUnderrunFlag | (uint32_t)kI3C_SlaveErrorOverwriteFlag));
588 #endif
589
590 if (0UL != status)
591 {
592 /* Select the correct error code. Ordered by severity, with bus issues first. */
593 if (0UL != (status & (uint32_t)kI3C_SlaveErrorOverrunFlag))
594 {
595 result = kStatus_I3C_OverrunError;
596 }
597 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorUnderrunFlag))
598 {
599 result = kStatus_I3C_UnderrunError;
600 }
601 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorUnderrunNakFlag))
602 {
603 result = kStatus_I3C_UnderrunNak;
604 }
605 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorTermFlag))
606 {
607 result = kStatus_I3C_Term;
608 }
609 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorInvalidStartFlag))
610 {
611 result = kStatus_I3C_InvalidStart;
612 }
613 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorSdrParityFlag))
614 {
615 result = kStatus_I3C_SdrParityError;
616 }
617 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorHdrParityFlag))
618 {
619 result = kStatus_I3C_HdrParityError;
620 }
621 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorHdrCRCFlag))
622 {
623 result = kStatus_I3C_CrcError;
624 }
625 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorS0S1Flag))
626 {
627 result = kStatus_I3C_S0S1Error;
628 }
629 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorOverreadFlag))
630 {
631 result = kStatus_I3C_ReadFifoError;
632 }
633 else if (0UL != (status & (uint32_t)kI3C_SlaveErrorOverwriteFlag))
634 {
635 result = kStatus_I3C_WriteFifoError;
636 }
637 else
638 {
639 assert(false);
640 }
641
642 /* Clear the flags. */
643 I3C_SlaveClearErrorStatusFlags(base, status);
644
645 /* Reset fifos. These flags clear automatically. */
646 base->SDATACTRL |= I3C_SDATACTRL_FLUSHTB_MASK | I3C_SDATACTRL_FLUSHFB_MASK;
647 }
648
649 return result;
650 }
651
I3C_SlaveWaitForTxReady(I3C_Type * base)652 static status_t I3C_SlaveWaitForTxReady(I3C_Type *base)
653 {
654 uint32_t errStatus;
655 status_t result;
656 size_t txCount;
657 size_t txFifoSize =
658 2UL << ((base->SCAPABILITIES & I3C_SCAPABILITIES_FIFOTX_MASK) >> I3C_SCAPABILITIES_FIFOTX_SHIFT);
659
660 #if I3C_RETRY_TIMES
661 uint32_t waitTimes = I3C_RETRY_TIMES;
662 #endif
663 do
664 {
665 /* Get the number of words in the tx fifo and compute empty slots. */
666 I3C_SlaveGetFifoCounts(base, NULL, &txCount);
667 txCount = txFifoSize - txCount;
668
669 /* Check for error flags. */
670 errStatus = I3C_SlaveGetErrorStatusFlags(base);
671 result = I3C_SlaveCheckAndClearError(base, errStatus);
672 if (kStatus_Success != result)
673 {
674 return result;
675 }
676 #if I3C_RETRY_TIMES
677 } while ((txCount == 0UL) && (--waitTimes));
678
679 if (waitTimes == 0)
680 {
681 return kStatus_I3C_Timeout;
682 }
683 #else
684 } while (txCount == 0UL);
685 #endif
686
687 return kStatus_Success;
688 }
689
I3C_MasterEmitStop(I3C_Type * base,bool waitIdle)690 static status_t I3C_MasterEmitStop(I3C_Type *base, bool waitIdle)
691 {
692 status_t result = kStatus_Success;
693
694 /* Return an error if the bus is not in transaction. */
695 if (I3C_MasterGetState(base) != kI3C_MasterStateNormAct)
696 {
697 return kStatus_I3C_InvalidReq;
698 }
699
700 /* Send the STOP signal */
701 base->MCTRL = (base->MCTRL & ~(I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_RDTERM_MASK)) |
702 I3C_MCTRL_REQUEST(kI3C_RequestEmitStop);
703
704 /* Wait for the stop operation finishes. */
705 /* Also check for errors while waiting. */
706 result = I3C_MasterWaitForCtrlDone(base, waitIdle);
707
708 return result;
709 }
710
711 /*!
712 * brief I3C master get IBI Type.
713 *
714 * param base The I3C peripheral base address.
715 * param i3c_ibi_type_t Type of #i3c_ibi_type_t.
716 */
I3C_GetIBIType(I3C_Type * base)717 i3c_ibi_type_t I3C_GetIBIType(I3C_Type *base)
718 {
719 uint32_t ibiValue = (base->MSTATUS & I3C_MSTATUS_IBITYPE_MASK) >> I3C_MSTATUS_IBITYPE_SHIFT;
720 i3c_ibi_type_t ibiType = kI3C_IbiNormal;
721
722 switch (ibiValue)
723 {
724 case 3L:
725 ibiType = kI3C_IbiHotJoin;
726 break;
727 case 2L:
728 ibiType = kI3C_IbiMasterRequest;
729 break;
730 default:
731 ibiType = kI3C_IbiNormal;
732 break;
733 }
734
735 return ibiType;
736 }
737
738 /*!
739 * @brief Make sure the bus isn't already busy.
740 *
741 * A busy bus is allowed if we are the one driving it.
742 *
743 * @param base The I3C peripheral base address.
744 * @retval #kStatus_Success
745 * @retval #kStatus_I3C_Busy
746 */
747 /* Not static so it can be used from fsl_i3c_edma.c. */
I3C_CheckForBusyBus(I3C_Type * base)748 status_t I3C_CheckForBusyBus(I3C_Type *base)
749 {
750 return (I3C_MasterGetBusIdleState(base) == true) ? kStatus_Success : kStatus_I3C_Busy;
751 }
752
753 /* brief Provides a default configuration for the I3C peripheral.
754 *
755 */
I3C_GetDefaultConfig(i3c_config_t * config)756 void I3C_GetDefaultConfig(i3c_config_t *config)
757 {
758 assert(NULL != config);
759
760 (void)memset(config, 0, sizeof(*config));
761
762 config->enableMaster = kI3C_MasterCapable;
763 config->disableTimeout = false;
764 config->hKeep = kI3C_MasterHighKeeperNone;
765 config->enableOpenDrainStop = true;
766 config->enableOpenDrainHigh = true;
767 config->baudRate_Hz.i2cBaud = 400000U;
768 config->baudRate_Hz.i3cPushPullBaud = 12500000U;
769 config->baudRate_Hz.i3cOpenDrainBaud = 2500000U;
770 config->masterDynamicAddress = 0x0AU; /* Default master dynamic address. */
771 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
772 config->slowClock_Hz = 0; /* Not update the Soc default setting. */
773 #endif
774 config->enableSlave = true;
775 config->vendorID = 0x11BU;
776 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND)
777 config->enableRandomPart = false;
778 #endif
779 config->partNumber = 0;
780 config->dcr = 0; /* Generic device. */
781 config->bcr = 0; /* BCR[7:6]: device role, I3C slave(2b'00), BCR[5]: SDR Only / SDR and HDR Capable, SDR and HDR
782 Capable(1b'1), BCR[4]: Bridge Identifier, Not a bridge device(1b'0), BCR[3]: Offline Capable,
783 device is offline capable(1b'1), BCR[2]: IBI Payload, No data byte following(1b'0), BCR[1]: IBI
784 Request Capable, capable(1b'1), BCR[0]: Max Data Speed Limitation, has limitation(1b'1). */
785 config->hdrMode = (uint8_t)kI3C_HDRModeDDR;
786 config->nakAllRequest = false;
787 config->ignoreS0S1Error = false;
788 config->offline = false;
789 config->matchSlaveStartStop = false;
790 config->maxWriteLength = 256U;
791 config->maxReadLength = 256U;
792 }
793
794 /*!
795 * @brief Initializes the I3C peripheral.
796 *
797 */
I3C_Init(I3C_Type * base,const i3c_config_t * config,uint32_t sourceClock_Hz)798 void I3C_Init(I3C_Type *base, const i3c_config_t *config, uint32_t sourceClock_Hz)
799 {
800 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) || \
801 !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
802 uint32_t instance = I3C_GetInstance(base);
803 #endif
804 uint32_t configValue;
805
806 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
807 /* Ungate the clock. */
808 CLOCK_EnableClock(kI3cClocks[instance]);
809 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
810
811 #if !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
812 /* Reset the I3C module */
813 RESET_PeripheralReset(kI3cResets[instance]);
814 #endif
815
816 if ((config->masterDynamicAddress != 0U) && (config->enableMaster == kI3C_MasterOn))
817 {
818 base->MDYNADDR &= ~I3C_MDYNADDR_DADDR_MASK;
819 base->MDYNADDR |= I3C_MDYNADDR_DADDR(config->masterDynamicAddress) | I3C_MDYNADDR_DAVALID_MASK;
820 }
821
822 base->MCONFIG = I3C_MCONFIG_MSTENA(config->enableMaster) | I3C_MCONFIG_DISTO(config->disableTimeout) |
823 I3C_MCONFIG_HKEEP(config->hKeep) | I3C_MCONFIG_ODSTOP(config->enableOpenDrainStop) |
824 I3C_MCONFIG_ODHPP(config->enableOpenDrainHigh);
825
826 #if defined(FSL_FEATURE_I3C_HAS_START_SCL_DELAY) && FSL_FEATURE_I3C_HAS_START_SCL_DELAY
827 base->MCONFIG_EXT = I3C_MCONFIG_EXT_I3C_CAS_DEL(config->startSclDelay) | I3C_MCONFIG_EXT_I3C_CASR_DEL(config->restartSclDelay);
828 #endif
829
830 I3C_MasterSetWatermarks(base, kI3C_TxTriggerUntilOneLessThanFull, kI3C_RxTriggerOnNotEmpty, true, true);
831
832 I3C_MasterSetBaudRate(base, &config->baudRate_Hz, sourceClock_Hz);
833
834 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
835 assert((config->slowClock_Hz >= 1000000U) || (config->slowClock_Hz == 0U));
836
837 uint8_t matchCount;
838 /* Set as (slowClk(MHz) - 1) to generate 1us clock cycle. Controller uses it to count 100us timeout. Target uses it as IBI request to drive SDA low.
839 Note: Use BAMATCH = 1 to generate 1us clock cycle if slow clock is 1MHz. The value of 0 would not give a correct match indication. */
840 if (config->slowClock_Hz != 0U)
841 {
842 matchCount = (uint8_t)(config->slowClock_Hz / 1000000UL) - 1U;
843 matchCount = (matchCount == 0U) ? 1U : matchCount;
844 }
845 else
846 {
847 /* BAMATCH has default value based on Soc default slow clock after reset, using this default value when slowClock_Hz is 0. */
848 matchCount = (uint8_t)((base->SCONFIG & I3C_SCONFIG_BAMATCH_MASK) >> I3C_SCONFIG_BAMATCH_SHIFT);
849 }
850 #endif
851
852 configValue = base->SCONFIG;
853
854 configValue &=
855 ~(I3C_SCONFIG_SADDR_MASK |
856 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
857 I3C_SCONFIG_BAMATCH_MASK |
858 #endif
859 I3C_SCONFIG_OFFLINE_MASK |
860 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND)
861 I3C_SCONFIG_IDRAND_MASK |
862 #endif
863 #if defined(FSL_FEATURE_I3C_HAS_HDROK) && FSL_FEATURE_I3C_HAS_HDROK
864 I3C_SCONFIG_HDROK_MASK |
865 #else
866 I3C_SCONFIG_DDROK_MASK |
867 #endif
868 I3C_SCONFIG_S0IGNORE_MASK | I3C_SCONFIG_MATCHSS_MASK | I3C_SCONFIG_NACK_MASK | I3C_SCONFIG_SLVENA_MASK);
869
870 configValue |= I3C_SCONFIG_SADDR(config->staticAddr) |
871 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
872 I3C_SCONFIG_BAMATCH(matchCount) |
873 #endif
874 I3C_SCONFIG_OFFLINE(config->offline) |
875 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND)
876 I3C_SCONFIG_IDRAND(config->enableRandomPart) |
877 #endif
878 #if defined(FSL_FEATURE_I3C_HAS_HDROK) && FSL_FEATURE_I3C_HAS_HDROK
879 I3C_SCONFIG_HDROK((0U != (config->hdrMode & (uint8_t)kI3C_HDRModeDDR)) ? 1U : 0U) |
880 #else
881 I3C_SCONFIG_DDROK((0U != (config->hdrMode & (uint8_t)kI3C_HDRModeDDR)) ? 1U : 0U) |
882 #endif
883 I3C_SCONFIG_S0IGNORE(config->ignoreS0S1Error) | I3C_SCONFIG_MATCHSS(config->matchSlaveStartStop) |
884 I3C_SCONFIG_NACK(config->nakAllRequest) | I3C_SCONFIG_SLVENA(config->enableSlave);
885
886 base->SVENDORID &= ~I3C_SVENDORID_VID_MASK;
887 base->SVENDORID |= I3C_SVENDORID_VID(config->vendorID);
888
889 #if defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND
890 base->SIDPARTNO = config->partNumber;
891 #else
892 if (!config->enableRandomPart)
893 {
894 base->SIDPARTNO = config->partNumber;
895 }
896 #endif
897
898 base->SIDEXT &= ~(I3C_SIDEXT_BCR_MASK | I3C_SIDEXT_DCR_MASK);
899 base->SIDEXT |= I3C_SIDEXT_BCR(config->bcr) | I3C_SIDEXT_DCR(config->dcr);
900
901 base->SMAXLIMITS &= ~(I3C_SMAXLIMITS_MAXRD_MASK | I3C_SMAXLIMITS_MAXWR_MASK);
902 base->SMAXLIMITS |= (I3C_SMAXLIMITS_MAXRD(config->maxReadLength) | I3C_SMAXLIMITS_MAXWR(config->maxWriteLength));
903
904 base->SCONFIG = configValue;
905 }
906
907 /*!
908 * brief Provides a default configuration for the I3C master peripheral.
909 *
910 * This function provides the following default configuration for the I3C master peripheral:
911 * code
912 * masterConfig->enableMaster = kI3C_MasterOn;
913 * masterConfig->disableTimeout = false;
914 * masterConfig->hKeep = kI3C_MasterHighKeeperNone;
915 * masterConfig->enableOpenDrainStop = true;
916 * masterConfig->enableOpenDrainHigh = true;
917 * masterConfig->baudRate_Hz = 100000U;
918 * masterConfig->busType = kI3C_TypeI2C;
919 * endcode
920 *
921 * After calling this function, you can override any settings in order to customize the configuration,
922 * prior to initializing the master driver with I3C_MasterInit().
923 *
924 * param[out] masterConfig User provided configuration structure for default values. Refer to #i3c_master_config_t.
925 */
I3C_MasterGetDefaultConfig(i3c_master_config_t * masterConfig)926 void I3C_MasterGetDefaultConfig(i3c_master_config_t *masterConfig)
927 {
928 (void)memset(masterConfig, 0, sizeof(*masterConfig));
929
930 masterConfig->enableMaster = kI3C_MasterOn;
931 masterConfig->disableTimeout = false;
932 masterConfig->hKeep = kI3C_MasterHighKeeperNone;
933 masterConfig->enableOpenDrainStop = true;
934 masterConfig->enableOpenDrainHigh = true;
935 masterConfig->baudRate_Hz.i2cBaud = 400000U;
936 masterConfig->baudRate_Hz.i3cPushPullBaud = 12500000U;
937 masterConfig->baudRate_Hz.i3cOpenDrainBaud = 2500000U;
938 }
939
940 /*!
941 * brief Initializes the I3C master peripheral.
942 *
943 * This function enables the peripheral clock and initializes the I3C master peripheral as described by the user
944 * provided configuration. A software reset is performed prior to configuration.
945 *
946 * param base The I3C peripheral base address.
947 * param masterConfig User provided peripheral configuration. Use I3C_MasterGetDefaultConfig() to get a set of
948 * defaults that you can override.
949 * param sourceClock_Hz Frequency in Hertz of the I3C functional clock. Used to calculate the baud rate divisors,
950 * filter widths, and timeout periods.
951 */
I3C_MasterInit(I3C_Type * base,const i3c_master_config_t * masterConfig,uint32_t sourceClock_Hz)952 void I3C_MasterInit(I3C_Type *base, const i3c_master_config_t *masterConfig, uint32_t sourceClock_Hz)
953 {
954 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) || \
955 !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
956 uint32_t instance = I3C_GetInstance(base);
957 #endif
958
959 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
960 /* Ungate the clock. */
961 CLOCK_EnableClock(kI3cClocks[instance]);
962 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
963
964 #if !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
965 /* Reset the I3C module */
966 RESET_PeripheralReset(kI3cResets[instance]);
967 #endif
968 base->MCONFIG = I3C_MCONFIG_MSTENA(masterConfig->enableMaster) | I3C_MCONFIG_DISTO(masterConfig->disableTimeout) |
969 I3C_MCONFIG_HKEEP(masterConfig->hKeep) | I3C_MCONFIG_ODSTOP(masterConfig->enableOpenDrainStop) |
970 I3C_MCONFIG_ODHPP(masterConfig->enableOpenDrainHigh);
971
972 #if defined(FSL_FEATURE_I3C_HAS_START_SCL_DELAY) && FSL_FEATURE_I3C_HAS_START_SCL_DELAY
973 base->MCONFIG_EXT = I3C_MCONFIG_EXT_I3C_CAS_DEL(masterConfig->startSclDelay) | I3C_MCONFIG_EXT_I3C_CASR_DEL(masterConfig->restartSclDelay);
974 #endif
975
976 I3C_MasterSetWatermarks(base, kI3C_TxTriggerUntilOneLessThanFull, kI3C_RxTriggerOnNotEmpty, true, true);
977
978 I3C_MasterSetBaudRate(base, &masterConfig->baudRate_Hz, sourceClock_Hz);
979
980 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
981 assert((masterConfig->slowClock_Hz >= 1000000U) || (masterConfig->slowClock_Hz == 0U));
982
983 uint32_t configValue;
984 uint8_t matchCount;
985
986 /* BAMATCH has default value based on Soc default slow clock after reset, using this default value when slowClock_Hz is 0. */
987 if (masterConfig->slowClock_Hz != 0U)
988 {
989 /* Set as (slowClk(MHz) - 1) to generate 1us clock cycle for 100us timeout. Note: Use BAMATCH = 1 to generate 1us clock cycle
990 if slow clock is 1MHz. The value of 0 would not give a correct match indication. */
991 matchCount = (uint8_t)(masterConfig->slowClock_Hz / 1000000UL) - 1U;
992 matchCount = (matchCount == 0U) ? 1U : matchCount;
993
994 configValue = base->SCONFIG & I3C_SCONFIG_BAMATCH_MASK;
995 configValue |= I3C_SCONFIG_BAMATCH(matchCount);
996 base->SCONFIG = configValue;
997 }
998 #endif
999 }
1000
1001 /*!
1002 * @brief Gets the I3C master state.
1003 *
1004 * @param base The I3C peripheral base address.
1005 * @return I3C master state.
1006 */
I3C_MasterGetState(I3C_Type * base)1007 i3c_master_state_t I3C_MasterGetState(I3C_Type *base)
1008 {
1009 uint32_t masterState = (base->MSTATUS & I3C_MSTATUS_STATE_MASK) >> I3C_MSTATUS_STATE_SHIFT;
1010 i3c_master_state_t returnCode;
1011
1012 switch (masterState)
1013 {
1014 case (uint32_t)kI3C_MasterStateIdle:
1015 returnCode = kI3C_MasterStateIdle;
1016 break;
1017 case (uint32_t)kI3C_MasterStateSlvReq:
1018 returnCode = kI3C_MasterStateSlvReq;
1019 break;
1020 case (uint32_t)kI3C_MasterStateMsgSdr:
1021 returnCode = kI3C_MasterStateMsgSdr;
1022 break;
1023 case (uint32_t)kI3C_MasterStateNormAct:
1024 returnCode = kI3C_MasterStateNormAct;
1025 break;
1026 case (uint32_t)kI3C_MasterStateDdr:
1027 returnCode = kI3C_MasterStateDdr;
1028 break;
1029 case (uint32_t)kI3C_MasterStateDaa:
1030 returnCode = kI3C_MasterStateDaa;
1031 break;
1032 case (uint32_t)kI3C_MasterStateIbiAck:
1033 returnCode = kI3C_MasterStateIbiAck;
1034 break;
1035 case (uint32_t)kI3C_MasterStateIbiRcv:
1036 returnCode = kI3C_MasterStateIbiRcv;
1037 break;
1038 default:
1039 returnCode = kI3C_MasterStateIdle;
1040 break;
1041 }
1042
1043 return returnCode;
1044 }
1045
1046 /*!
1047 * brief Deinitializes the I3C master peripheral.
1048 *
1049 * This function disables the I3C master peripheral and gates the clock. It also performs a software
1050 * reset to restore the peripheral to reset conditions.
1051 *
1052 * param base The I3C peripheral base address.
1053 */
I3C_MasterDeinit(I3C_Type * base)1054 void I3C_MasterDeinit(I3C_Type *base)
1055 {
1056 uint32_t idx = I3C_GetInstance(base);
1057
1058 #if !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
1059 /* Reset the I3C module */
1060 RESET_PeripheralReset(kI3cResets[idx]);
1061 #endif
1062
1063 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
1064 /* Gate clock. */
1065 CLOCK_DisableClock(kI3cClocks[idx]);
1066 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
1067
1068 /* Reset handle pointer. */
1069 s_i3cMasterHandle[idx] = NULL;
1070 }
1071
I3C_CalcErrorRatio(uint32_t curFreq,uint32_t desiredFreq)1072 static uint32_t I3C_CalcErrorRatio(uint32_t curFreq, uint32_t desiredFreq)
1073 {
1074 if (curFreq > desiredFreq)
1075 {
1076 return (curFreq - desiredFreq) * 100UL / desiredFreq;
1077 }
1078 else
1079 {
1080 return (desiredFreq - curFreq) * 100UL / desiredFreq;
1081 }
1082 }
1083
1084 /*!
1085 * brief Sets the I3C bus frequency for master transactions.
1086 *
1087 * The I3C master is automatically disabled and re-enabled as necessary to configure the baud
1088 * rate. Do not call this function during a transfer, or the transfer is aborted.
1089 *
1090 * param base The I3C peripheral base address.
1091 * param baudRate_Hz Pointer to structure of requested bus frequency in Hertz.
1092 * param sourceClock_Hz I3C functional clock frequency in Hertz.
1093 */
I3C_MasterSetBaudRate(I3C_Type * base,const i3c_baudrate_hz_t * baudRate_Hz,uint32_t sourceClock_Hz)1094 void I3C_MasterSetBaudRate(I3C_Type *base, const i3c_baudrate_hz_t *baudRate_Hz, uint32_t sourceClock_Hz)
1095 {
1096 uint32_t div, freq;
1097 uint32_t divEven, divOdd;
1098 uint32_t ppBaud, odBaud, i2cBaud;
1099 uint32_t errRate0, errRate1;
1100 uint32_t i3cPPBaud_HZ = baudRate_Hz->i3cPushPullBaud;
1101 uint32_t i3cPPBaudMax_HZ = i3cPPBaud_HZ / 10U + i3cPPBaud_HZ; /* max is 1.1*i3cPPBaud_HZ */
1102 uint32_t i3cODBaud_HZ = baudRate_Hz->i3cOpenDrainBaud;
1103 uint32_t i3cODBaudMax_HZ = i3cODBaud_HZ / 10U + i3cODBaud_HZ; /* max is 1.1*i3cODBaud_HZ */
1104 uint32_t i2cBaud_HZ = baudRate_Hz->i2cBaud;
1105 uint32_t i3cPPLow_Ns, i3cOdLow_Ns;
1106 bool isODHigh = (0U != (base->MCONFIG & I3C_MCONFIG_ODHPP_MASK)) ? true : false;
1107
1108 /* Find out the div to generate target freq */
1109 freq = sourceClock_Hz / 2UL;
1110 /* ppFreq = FCLK / 2 / (PPBAUD + 1)), 0 <= PPBAUD <= 15 */
1111 /* We need PPBAUD generate 12.5MHz or so. */
1112 div = freq / i3cPPBaud_HZ;
1113 div = (div == 0UL) ? 1UL : div;
1114 if (freq / div > i3cPPBaudMax_HZ)
1115 {
1116 div++;
1117 }
1118 assert(div <= FSL_I3C_PPBAUD_DIV_MAX);
1119 ppBaud = div - 1UL;
1120 freq /= div;
1121
1122 i3cPPLow_Ns = (uint32_t)(NSEC_PER_SEC / (2UL * freq));
1123
1124 /* We need ODBAUD generate 2.5MHz or so. */
1125 if (isODHigh)
1126 {
1127 /* odFreq = (2*freq) / (ODBAUD + 2), 1 <= ODBAUD <= 255 */
1128 div = (2UL * freq) / i3cODBaud_HZ;
1129 div = div < 2UL ? 2UL : div;
1130 if ((2UL * freq / div) > i3cODBaudMax_HZ)
1131 {
1132 div++;
1133 }
1134 odBaud = div - 2UL;
1135 freq = (2UL * freq) / div;
1136 }
1137 else
1138 {
1139 /* odFreq = ppFreq / (ODBAUD + 1), 1 <= ODBAUD <= 255 */
1140 div = freq / i3cODBaud_HZ;
1141 div = div < 1UL ? 1UL : div;
1142 if (freq / div > i3cODBaudMax_HZ)
1143 {
1144 div++;
1145 }
1146 odBaud = div - 1UL;
1147 freq /= div;
1148 }
1149
1150 i3cOdLow_Ns = (odBaud + 1UL) * i3cPPLow_Ns;
1151
1152 /* i2cFreq = odFreq / (I2CBAUD + 1), 0 <= I2CBAUD <= 7 (I2CBAUD need << 1 in register) */
1153 /* i2cFreq = NSEC_PER_SEC / (I2CBAUD + 1)*i3cOdLow_Ns */
1154 divEven = (sourceClock_Hz / i2cBaud_HZ) / (2UL * (ppBaud + 1UL) * (odBaud + 1UL));
1155 divEven = divEven == 0UL ? 1UL : divEven;
1156 errRate0 = I3C_CalcErrorRatio((uint32_t)(NSEC_PER_SEC / (2UL * divEven * i3cOdLow_Ns)), i2cBaud_HZ);
1157
1158 divOdd = ((sourceClock_Hz / i2cBaud_HZ) / ((ppBaud + 1UL) * (odBaud + 1UL) - 1UL)) / 2UL;
1159 divOdd = divOdd == 0UL ? 1UL : divOdd;
1160 errRate1 = I3C_CalcErrorRatio((uint32_t)(NSEC_PER_SEC / ((2UL * divOdd + 1UL) * i3cOdLow_Ns)), i2cBaud_HZ);
1161
1162 if (errRate0 < FSL_I3C_ERROR_RATE_MAX || errRate1 < FSL_I3C_ERROR_RATE_MAX)
1163 {
1164 /* Use this div */
1165 i2cBaud = errRate0 < errRate1 ? (divEven - 1UL) * 2UL : (divOdd - 1UL) * 2UL + 1UL;
1166 }
1167 else
1168 {
1169 /* Use div + 1, unless current freq is already lower than desired. */
1170 i2cBaud = freq / divEven < i2cBaud_HZ ? (divEven - 1UL) * 2UL : divEven * 2UL;
1171 }
1172
1173 base->MCONFIG = (base->MCONFIG & ~(I3C_MCONFIG_PPBAUD_MASK | I3C_MCONFIG_PPLOW_MASK | I3C_MCONFIG_ODBAUD_MASK |
1174 I3C_MCONFIG_I2CBAUD_MASK)) |
1175 I3C_MCONFIG_PPBAUD(ppBaud) | I3C_MCONFIG_ODBAUD(odBaud) | I3C_MCONFIG_I2CBAUD(i2cBaud);
1176 }
1177
1178 /*!
1179 * brief Sends a START signal and slave address on the I2C/I3C bus, receive size is also specified
1180 * in the call.
1181 * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure
1182 * that another master is not occupying the bus. Then a START signal is transmitted, followed by the
1183 * 7-bit address specified in the a address parameter. Note that this function does not actually wait
1184 * until the START and address are successfully sent on the bus before returning.
1185 *
1186 * param base The I3C peripheral base address.
1187 * param type The bus type to use in this transaction.
1188 * param address 7-bit slave device address, in bits [6:0].
1189 * param dir Master transfer direction, either #kI3C_Read or #kI3C_Write. This parameter is used to set
1190 * the R/w bit (bit 0) in the transmitted slave address.
1191 * param rxSize Read terminate size for the followed read transfer, limit to 255 bytes.
1192 * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO.
1193 * retval #kStatus_I3C_Busy Another master is currently utilizing the bus.
1194 */
I3C_MasterStartWithRxSize(I3C_Type * base,i3c_bus_type_t type,uint8_t address,i3c_direction_t dir,uint8_t rxSize)1195 status_t I3C_MasterStartWithRxSize(
1196 I3C_Type *base, i3c_bus_type_t type, uint8_t address, i3c_direction_t dir, uint8_t rxSize)
1197 {
1198 i3c_master_state_t masterState = I3C_MasterGetState(base);
1199 bool checkDdrState = (type == kI3C_TypeI3CDdr) ? (masterState != kI3C_MasterStateDdr) : true;
1200 if ((masterState != kI3C_MasterStateIdle) && (masterState != kI3C_MasterStateNormAct) && checkDdrState)
1201 {
1202 return kStatus_I3C_Busy;
1203 }
1204
1205 return I3C_MasterRepeatedStartWithRxSize(base, type, address, dir, rxSize);
1206 }
1207
1208 /*!
1209 * brief Sends a START signal and slave address on the I2C/I3C bus.
1210 *
1211 * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure
1212 * that another master is not occupying the bus. Then a START signal is transmitted, followed by the
1213 * 7-bit address specified in the a address parameter. Note that this function does not actually wait
1214 * until the START and address are successfully sent on the bus before returning.
1215 *
1216 * param base The I3C peripheral base address.
1217 * param type The bus type to use in this transaction.
1218 * param address 7-bit slave device address, in bits [6:0].
1219 * param dir Master transfer direction, either #kI3C_Read or #kI3C_Write. This parameter is used to set
1220 * the R/w bit (bit 0) in the transmitted slave address.
1221 * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO.
1222 * retval #kStatus_I3C_Busy Another master is currently utilizing the bus.
1223 */
I3C_MasterStart(I3C_Type * base,i3c_bus_type_t type,uint8_t address,i3c_direction_t dir)1224 status_t I3C_MasterStart(I3C_Type *base, i3c_bus_type_t type, uint8_t address, i3c_direction_t dir)
1225 {
1226 i3c_master_state_t masterState = I3C_MasterGetState(base);
1227 bool checkDdrState = (type == kI3C_TypeI3CDdr) ? (masterState != kI3C_MasterStateDdr) : true;
1228 if ((masterState != kI3C_MasterStateIdle) && (masterState != kI3C_MasterStateNormAct) && checkDdrState)
1229 {
1230 return kStatus_I3C_Busy;
1231 }
1232
1233 return I3C_MasterStartWithRxSize(base, type, address, dir, 0);
1234 }
1235
1236 /*!
1237 * brief Sends a repeated START signal and slave address on the I2C/I3C bus, receive size is also specified
1238 * in the call.
1239 *
1240 * This function is used to send a Repeated START signal when a transfer is already in progress. Like
1241 * I3C_MasterStart(), it also sends the specified 7-bit address. Call this API also configures the read
1242 * terminate size for the following read transfer. For example, set the rxSize = 2, the following read transfer
1243 * will be terminated after two bytes of data received. Write transfer will not be affected by the rxSize
1244 * configuration.
1245 *
1246 * note This function exists primarily to maintain compatible APIs between I3C and I2C drivers,
1247 * as well as to better document the intent of code that uses these APIs.
1248 *
1249 * param base The I3C peripheral base address.
1250 * param type The bus type to use in this transaction.
1251 * param address 7-bit slave device address, in bits [6:0].
1252 * param dir Master transfer direction, either #kI3C_Read or #kI3C_Write. This parameter is used to set
1253 * the R/w bit (bit 0) in the transmitted slave address.
1254 * param rxSize Read terminate size for the followed read transfer, limit to 255 bytes.
1255 * retval #kStatus_Success Repeated START signal and address were successfully enqueued in the transmit FIFO.
1256 */
I3C_MasterRepeatedStartWithRxSize(I3C_Type * base,i3c_bus_type_t type,uint8_t address,i3c_direction_t dir,uint8_t rxSize)1257 status_t I3C_MasterRepeatedStartWithRxSize(
1258 I3C_Type *base, i3c_bus_type_t type, uint8_t address, i3c_direction_t dir, uint8_t rxSize)
1259 {
1260 uint32_t mctrlVal;
1261
1262 /* Clear all flags. */
1263 I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
1264
1265 #if defined(FSL_FEATURE_I3C_HAS_ERRATA_051617) && (FSL_FEATURE_I3C_HAS_ERRATA_051617)
1266 /* ERRATA051617: When used as I2C controller generates repeated START randomly before the STOP under PVT condition.
1267 This issue is caused by a glitch at the output of an internal clock MUX. The glitch when generates acts as a clock
1268 pulse which causes the SDA line to fall early during SCL high period and creates the unintended Repeated START before
1269 actual STOP. */
1270 if (type == kI3C_TypeI2C)
1271 {
1272 base->MCONFIG |= I3C_MCONFIG_SKEW(1);
1273 }
1274 else
1275 {
1276 base->MCONFIG &= ~I3C_MCONFIG_SKEW_MASK;
1277 }
1278 #endif
1279
1280 /* Issue start command. */
1281 mctrlVal = base->MCTRL;
1282 mctrlVal &= ~(I3C_MCTRL_TYPE_MASK | I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_ADDR_MASK |
1283 I3C_MCTRL_RDTERM_MASK);
1284 mctrlVal |= I3C_MCTRL_TYPE(type) | I3C_MCTRL_REQUEST(kI3C_RequestEmitStartAddr) | I3C_MCTRL_DIR(dir) |
1285 I3C_MCTRL_ADDR(address) | I3C_MCTRL_RDTERM(rxSize);
1286
1287 base->MCTRL = mctrlVal;
1288
1289 return kStatus_Success;
1290 }
1291 /*!
1292 * brief Sends a STOP signal on the I2C/I3C bus.
1293 *
1294 * This function does not return until the STOP signal is seen on the bus, or an error occurs.
1295 *
1296 * param base The I3C peripheral base address.
1297 * retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated.
1298 * retval #kStatus_I3C_Busy Another master is currently utilizing the bus.
1299 * retval #kStatus_I3C_Nak The slave device sent a NAK in response to a byte.
1300 * retval #kStatus_I3C_FifoError FIFO under run or overrun.
1301 * retval #kStatus_I3C_ArbitrationLost Arbitration lost error.
1302 * retval #kStatus_I3C_PinLowTimeout SCL or SDA were held low longer than the timeout.
1303 */
I3C_MasterStop(I3C_Type * base)1304 status_t I3C_MasterStop(I3C_Type *base)
1305 {
1306 return I3C_MasterEmitStop(base, true);
1307 }
1308
1309 /*!
1310 * brief I3C master emit request.
1311 *
1312 * param base The I3C peripheral base address.
1313 * param masterReq I3C master request of type #i3c_bus_request_t
1314 */
I3C_MasterEmitRequest(I3C_Type * base,i3c_bus_request_t masterReq)1315 void I3C_MasterEmitRequest(I3C_Type *base, i3c_bus_request_t masterReq)
1316 {
1317 uint32_t mctrlReg = base->MCTRL;
1318
1319 mctrlReg &= ~I3C_MCTRL_REQUEST_MASK;
1320
1321 if (masterReq == kI3C_RequestProcessDAA)
1322 {
1323 mctrlReg &= ~I3C_MCTRL_TYPE_MASK;
1324 }
1325
1326 mctrlReg |= I3C_MCTRL_REQUEST(masterReq);
1327
1328 base->MCTRL = mctrlReg;
1329 }
1330
1331 /*!
1332 * brief I3C master register IBI rule.
1333 *
1334 * param base The I3C peripheral base address.
1335 * param ibiRule Pointer to ibi rule description of type #i3c_register_ibi_addr_t
1336 */
I3C_MasterRegisterIBI(I3C_Type * base,i3c_register_ibi_addr_t * ibiRule)1337 void I3C_MasterRegisterIBI(I3C_Type *base, i3c_register_ibi_addr_t *ibiRule)
1338 {
1339 assert(NULL != ibiRule);
1340 uint32_t ruleValue = I3C_MIBIRULES_MSB0_MASK;
1341
1342 for (uint32_t count = 0; count < ARRAY_SIZE(ibiRule->address); count++)
1343 {
1344 ruleValue |= ((uint32_t)ibiRule->address[count]) << (count * I3C_MIBIRULES_ADDR1_SHIFT);
1345 }
1346
1347 ruleValue &= ~I3C_MIBIRULES_NOBYTE_MASK;
1348
1349 if (!ibiRule->ibiHasPayload)
1350 {
1351 ruleValue |= I3C_MIBIRULES_NOBYTE_MASK;
1352 }
1353
1354 base->MIBIRULES = ruleValue;
1355 }
1356
1357 /*!
1358 * brief I3C master get IBI rule.
1359 *
1360 * param base The I3C peripheral base address.
1361 * param ibiRule Pointer to store the read out ibi rule description.
1362 */
I3C_MasterGetIBIRules(I3C_Type * base,i3c_register_ibi_addr_t * ibiRule)1363 void I3C_MasterGetIBIRules(I3C_Type *base, i3c_register_ibi_addr_t *ibiRule)
1364 {
1365 assert(NULL != ibiRule);
1366
1367 uint32_t ruleValue = base->MIBIRULES;
1368
1369 for (uint32_t count = 0; count < ARRAY_SIZE(ibiRule->address); count++)
1370 {
1371 ibiRule->address[count] =
1372 (uint8_t)(ruleValue >> (count * I3C_MIBIRULES_ADDR1_SHIFT)) & I3C_MIBIRULES_ADDR0_MASK;
1373 }
1374
1375 ibiRule->ibiHasPayload = (0U == (ruleValue & I3C_MIBIRULES_NOBYTE_MASK));
1376 }
1377
1378 /*!
1379 * brief Performs a polling receive transfer on the I2C/I3C bus.
1380 *
1381 * param base The I3C peripheral base address.
1382 * param rxBuff The pointer to the data to be transferred.
1383 * param rxSize The length in bytes of the data to be transferred.
1384 * param flags Bit mask of options for the transfer. See enumeration #_i3c_master_transfer_flags for available options.
1385 * retval #kStatus_Success Data was received successfully.
1386 * retval #kStatus_I3C_Busy Another master is currently utilizing the bus.
1387 * retval #kStatus_I3C_Nak The slave device sent a NAK in response to a byte.
1388 * retval #kStatus_I3C_FifoError FIFO under run or overrun.
1389 * retval #kStatus_I3C_ArbitrationLost Arbitration lost error.
1390 * retval #kStatus_I3C_PinLowTimeout SCL or SDA were held low longer than the timeout.
1391 */
I3C_MasterReceive(I3C_Type * base,void * rxBuff,size_t rxSize,uint32_t flags)1392 status_t I3C_MasterReceive(I3C_Type *base, void *rxBuff, size_t rxSize, uint32_t flags)
1393 {
1394 status_t result = kStatus_Success;
1395 bool isRxAutoTerm = ((flags & (uint32_t)kI3C_TransferRxAutoTermFlag) != 0UL);
1396 bool completed = false;
1397 uint32_t status;
1398 uint8_t *buf;
1399
1400 assert(NULL != rxBuff);
1401
1402 /* Handle empty read. */
1403 if (rxSize == 0UL)
1404 {
1405 return kStatus_Success;
1406 }
1407
1408 #if I3C_RETRY_TIMES
1409 uint32_t waitTimes = I3C_RETRY_TIMES;
1410 #endif
1411
1412 /* Receive data */
1413 buf = (uint8_t *)rxBuff;
1414
1415 while ((rxSize != 0UL) || !completed)
1416 {
1417 #if I3C_RETRY_TIMES
1418 if (--waitTimes == 0)
1419 {
1420 return kStatus_I3C_Timeout;
1421 }
1422 #endif
1423 /* Check for errors. */
1424 result = I3C_MasterCheckAndClearError(base, I3C_MasterGetErrorStatusFlags(base));
1425 if (kStatus_Success != result)
1426 {
1427 return result;
1428 }
1429
1430 /* Check complete flag */
1431 if (!completed)
1432 {
1433 status = I3C_MasterGetStatusFlags(base) & (uint32_t)kI3C_MasterCompleteFlag;
1434 if (0UL != status)
1435 {
1436 completed = true;
1437 /* Clear complete flag */
1438 I3C_MasterClearStatusFlags(base, (uint32_t)kI3C_MasterCompleteFlag);
1439 /* Send stop if needed */
1440 if ((flags & (uint32_t)kI3C_TransferNoStopFlag) == 0UL)
1441 {
1442 if (I3C_MasterGetState(base) == kI3C_MasterStateDdr)
1443 {
1444 I3C_MasterEmitRequest(base, kI3C_RequestForceExit);
1445 result = I3C_MasterWaitForCtrlDone(base, false);
1446 }
1447 else
1448 {
1449 result = I3C_MasterEmitStop(base, false);
1450 }
1451 if (kStatus_Success != result)
1452 {
1453 return result;
1454 }
1455 }
1456 }
1457 }
1458
1459 /* Check RX data */
1460 if ((0UL != rxSize) && (0UL != (base->MDATACTRL & I3C_MDATACTRL_RXCOUNT_MASK)))
1461 {
1462 *buf++ = (uint8_t)(base->MRDATAB & I3C_MRDATAB_VALUE_MASK);
1463 rxSize--;
1464 if ((flags & (uint32_t)kI3C_TransferDisableRxTermFlag) == 0UL)
1465 {
1466 if ((!isRxAutoTerm) && (rxSize == 1U))
1467 {
1468 base->MCTRL |= I3C_MCTRL_RDTERM(1U);
1469 }
1470 }
1471 }
1472 }
1473
1474 /* Wait idle if stop is sent. */
1475 if ((flags & (uint32_t)kI3C_TransferNoStopFlag) == 0UL)
1476 {
1477 #if I3C_RETRY_TIMES
1478 while ((I3C_MasterGetState(base) != kI3C_MasterStateIdle) && --waitTimes)
1479 #else
1480 while (I3C_MasterGetState(base) != kI3C_MasterStateIdle)
1481 #endif
1482 {
1483 }
1484 }
1485 return result;
1486 }
1487
1488 /*!
1489 * brief Performs a polling send transfer on the I2C/I3C bus.
1490 *
1491 * Sends up to a txSize number of bytes to the previously addressed slave device. The slave may
1492 * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this
1493 * function returns #kStatus_I3C_Nak.
1494 *
1495 * param base The I3C peripheral base address.
1496 * param txBuff The pointer to the data to be transferred.
1497 * param txSize The length in bytes of the data to be transferred.
1498 * param flags Bit mask of options for the transfer. See enumeration #_i3c_master_transfer_flags for available options.
1499 * retval #kStatus_Success Data was sent successfully.
1500 * retval #kStatus_I3C_Busy Another master is currently utilizing the bus.
1501 * retval #kStatus_I3C_Nak The slave device sent a NAK in response to a byte.
1502 * retval #kStatus_I3C_FifoError FIFO under run or over run.
1503 * retval #kStatus_I3C_ArbitrationLost Arbitration lost error.
1504 * retval #kStatus_I3C_PinLowTimeout SCL or SDA were held low longer than the timeout.
1505 */
I3C_MasterSend(I3C_Type * base,const void * txBuff,size_t txSize,uint32_t flags)1506 status_t I3C_MasterSend(I3C_Type *base, const void *txBuff, size_t txSize, uint32_t flags)
1507 {
1508 i3c_puint8_to_u32_t buf;
1509 buf.cpuint8 = (const uint8_t *)((const void *)txBuff);
1510 status_t result = kStatus_Success;
1511 bool enableWord = ((flags & (uint32_t)kI3C_TransferWordsFlag) == (uint32_t)kI3C_TransferWordsFlag) ? true : false;
1512 uint8_t byteCounts = enableWord ? 2U : 1U;
1513
1514 assert(NULL != txBuff);
1515 if (enableWord)
1516 {
1517 assert(txSize % 2UL == 0UL);
1518 }
1519
1520 /* Send data buffer */
1521 while (0UL != txSize)
1522 {
1523 /* Wait until there is room in the fifo. This also checks for errors. */
1524 result = I3C_MasterWaitForTxReady(base, byteCounts);
1525 if (kStatus_Success != result)
1526 {
1527 return result;
1528 }
1529
1530 /* Write byte into I3C master data register. */
1531 if (txSize > byteCounts)
1532 {
1533 if (enableWord)
1534 {
1535 base->MWDATAH = (uint32_t)buf.cpuint8[1] << 8UL | (uint32_t)buf.cpuint8[0];
1536 }
1537 else
1538 {
1539 base->MWDATAB = *buf.cpuint8;
1540 }
1541 }
1542 else
1543 {
1544 if (enableWord)
1545 {
1546 base->MWDATAHE = (uint32_t)buf.cpuint8[1] << 8UL | (uint32_t)buf.cpuint8[0];
1547 }
1548 else
1549 {
1550 base->MWDATABE = *buf.cpuint8;
1551 }
1552 }
1553
1554 buf.u32 = buf.u32 + byteCounts;
1555 txSize = txSize - byteCounts;
1556 }
1557
1558 result = I3C_MasterWaitForComplete(base, false);
1559 if ((result == kStatus_Success) && ((flags & (uint32_t)kI3C_TransferNoStopFlag) == 0UL))
1560 {
1561 if (I3C_MasterGetState(base) == kI3C_MasterStateDdr)
1562 {
1563 I3C_MasterEmitRequest(base, kI3C_RequestForceExit);
1564 result = I3C_MasterWaitForCtrlDone(base, false);
1565 }
1566 else
1567 {
1568 result = I3C_MasterEmitStop(base, true);
1569 }
1570 }
1571
1572 return result;
1573 }
1574
1575 /*!
1576 * brief Performs a DAA in the i3c bus with specified temporary baud rate.
1577 *
1578 * param base The I3C peripheral base address.
1579 * param addressList The pointer for address list which is used to do DAA.
1580 * param count The address count in the address list.
1581 * param daaBaudRate The temporary baud rate in DAA process, NULL for using initial setting.
1582 * The initial setting is set back between the completion of the DAA and the return of this function.
1583 * retval #kStatus_Success The transaction was started successfully.
1584 * retval #kStatus_I3C_Busy Either another master is currently utilizing the bus, or a non-blocking
1585 * transaction is already in progress.
1586 * retval #kStatus_I3C_SlaveCountExceed The I3C slave count has exceed the definition in I3C_MAX_DEVCNT.
1587 */
I3C_MasterProcessDAASpecifiedBaudrate(I3C_Type * base,uint8_t * addressList,uint32_t count,i3c_master_daa_baudrate_t * daaBaudRate)1588 status_t I3C_MasterProcessDAASpecifiedBaudrate(I3C_Type *base,
1589 uint8_t *addressList,
1590 uint32_t count,
1591 i3c_master_daa_baudrate_t *daaBaudRate)
1592 {
1593 assert(addressList != NULL);
1594 assert(count != 0U);
1595
1596 status_t result = kStatus_Success;
1597 uint8_t rxBuffer[8] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU};
1598 uint32_t masterConfig = 0;
1599 uint32_t devCount = 0;
1600 uint8_t rxSize = 0;
1601 bool mctrlDone = false;
1602 i3c_baudrate_hz_t baudRate_Hz;
1603 uint32_t errStatus;
1604 uint32_t status;
1605 size_t rxCount;
1606
1607 /* Return an error if the bus is already in use not by us. */
1608 result = I3C_CheckForBusyBus(base);
1609 if (kStatus_Success != result)
1610 {
1611 return result;
1612 }
1613
1614 /* Clear all flags. */
1615 I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
1616 I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
1617
1618 /* Disable I3C IRQ sources while we configure stuff. */
1619 uint32_t enabledInts = I3C_MasterGetEnabledInterrupts(base);
1620 I3C_MasterDisableInterrupts(base, enabledInts);
1621
1622 /* Temporarily adjust baud rate before DAA. */
1623 if (daaBaudRate != NULL)
1624 {
1625 masterConfig = base->MCONFIG;
1626 /* Set non-zero value for I2C baud rate which is useless here. */
1627 baudRate_Hz.i2cBaud = 1;
1628 baudRate_Hz.i3cOpenDrainBaud = daaBaudRate->i3cOpenDrainBaud;
1629 baudRate_Hz.i3cPushPullBaud = daaBaudRate->i3cPushPullBaud;
1630 I3C_MasterSetBaudRate(base, &baudRate_Hz, daaBaudRate->sourceClock_Hz);
1631 }
1632
1633 /* Emit process DAA */
1634 I3C_MasterEmitRequest(base, kI3C_RequestProcessDAA);
1635
1636 do
1637 {
1638 status = I3C_MasterGetStatusFlags(base);
1639
1640 /* Check for error flags. */
1641 errStatus = I3C_MasterGetErrorStatusFlags(base);
1642 result = I3C_MasterCheckAndClearError(base, errStatus);
1643 if (kStatus_Success != result)
1644 {
1645 break;
1646 }
1647
1648 if ((!mctrlDone) || (rxSize < 8U))
1649 {
1650 I3C_MasterGetFifoCounts(base, &rxCount, NULL);
1651
1652 if (rxCount != 0U)
1653 {
1654 rxBuffer[rxSize++] = (uint8_t)(base->MRDATAB & I3C_MRDATAB_VALUE_MASK);
1655 }
1656
1657 if ((status & (uint32_t)kI3C_MasterControlDoneFlag) != 0U)
1658 {
1659 I3C_MasterClearStatusFlags(base, (uint32_t)kI3C_MasterControlDoneFlag);
1660 mctrlDone = true;
1661 }
1662 }
1663 else if ((I3C_MasterGetState(base) == kI3C_MasterStateDaa) &&
1664 (0UL != (I3C_MasterGetStatusFlags(base) & (uint32_t)kI3C_MasterBetweenFlag)))
1665 {
1666 if (((devCount + 1UL) > count) || ((devCount + 1UL) > I3C_MAX_DEVCNT))
1667 {
1668 result = kStatus_I3C_SlaveCountExceed;
1669 break;
1670 }
1671
1672 /* Assign the dynamic address from address list. */
1673 devList[devCount].dynamicAddr = *addressList++;
1674 base->MWDATAB = devList[devCount].dynamicAddr;
1675
1676 /* Emit process DAA again. */
1677 I3C_MasterEmitRequest(base, kI3C_RequestProcessDAA);
1678
1679 devList[devCount].vendorID = (((uint16_t)rxBuffer[0] << 8U | (uint16_t)rxBuffer[1]) & 0xFFFEU) >> 1U;
1680 devList[devCount].partNumber = ((uint32_t)rxBuffer[2] << 24U | (uint32_t)rxBuffer[3] << 16U |
1681 (uint32_t)rxBuffer[4] << 8U | (uint32_t)rxBuffer[5]);
1682 devList[devCount].bcr = rxBuffer[6];
1683 devList[devCount].dcr = rxBuffer[7];
1684 devCount++;
1685 usedDevCount++;
1686
1687 /* Ready to handle next device. */
1688 mctrlDone = false;
1689 rxSize = 0;
1690 }
1691 else
1692 {
1693 /* Intentional empty */
1694 }
1695 } while ((status & (uint32_t)kI3C_MasterCompleteFlag) != (uint32_t)kI3C_MasterCompleteFlag);
1696
1697 /* Master stops DAA if slave device number exceeds the prepared address number. */
1698 if (result == kStatus_I3C_SlaveCountExceed)
1699 {
1700 /* Send the STOP signal */
1701 base->MCTRL = (base->MCTRL & ~(I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_RDTERM_MASK)) |
1702 I3C_MCTRL_REQUEST(kI3C_RequestEmitStop);
1703 }
1704
1705 /* Set back initial baud rate after DAA is over. */
1706 if (daaBaudRate != NULL)
1707 {
1708 base->MCONFIG = masterConfig;
1709 }
1710
1711 /* Clear all flags. */
1712 I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
1713 I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
1714
1715 /* Enable I3C IRQ sources while we configure stuff. */
1716 I3C_MasterEnableInterrupts(base, enabledInts);
1717
1718 return result;
1719 }
1720
1721 /*!
1722 * brief Get device information list after DAA process is done.
1723 *
1724 * param base The I3C peripheral base address.
1725 * param[out] count The pointer to store the available device count.
1726 * return Pointer to the i3c_device_info_t array.
1727 */
I3C_MasterGetDeviceListAfterDAA(I3C_Type * base,uint8_t * count)1728 i3c_device_info_t *I3C_MasterGetDeviceListAfterDAA(I3C_Type *base, uint8_t *count)
1729 {
1730 assert(NULL != count);
1731
1732 *count = usedDevCount;
1733
1734 return devList;
1735 }
1736
1737 /*!
1738 * @brief introduce function I3C_MasterClearFlagsAndEnableIRQ.
1739 *
1740 * This function was used of Clear all flags and Enable I3C IRQ sources for @param *base.
1741 *
1742 * @param base The I3C peripheral base address.
1743 */
I3C_MasterClearFlagsAndEnableIRQ(I3C_Type * base)1744 static void I3C_MasterClearFlagsAndEnableIRQ(I3C_Type *base)
1745 {
1746 /* Clear all flags. */
1747 I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
1748 /* Enable I3C IRQ sources. */
1749 I3C_MasterEnableInterrupts(base, (uint32_t)kMasterIrqFlags);
1750 }
1751
1752 /*!
1753 * @brief introduce function I3C_MasterTransferNoStartFlag.
1754 *
1755 * This function was used of Check if device request wins arbitration.
1756 *
1757 * @param base The I3C peripheral base address.
1758 * @param transfer Pointer to the transfer structure.
1759 * @retval #true if the device wins arbitration.
1760 * @retval #false if the device not wins arbitration.
1761 */
I3C_MasterTransferNoStartFlag(I3C_Type * base,i3c_master_transfer_t * transfer)1762 static bool I3C_MasterTransferNoStartFlag(I3C_Type *base, i3c_master_transfer_t *transfer)
1763 {
1764 /* Wait tx fifo empty. */
1765 size_t txCount = 0xFFUL;
1766
1767 while (txCount != 0U)
1768 {
1769 I3C_MasterGetFifoCounts(base, NULL, &txCount);
1770 }
1771
1772 /* Check if device request wins arbitration. */
1773 if (0UL != (I3C_MasterGetStatusFlags(base) & (uint32_t)kI3C_MasterArbitrationWonFlag))
1774 {
1775 I3C_MasterClearFlagsAndEnableIRQ(base);
1776 return true;
1777 }
1778 return false;
1779 }
1780
1781 /*!
1782 * brief Performs a master polling transfer on the I2C/I3C bus.
1783 *
1784 * note The API does not return until the transfer succeeds or fails due
1785 * to error happens during transfer.
1786 *
1787 * param base The I3C peripheral base address.
1788 * param transfer Pointer to the transfer structure.
1789 * retval #kStatus_Success Data was received successfully.
1790 * retval #kStatus_I3C_Busy Another master is currently utilizing the bus.
1791 * retval #kStatus_I3C_Nak The slave device sent a NAK in response to a byte.
1792 * retval #kStatus_I3C_FifoError FIFO under run or overrun.
1793 * retval #kStatus_I3C_ArbitrationLost Arbitration lost error.
1794 * retval #kStatus_I3C_PinLowTimeout SCL or SDA were held low longer than the timeout.
1795 */
I3C_MasterTransferBlocking(I3C_Type * base,i3c_master_transfer_t * transfer)1796 status_t I3C_MasterTransferBlocking(I3C_Type *base, i3c_master_transfer_t *transfer)
1797 {
1798 assert(NULL != transfer);
1799 assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
1800
1801 status_t result = kStatus_Success;
1802 i3c_direction_t direction = transfer->direction;
1803 i3c_master_state_t masterState = I3C_MasterGetState(base);
1804 bool checkDdrState = false;
1805 i3c_rx_term_ops_t rxTermOps;
1806
1807 /* Return an error if the bus is already in use not by us. */
1808 checkDdrState = (transfer->busType == kI3C_TypeI3CDdr) ? (masterState != kI3C_MasterStateDdr) : true;
1809
1810 if ((masterState != kI3C_MasterStateIdle) && (masterState != kI3C_MasterStateNormAct) && checkDdrState)
1811 {
1812 return kStatus_I3C_Busy;
1813 }
1814
1815 /* Clear all flags. */
1816 I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
1817 /* Reset fifos. These flags clear automatically. */
1818 base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
1819
1820 /* Disable I3C IRQ sources while we configure stuff. */
1821 I3C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
1822
1823 if (transfer->busType != kI3C_TypeI3CDdr)
1824 {
1825 direction = (0UL != transfer->subaddressSize) ? kI3C_Write : transfer->direction;
1826 }
1827
1828 /* True: Set Rx termination bytes at start point, False: Set Rx termination one bytes in advance. */
1829 if ((transfer->flags & (uint32_t)kI3C_TransferDisableRxTermFlag) != 0U)
1830 {
1831 rxTermOps = kI3C_RxTermDisable;
1832 }
1833 else if (transfer->dataSize <= 255U)
1834 {
1835 rxTermOps = kI3C_RxAutoTerm;
1836 }
1837 else
1838 {
1839 rxTermOps = kI3C_RxTermLastByte;
1840 }
1841
1842 if (0UL != (transfer->flags & (uint32_t)kI3C_TransferStartWithBroadcastAddr))
1843 {
1844 if (0UL != (transfer->flags & (uint32_t)kI3C_TransferNoStartFlag))
1845 {
1846 return kStatus_InvalidArgument;
1847 }
1848
1849 if (0UL != (transfer->flags & (uint32_t)kI3C_TransferRepeatedStartFlag))
1850 {
1851 return kStatus_InvalidArgument;
1852 }
1853
1854 /* Issue 0x7E as start. */
1855 result = I3C_MasterStart(base, transfer->busType, 0x7E, kI3C_Write);
1856 if (result != kStatus_Success)
1857 {
1858 return result;
1859 }
1860
1861 result = I3C_MasterWaitForCtrlDone(base, false);
1862 if (result != kStatus_Success)
1863 {
1864 return result;
1865 }
1866 }
1867
1868 if (0UL == (transfer->flags & (uint32_t)kI3C_TransferNoStartFlag))
1869 {
1870 if ((direction == kI3C_Read) && (rxTermOps == kI3C_RxAutoTerm))
1871 {
1872 result = I3C_MasterStartWithRxSize(base, transfer->busType, transfer->slaveAddress, direction,
1873 (uint8_t)transfer->dataSize);
1874 }
1875 else
1876 {
1877 result = I3C_MasterStart(base, transfer->busType, transfer->slaveAddress, direction);
1878 }
1879 if (result != kStatus_Success)
1880 {
1881 return result;
1882 }
1883
1884 result = I3C_MasterWaitForCtrlDone(base, false);
1885 if (result != kStatus_Success)
1886 {
1887 return result;
1888 }
1889
1890 if (true == I3C_MasterTransferNoStartFlag(base, transfer))
1891 {
1892 return kStatus_I3C_IBIWon;
1893 }
1894 }
1895 else
1896 {
1897 if ((direction == kI3C_Read) && (rxTermOps != kI3C_RxTermDisable))
1898 {
1899 /* Can't set Rx termination more than one bytes in advance without START. */
1900 rxTermOps = kI3C_RxTermLastByte;
1901 }
1902 }
1903
1904 /* Subaddress, MSB first. */
1905 if (0U != transfer->subaddressSize)
1906 {
1907 uint32_t subaddressRemaining = transfer->subaddressSize;
1908 while (0UL != subaddressRemaining--)
1909 {
1910 uint8_t subaddressByte = (uint8_t)((transfer->subaddress >> (8UL * subaddressRemaining)) & 0xFFUL);
1911
1912 result = I3C_MasterWaitForTxReady(base, 1U);
1913
1914 if ((0UL == subaddressRemaining) && ((transfer->direction == kI3C_Read) || (0UL == transfer->dataSize)) &&
1915 (transfer->busType != kI3C_TypeI3CDdr))
1916 {
1917 base->MWDATABE = subaddressByte;
1918 result = I3C_MasterWaitForComplete(base, false);
1919 if (kStatus_Success != result)
1920 {
1921 if (result == kStatus_I3C_Nak)
1922 {
1923 (void)I3C_MasterEmitStop(base, true);
1924 }
1925 I3C_MasterClearFlagsAndEnableIRQ(base);
1926 return result;
1927 }
1928 }
1929 else
1930 {
1931 base->MWDATAB = subaddressByte;
1932 }
1933 }
1934 /* Need to send repeated start if switching directions to read. */
1935 if ((transfer->busType != kI3C_TypeI3CDdr) && (0UL != transfer->dataSize) && (transfer->direction == kI3C_Read))
1936 {
1937 if (rxTermOps == kI3C_RxAutoTerm)
1938 {
1939 result = I3C_MasterRepeatedStartWithRxSize(base, transfer->busType, transfer->slaveAddress, kI3C_Read,
1940 (uint8_t)transfer->dataSize);
1941 }
1942 else
1943 {
1944 result = I3C_MasterRepeatedStart(base, transfer->busType, transfer->slaveAddress, kI3C_Read);
1945 }
1946
1947 if (kStatus_Success != result)
1948 {
1949 I3C_MasterClearFlagsAndEnableIRQ(base);
1950 return result;
1951 }
1952
1953 result = I3C_MasterWaitForCtrlDone(base, false);
1954 if (result != kStatus_Success)
1955 {
1956 return result;
1957 }
1958 }
1959 }
1960
1961 if (rxTermOps == kI3C_RxAutoTerm)
1962 {
1963 transfer->flags |= (uint32_t)kI3C_TransferRxAutoTermFlag;
1964 }
1965 else
1966 {
1967 transfer->flags &= ~(uint32_t)kI3C_TransferRxAutoTermFlag;
1968 }
1969
1970 /* Transmit data. */
1971 if ((transfer->direction == kI3C_Write) && (transfer->dataSize > 0UL))
1972 {
1973 /* Send Data. */
1974 result = I3C_MasterSend(base, transfer->data, transfer->dataSize, transfer->flags);
1975 }
1976 /* Receive Data. */
1977 else if ((transfer->direction == kI3C_Read) && (transfer->dataSize > 0UL))
1978 {
1979 result = I3C_MasterReceive(base, transfer->data, transfer->dataSize, transfer->flags);
1980 }
1981 else
1982 {
1983 if ((transfer->flags & (uint32_t)kI3C_TransferNoStopFlag) == 0UL)
1984 {
1985 result = I3C_MasterEmitStop(base, true);
1986 }
1987 }
1988
1989 if (result == kStatus_I3C_Nak)
1990 {
1991 (void)I3C_MasterEmitStop(base, true);
1992 }
1993
1994 I3C_MasterClearFlagsAndEnableIRQ(base);
1995
1996 return result;
1997 }
1998
1999 /*!
2000 * brief Creates a new handle for the I3C master non-blocking APIs.
2001 *
2002 * The creation of a handle is for use with the non-blocking APIs. Once a handle
2003 * is created, there is not a corresponding destroy handle. If the user wants to
2004 * terminate a transfer, the I3C_MasterTransferAbort() API shall be called.
2005 *
2006 *
2007 * note The function also enables the NVIC IRQ for the input I3C. Need to notice
2008 * that on some SoCs the I3C IRQ is connected to INTMUX, in this case user needs to
2009 * enable the associated INTMUX IRQ in application.
2010 *
2011 * param base The I3C peripheral base address.
2012 * param[out] handle Pointer to the I3C master driver handle.
2013 * param callback User provided pointer to the asynchronous callback function.
2014 * param userData User provided pointer to the application callback data.
2015 */
I3C_MasterTransferCreateHandle(I3C_Type * base,i3c_master_handle_t * handle,const i3c_master_transfer_callback_t * callback,void * userData)2016 void I3C_MasterTransferCreateHandle(I3C_Type *base,
2017 i3c_master_handle_t *handle,
2018 const i3c_master_transfer_callback_t *callback,
2019 void *userData)
2020 {
2021 uint32_t instance;
2022
2023 assert(NULL != handle);
2024
2025 /* Clear out the handle. */
2026 (void)memset(handle, 0, sizeof(*handle));
2027
2028 /* Look up instance number */
2029 instance = I3C_GetInstance(base);
2030
2031 /* Save base and instance. */
2032 handle->callback = *callback;
2033 handle->userData = userData;
2034
2035 /* Save this handle for IRQ use. */
2036 s_i3cMasterHandle[instance] = handle;
2037
2038 /* Set irq handler. */
2039 s_i3cMasterIsr = I3C_MasterTransferHandleIRQ;
2040
2041 /* Clear all flags. */
2042 I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
2043 I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
2044 /* Reset fifos. These flags clear automatically. */
2045 base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
2046
2047 /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
2048 In some cases the I3C IRQ is configured through INTMUX, user needs to enable
2049 INTMUX IRQ in application code. */
2050 (void)EnableIRQ(kI3cIrqs[instance]);
2051
2052 /* Clear internal IRQ enables and enable NVIC IRQ. */
2053 I3C_MasterEnableInterrupts(base, (uint32_t)kMasterIrqFlags);
2054 }
2055
I3C_TransferStateMachineIBIWonState(I3C_Type * base,i3c_master_handle_t * handle,i3c_master_state_machine_param_t * stateParams)2056 static void I3C_TransferStateMachineIBIWonState(I3C_Type *base,
2057 i3c_master_handle_t *handle,
2058 i3c_master_state_machine_param_t *stateParams)
2059 {
2060 assert(NULL != base && NULL != handle && NULL != stateParams);
2061 if (stateParams->masterState == kI3C_MasterStateIbiAck)
2062 {
2063 handle->ibiType = I3C_GetIBIType(base);
2064 if (handle->callback.ibiCallback != NULL)
2065 {
2066 handle->callback.ibiCallback(base, handle, handle->ibiType, kI3C_IbiAckNackPending);
2067 }
2068 else
2069 {
2070 I3C_MasterEmitIBIResponse(base, kI3C_IbiRespNack);
2071 }
2072 }
2073
2074 /* Make sure there is data in the rx fifo. */
2075 if (0UL != stateParams->rxCount)
2076 {
2077 if ((handle->ibiBuff == NULL) && (handle->callback.ibiCallback != NULL))
2078 {
2079 handle->callback.ibiCallback(base, handle, kI3C_IbiNormal, kI3C_IbiDataBuffNeed);
2080 }
2081 uint8_t tempData = (uint8_t)base->MRDATAB;
2082 if (handle->ibiBuff != NULL)
2083 {
2084 handle->ibiBuff[handle->ibiPayloadSize++] = tempData;
2085 }
2086 (stateParams->rxCount)--;
2087 return;
2088 }
2089 else if (0UL != (stateParams->status & (uint32_t)kI3C_MasterCompleteFlag))
2090 {
2091 handle->ibiType = I3C_GetIBIType(base);
2092 handle->ibiAddress = I3C_GetIBIAddress(base);
2093 stateParams->state_complete = true;
2094 stateParams->result = kStatus_I3C_IBIWon;
2095 }
2096 else
2097 {
2098 stateParams->state_complete = true;
2099 }
2100 }
2101
I3C_TransferStateMachineSendCommandState(I3C_Type * base,i3c_master_handle_t * handle,i3c_master_state_machine_param_t * stateParams)2102 static void I3C_TransferStateMachineSendCommandState(I3C_Type *base,
2103 i3c_master_handle_t *handle,
2104 i3c_master_state_machine_param_t *stateParams)
2105 {
2106 assert(NULL != base && NULL != handle && NULL != stateParams);
2107 I3C_MasterEnableInterrupts(base, (uint32_t)kI3C_MasterTxReadyFlag);
2108 /* Make sure there is room in the tx fifo for the next command. */
2109 if (0UL == (stateParams->txCount)--)
2110 {
2111 stateParams->state_complete = true;
2112 return;
2113 }
2114 if (handle->transfer.subaddressSize > 1U)
2115 {
2116 handle->transfer.subaddressSize--;
2117 base->MWDATAB = (uint8_t)((handle->transfer.subaddress) >> (8U * handle->transfer.subaddressSize));
2118 }
2119 else if (handle->transfer.subaddressSize == 1U)
2120 {
2121 handle->transfer.subaddressSize--;
2122
2123 if ((handle->transfer.direction == kI3C_Read) || (0UL == handle->transfer.dataSize))
2124 {
2125 base->MWDATABE = (uint8_t)((handle->transfer.subaddress) >> (8U * handle->transfer.subaddressSize));
2126
2127 if (handle->transfer.busType != kI3C_TypeI3CDdr)
2128 {
2129 if (0UL == handle->transfer.dataSize)
2130 {
2131 handle->state = (uint8_t)kWaitForCompletionState;
2132 }
2133 else
2134 {
2135 /* xfer->dataSize != 0U, xfer->direction = kI3C_Read */
2136 handle->state = (uint8_t)kWaitRepeatedStartCompleteState;
2137 }
2138 }
2139 else
2140 {
2141 handle->state = (uint8_t)kTransferDataState;
2142 }
2143 }
2144 else
2145 {
2146 /* Next state, transfer data. */
2147 handle->state = (uint8_t)kTransferDataState;
2148 base->MWDATAB = (uint8_t)((handle->transfer.subaddress) >> (8U * handle->transfer.subaddressSize));
2149 }
2150 }
2151 else
2152 {
2153 /* Eliminate misra 15.7*/
2154 }
2155 }
2156
I3C_TransferStateMachineWaitRepeatedStartCompleteState(I3C_Type * base,i3c_master_handle_t * handle,i3c_master_state_machine_param_t * stateParams)2157 static void I3C_TransferStateMachineWaitRepeatedStartCompleteState(I3C_Type *base,
2158 i3c_master_handle_t *handle,
2159 i3c_master_state_machine_param_t *stateParams)
2160 {
2161 assert(NULL != base && NULL != handle && NULL != stateParams);
2162 /* We stay in this state until the master complete. */
2163 if (0UL != (stateParams->status & (uint32_t)kI3C_MasterCompleteFlag))
2164 {
2165 handle->state = (uint8_t)kTransferDataState;
2166 I3C_MasterDisableInterrupts(base, (uint32_t)kI3C_MasterTxReadyFlag);
2167
2168 if (handle->remainingBytes < 256U)
2169 {
2170 handle->rxTermOps = (handle->rxTermOps == kI3C_RxTermDisable) ? handle->rxTermOps : kI3C_RxAutoTerm;
2171 stateParams->result =
2172 I3C_MasterRepeatedStartWithRxSize(base, handle->transfer.busType, handle->transfer.slaveAddress,
2173 kI3C_Read, (uint8_t)handle->remainingBytes);
2174 }
2175 else
2176 {
2177 stateParams->result =
2178 I3C_MasterRepeatedStart(base, handle->transfer.busType, handle->transfer.slaveAddress, kI3C_Read);
2179 }
2180 }
2181
2182 stateParams->state_complete = true;
2183 }
2184
I3C_TransferStateMachineTransferDataState(I3C_Type * base,i3c_master_handle_t * handle,i3c_master_state_machine_param_t * stateParams)2185 static void I3C_TransferStateMachineTransferDataState(I3C_Type *base,
2186 i3c_master_handle_t *handle,
2187 i3c_master_state_machine_param_t *stateParams)
2188 {
2189 assert(NULL != base && NULL != handle && NULL != stateParams);
2190
2191 i3c_puint8_to_u32_t dataBuff;
2192 if (handle->transfer.direction == kI3C_Write)
2193 {
2194 /* Make sure there is room in the tx fifo. */
2195 if (0UL == (stateParams->txCount)--)
2196 {
2197 stateParams->state_complete = true;
2198 return;
2199 }
2200
2201 /* Put byte to send in fifo. */
2202 dataBuff.puint8 = (uint8_t *)handle->transfer.data;
2203 if (handle->transfer.dataSize > 1U)
2204 {
2205 base->MWDATAB = *dataBuff.puint8;
2206 }
2207 else
2208 {
2209 base->MWDATABE = *dataBuff.puint8;
2210 }
2211 dataBuff.u32 = dataBuff.u32 + 1U;
2212 (handle->transfer.dataSize)--;
2213 handle->transfer.data = (void *)(dataBuff.puint8);
2214
2215 /* Move to stop when the transfer is done. */
2216 if (--handle->remainingBytes == 0UL)
2217 {
2218 handle->state = (uint8_t)kWaitForCompletionState;
2219 }
2220 }
2221 else
2222 {
2223 /* Make sure there is data in the rx fifo. */
2224 if (0UL == (stateParams->rxCount)--)
2225 {
2226 stateParams->state_complete = true;
2227 return;
2228 }
2229
2230 /* Read byte from fifo. */
2231 dataBuff.puint8 = (uint8_t *)handle->transfer.data;
2232 *dataBuff.puint8 = (uint8_t)base->MRDATAB;
2233 dataBuff.u32 = dataBuff.u32 + 1U;
2234 handle->transfer.data = (void *)(dataBuff.puint8);
2235
2236 /* Move to stop when the transfer is done. */
2237 if (--handle->remainingBytes == 0UL)
2238 {
2239 handle->state = (uint8_t)kWaitForCompletionState;
2240 }
2241
2242 if ((handle->rxTermOps == kI3C_RxTermLastByte) && (handle->remainingBytes == 1UL))
2243 {
2244 base->MCTRL |= I3C_MCTRL_RDTERM(1UL);
2245 }
2246 }
2247 }
2248
I3C_TransferStateMachineWaitForCompletionState(i3c_master_handle_t * handle,i3c_master_state_machine_param_t * stateParams)2249 static void I3C_TransferStateMachineWaitForCompletionState(i3c_master_handle_t *handle,
2250 i3c_master_state_machine_param_t *stateParams)
2251 {
2252 /* We stay in this state until the maste complete. */
2253 if (0UL != (stateParams->status & (uint32_t)kI3C_MasterCompleteFlag))
2254 {
2255 handle->state = (uint8_t)kStopState;
2256 }
2257 else
2258 {
2259 stateParams->state_complete = true;
2260 }
2261 }
2262
I3C_TransferStateMachineStopState(I3C_Type * base,i3c_master_handle_t * handle,i3c_master_state_machine_param_t * stateParams)2263 static void I3C_TransferStateMachineStopState(I3C_Type *base,
2264 i3c_master_handle_t *handle,
2265 i3c_master_state_machine_param_t *stateParams)
2266 {
2267 /* Only issue a stop transition if the caller requested it. */
2268 if (0UL == (handle->transfer.flags & (uint32_t)kI3C_TransferNoStopFlag))
2269 {
2270 /* Make sure there is room in the tx fifo for the stop command. */
2271 if (0UL == (stateParams->txCount)--)
2272 {
2273 stateParams->state_complete = true;
2274 return;
2275 }
2276 if (handle->transfer.busType == kI3C_TypeI3CDdr)
2277 {
2278 I3C_MasterEmitRequest(base, kI3C_RequestForceExit);
2279 }
2280 else
2281 {
2282 (void)I3C_MasterEmitStop(base, false);
2283 }
2284 }
2285 stateParams->state_complete = true;
2286 }
2287
I3C_RunTransferStateMachine(I3C_Type * base,i3c_master_handle_t * handle,bool * isDone)2288 static status_t I3C_RunTransferStateMachine(I3C_Type *base, i3c_master_handle_t *handle, bool *isDone)
2289 {
2290 i3c_master_state_machine_param_t stateParams;
2291 (void)memset(&stateParams, 0, sizeof(stateParams));
2292
2293 stateParams.result = kStatus_Success;
2294 stateParams.state_complete = false;
2295
2296 /* Set default isDone return value. */
2297 *isDone = false;
2298
2299 uint32_t errStatus;
2300 size_t txFifoSize =
2301 2UL << ((base->SCAPABILITIES & I3C_SCAPABILITIES_FIFOTX_MASK) >> I3C_SCAPABILITIES_FIFOTX_SHIFT);
2302
2303 /* Check for errors. */
2304 stateParams.status = (uint32_t)I3C_MasterGetPendingInterrupts(base);
2305 I3C_MasterClearStatusFlags(base, stateParams.status);
2306
2307 stateParams.masterState = I3C_MasterGetState(base);
2308 errStatus = I3C_MasterGetErrorStatusFlags(base);
2309 stateParams.result = I3C_MasterCheckAndClearError(base, errStatus);
2310 if (kStatus_Success != stateParams.result)
2311 {
2312 return stateParams.result;
2313 }
2314
2315 if (0UL != (stateParams.status & (uint32_t)kI3C_MasterSlave2MasterFlag))
2316 {
2317 if (handle->callback.slave2Master != NULL)
2318 {
2319 handle->callback.slave2Master(base, handle->userData);
2320 }
2321 }
2322
2323 if ((0UL != (stateParams.status & (uint32_t)kI3C_MasterSlaveStartFlag)) &&
2324 (handle->transfer.busType != kI3C_TypeI2C))
2325 {
2326 handle->state = (uint8_t)kSlaveStartState;
2327 }
2328
2329 if ((stateParams.masterState == kI3C_MasterStateIbiRcv) || (stateParams.masterState == kI3C_MasterStateIbiAck))
2330 {
2331 handle->state = (uint8_t)kIBIWonState;
2332 }
2333
2334 if (handle->state == (uint8_t)kIdleState)
2335 {
2336 return stateParams.result;
2337 }
2338
2339 /* Get fifo counts and compute room in tx fifo. */
2340 I3C_MasterGetFifoCounts(base, &stateParams.rxCount, &stateParams.txCount);
2341 stateParams.txCount = txFifoSize - stateParams.txCount;
2342
2343 while (!stateParams.state_complete)
2344 {
2345 /* Execute the state. */
2346 switch (handle->state)
2347 {
2348 case (uint8_t)kSlaveStartState:
2349 /* Emit start + 0x7E */
2350 I3C_MasterEmitRequest(base, kI3C_RequestAutoIbi);
2351 handle->state = (uint8_t)kIBIWonState;
2352 stateParams.state_complete = true;
2353 break;
2354
2355 case (uint8_t)kIBIWonState:
2356 I3C_TransferStateMachineIBIWonState(base, handle, &stateParams);
2357 break;
2358
2359 case (uint8_t)kSendCommandState:
2360 I3C_TransferStateMachineSendCommandState(base, handle, &stateParams);
2361 break;
2362
2363 case (uint8_t)kWaitRepeatedStartCompleteState:
2364 I3C_TransferStateMachineWaitRepeatedStartCompleteState(base, handle, &stateParams);
2365 break;
2366
2367 case (uint8_t)kTransferDataState:
2368 I3C_TransferStateMachineTransferDataState(base, handle, &stateParams);
2369 break;
2370
2371 case (uint8_t)kWaitForCompletionState:
2372 I3C_TransferStateMachineWaitForCompletionState(handle, &stateParams);
2373 break;
2374
2375 case (uint8_t)kStopState:
2376 I3C_TransferStateMachineStopState(base, handle, &stateParams);
2377 *isDone = true;
2378 break;
2379
2380 default:
2381 assert(false);
2382 break;
2383 }
2384 }
2385 return stateParams.result;
2386 }
2387
I3C_InitTransferStateMachine(I3C_Type * base,i3c_master_handle_t * handle)2388 static status_t I3C_InitTransferStateMachine(I3C_Type *base, i3c_master_handle_t *handle)
2389 {
2390 i3c_master_transfer_t *xfer = &handle->transfer;
2391 status_t result = kStatus_Success;
2392 i3c_direction_t direction = xfer->direction;
2393
2394 if (xfer->busType != kI3C_TypeI3CDdr)
2395 {
2396 direction = (0UL != xfer->subaddressSize) ? kI3C_Write : xfer->direction;
2397 }
2398
2399 if (0UL != (xfer->flags & (uint32_t)kI3C_TransferStartWithBroadcastAddr))
2400 {
2401 if (0UL != (xfer->flags & (uint32_t)kI3C_TransferNoStartFlag))
2402 {
2403 return kStatus_InvalidArgument;
2404 }
2405
2406 if (0UL != (xfer->flags & (uint32_t)kI3C_TransferRepeatedStartFlag))
2407 {
2408 return kStatus_InvalidArgument;
2409 }
2410
2411 /* Issue 0x7E as start. */
2412 result = I3C_MasterStart(base, xfer->busType, 0x7E, kI3C_Write);
2413 if (result != kStatus_Success)
2414 {
2415 return result;
2416 }
2417
2418 result = I3C_MasterWaitForCtrlDone(base, false);
2419 if (result != kStatus_Success)
2420 {
2421 return result;
2422 }
2423 }
2424
2425 /* Handle no start option. */
2426 if (0U != (xfer->flags & (uint32_t)kI3C_TransferNoStartFlag))
2427 {
2428 /* No need to send start flag, directly go to send command or data */
2429 if (xfer->subaddressSize > 0UL)
2430 {
2431 handle->state = (uint8_t)kSendCommandState;
2432 }
2433 else
2434 {
2435 if (direction == kI3C_Write)
2436 {
2437 /* Next state, send data. */
2438 handle->state = (uint8_t)kTransferDataState;
2439 }
2440 else
2441 {
2442 /* Only support write with no stop signal. */
2443 return kStatus_InvalidArgument;
2444 }
2445 }
2446 I3C_MasterTransferHandleIRQ(base, handle);
2447 return result;
2448 }
2449 /* If repeated start is requested, send repeated start. */
2450 else if (0U != (xfer->flags & (uint32_t)kI3C_TransferRepeatedStartFlag))
2451 {
2452 result = I3C_MasterRepeatedStart(base, xfer->busType, xfer->slaveAddress, direction);
2453 }
2454 else /* For normal transfer, send start. */
2455 {
2456 result = I3C_MasterStart(base, xfer->busType, xfer->slaveAddress, direction);
2457 }
2458
2459 if (xfer->subaddressSize > 0U)
2460 {
2461 handle->state = (uint8_t)kSendCommandState;
2462 }
2463 else if (xfer->dataSize != 0U)
2464 {
2465 handle->state = (uint8_t)kTransferDataState;
2466 }
2467 else
2468 {
2469 handle->state = (uint8_t)kStopState;
2470 }
2471
2472 if ((handle->remainingBytes < 256U) && (direction == kI3C_Read))
2473 {
2474 handle->rxTermOps = (handle->rxTermOps == kI3C_RxTermDisable) ? handle->rxTermOps : kI3C_RxAutoTerm;
2475 base->MCTRL |= I3C_MCTRL_RDTERM(handle->remainingBytes);
2476 }
2477
2478 return result;
2479 }
2480
2481 /*!
2482 * brief Performs a non-blocking transaction on the I2C/I3C bus.
2483 *
2484 * param base The I3C peripheral base address.
2485 * param handle Pointer to the I3C master driver handle.
2486 * param transfer The pointer to the transfer descriptor.
2487 * retval #kStatus_Success The transaction was started successfully.
2488 * retval #kStatus_I3C_Busy Either another master is currently utilizing the bus, or a non-blocking
2489 * transaction is already in progress.
2490 */
I3C_MasterTransferNonBlocking(I3C_Type * base,i3c_master_handle_t * handle,i3c_master_transfer_t * transfer)2491 status_t I3C_MasterTransferNonBlocking(I3C_Type *base, i3c_master_handle_t *handle, i3c_master_transfer_t *transfer)
2492 {
2493 assert(NULL != handle);
2494 assert(NULL != transfer);
2495 assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
2496 i3c_master_state_t masterState = I3C_MasterGetState(base);
2497 bool checkDdrState = false;
2498
2499 /* Return busy if another transaction is in progress. */
2500 if (handle->state != (uint8_t)kIdleState)
2501 {
2502 return kStatus_I3C_Busy;
2503 }
2504
2505 /* Return an error if the bus is already in use not by us. */
2506 checkDdrState = (transfer->busType == kI3C_TypeI3CDdr) ? (masterState != kI3C_MasterStateDdr) : true;
2507 if ((masterState != kI3C_MasterStateIdle) && (masterState != kI3C_MasterStateNormAct) && checkDdrState)
2508 {
2509 return kStatus_I3C_Busy;
2510 }
2511
2512 /* Disable I3C IRQ sources while we configure stuff. */
2513 I3C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
2514
2515 /* Save transfer into handle. */
2516 handle->transfer = *transfer;
2517 handle->remainingBytes = transfer->dataSize;
2518
2519 /* Configure IBI response type. */
2520 base->MCTRL &= ~I3C_MCTRL_IBIRESP_MASK;
2521 base->MCTRL |= I3C_MCTRL_IBIRESP(transfer->ibiResponse);
2522
2523 /* Clear all flags. */
2524 I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
2525 I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
2526 /* Reset fifos. These flags clear automatically. */
2527 base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
2528
2529 if ((transfer->flags & (uint32_t)kI3C_TransferDisableRxTermFlag) != 0U)
2530 {
2531 handle->rxTermOps = kI3C_RxTermDisable;
2532 }
2533 else if (transfer->dataSize <= 255U)
2534 {
2535 handle->rxTermOps = kI3C_RxAutoTerm;
2536 }
2537 else
2538 {
2539 handle->rxTermOps = kI3C_RxTermLastByte;
2540 }
2541
2542 /* Generate commands to send. */
2543 (void)I3C_InitTransferStateMachine(base, handle);
2544
2545 /* Enable I3C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
2546 I3C_MasterEnableInterrupts(base, (uint32_t)kMasterIrqFlags);
2547
2548 if (transfer->direction == kI3C_Write)
2549 {
2550 I3C_MasterEnableInterrupts(base, (uint32_t)kI3C_MasterTxReadyFlag);
2551 }
2552
2553 return kStatus_Success;
2554 }
2555
2556 /*!
2557 * brief Returns number of bytes transferred so far.
2558 * param base The I3C peripheral base address.
2559 * param handle Pointer to the I3C master driver handle.
2560 * param[out] count Number of bytes transferred so far by the non-blocking transaction.
2561 * retval #kStatus_Success
2562 * retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
2563 */
I3C_MasterTransferGetCount(I3C_Type * base,i3c_master_handle_t * handle,size_t * count)2564 status_t I3C_MasterTransferGetCount(I3C_Type *base, i3c_master_handle_t *handle, size_t *count)
2565 {
2566 assert(NULL != handle);
2567
2568 if (NULL == count)
2569 {
2570 return kStatus_InvalidArgument;
2571 }
2572
2573 /* Catch when there is not an active transfer. */
2574 if (handle->state == (uint8_t)kIdleState)
2575 {
2576 *count = 0;
2577 return kStatus_NoTransferInProgress;
2578 }
2579
2580 uint8_t state;
2581 uint32_t remainingBytes;
2582 uint32_t dataSize;
2583
2584 /* Cache some fields with IRQs disabled. This ensures all field values */
2585 /* are synchronized with each other during an ongoing transfer. */
2586 uint32_t irqs = I3C_MasterGetEnabledInterrupts(base);
2587 I3C_MasterDisableInterrupts(base, irqs);
2588 state = handle->state;
2589 remainingBytes = handle->remainingBytes;
2590 dataSize = handle->transfer.dataSize;
2591 I3C_MasterEnableInterrupts(base, irqs);
2592
2593 /* Get transfer count based on current transfer state. */
2594 switch (state)
2595 {
2596 case (uint8_t)kIdleState:
2597 case (uint8_t)kSendCommandState:
2598 *count = 0;
2599 break;
2600
2601 case (uint8_t)kTransferDataState:
2602 *count = dataSize - remainingBytes;
2603 break;
2604
2605 case (uint8_t)kStopState:
2606 case (uint8_t)kWaitForCompletionState:
2607 default:
2608 *count = dataSize;
2609 break;
2610 }
2611
2612 return kStatus_Success;
2613 }
2614
2615 /*!
2616 * brief Terminates a non-blocking I3C master transmission early.
2617 *
2618 * note It is not safe to call this function from an IRQ handler that has a higher priority than the
2619 * I3C peripheral's IRQ priority.
2620 *
2621 * param base The I3C peripheral base address.
2622 * param handle Pointer to the I3C master driver handle.
2623 * retval #kStatus_Success A transaction was successfully aborted.
2624 * retval #kStatus_I3C_Idle There is not a non-blocking transaction currently in progress.
2625 */
I3C_MasterTransferAbort(I3C_Type * base,i3c_master_handle_t * handle)2626 void I3C_MasterTransferAbort(I3C_Type *base, i3c_master_handle_t *handle)
2627 {
2628 if (handle->state != (uint8_t)kIdleState)
2629 {
2630 /* Disable internal IRQ enables. */
2631 I3C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
2632
2633 /* Reset fifos. These flags clear automatically. */
2634 base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
2635
2636 /* Send a stop command to finalize the transfer. */
2637 (void)I3C_MasterStop(base);
2638
2639 /* Reset handle. */
2640 handle->state = (uint8_t)kIdleState;
2641 }
2642 }
2643
2644 /*!
2645 * brief Reusable routine to handle master interrupts.
2646 * note This function does not need to be called unless you are reimplementing the
2647 * nonblocking API's interrupt handler routines to add special functionality.
2648 * param base The I3C peripheral base address.
2649 * param intHandle Pointer to the I3C master driver handle.
2650 */
I3C_MasterTransferHandleIRQ(I3C_Type * base,void * intHandle)2651 void I3C_MasterTransferHandleIRQ(I3C_Type *base, void *intHandle)
2652 {
2653 i3c_master_handle_t *handle = (i3c_master_handle_t *)intHandle;
2654 status_t result;
2655 bool isDone;
2656
2657 /* Don't do anything if we don't have a valid handle. */
2658 if (NULL == handle)
2659 {
2660 return;
2661 }
2662
2663 result = I3C_RunTransferStateMachine(base, handle, &isDone);
2664
2665 if (handle->state == (uint8_t)kIdleState)
2666 {
2667 I3C_MasterDisableInterrupts(base, (uint32_t)kI3C_MasterTxReadyFlag);
2668 return;
2669 }
2670
2671 if (isDone || (result != kStatus_Success))
2672 {
2673 /* XXX need to handle data that may be in rx fifo below watermark level? */
2674
2675 /* XXX handle error, terminate xfer */
2676 if ((result == kStatus_I3C_Nak) || (result == kStatus_I3C_IBIWon))
2677 {
2678 (void)I3C_MasterEmitStop(base, false);
2679 }
2680
2681 /* Disable internal IRQ enables. */
2682 I3C_MasterDisableInterrupts(base, (uint32_t)kI3C_MasterTxReadyFlag);
2683
2684 /* Set handle to idle state. */
2685 handle->state = (uint8_t)kIdleState;
2686
2687 /* Invoke IBI user callback. */
2688 if ((result == kStatus_I3C_IBIWon) && (handle->callback.ibiCallback != NULL))
2689 {
2690 handle->callback.ibiCallback(base, handle, handle->ibiType, kI3C_IbiReady);
2691 handle->ibiPayloadSize = 0;
2692 }
2693
2694 /* Invoke callback. */
2695 if (NULL != handle->callback.transferComplete)
2696 {
2697 handle->callback.transferComplete(base, handle, result, handle->userData);
2698 }
2699 }
2700 }
2701
2702 /*!
2703 * brief Provides a default configuration for the I3C slave peripheral.
2704 *
2705 * This function provides the following default configuration for the I3C slave peripheral:
2706 * code
2707 * slaveConfig->enableslave = true;
2708 * endcode
2709 *
2710 * After calling this function, you can override any settings in order to customize the configuration,
2711 * prior to initializing the slave driver with I3C_SlaveInit().
2712 *
2713 * param[out] slaveConfig User provided configuration structure for default values. Refer to #i3c_slave_config_t.
2714 */
I3C_SlaveGetDefaultConfig(i3c_slave_config_t * slaveConfig)2715 void I3C_SlaveGetDefaultConfig(i3c_slave_config_t *slaveConfig)
2716 {
2717 assert(NULL != slaveConfig);
2718
2719 (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
2720
2721 slaveConfig->enableSlave = true;
2722 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ) && FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ)
2723 slaveConfig->isHotJoin = false;
2724 #endif
2725 slaveConfig->vendorID = 0x11BU;
2726 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND)
2727 slaveConfig->enableRandomPart = false;
2728 #endif
2729 slaveConfig->partNumber = 0;
2730 slaveConfig->dcr = 0; /* Generic device. */
2731 slaveConfig->bcr =
2732 0; /* BCR[7:6]: device role, I3C slave(2b'00), BCR[5]: SDR Only / SDR and HDR Capable, SDR and HDR
2733 Capable(1b'1), BCR[4]: Bridge Identifier, Not a bridge device(1b'0), BCR[3]: Offline Capable, device is
2734 offline capable(1b'1), BCR[2]: IBI Payload, No data byte following(1b'0), BCR[1]: IBI Request Capable,
2735 capable(1b'1), BCR[0]: Max Data Speed Limitation, has limitation(1b'1). */
2736 slaveConfig->hdrMode = (uint8_t)kI3C_HDRModeDDR;
2737 slaveConfig->nakAllRequest = false;
2738 slaveConfig->ignoreS0S1Error = true;
2739 slaveConfig->offline = false;
2740 slaveConfig->matchSlaveStartStop = false;
2741 slaveConfig->maxWriteLength = 256U;
2742 slaveConfig->maxReadLength = 256U;
2743 }
2744
2745 /*!
2746 * brief Initializes the I3C slave peripheral.
2747 *
2748 * This function enables the peripheral clock and initializes the I3C slave peripheral as described by the user
2749 * provided configuration.
2750 *
2751 * param base The I3C peripheral base address.
2752 * param slaveConfig User provided peripheral configuration. Use I3C_SlaveGetDefaultConfig() to get a set of
2753 * defaults that you can override.
2754 * param slowClock_Hz Frequency in Hertz of the I3C slow clock. Used to calculate the bus match condition values.
2755 * If FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH defines as 1, this parameter is useless.
2756 */
I3C_SlaveInit(I3C_Type * base,const i3c_slave_config_t * slaveConfig,uint32_t slowClock_Hz)2757 void I3C_SlaveInit(I3C_Type *base, const i3c_slave_config_t *slaveConfig, uint32_t slowClock_Hz)
2758 {
2759 assert(NULL != slaveConfig);
2760 assert((slowClock_Hz >= 1000000U) || (slowClock_Hz == 0U));
2761
2762 uint32_t configValue;
2763 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) || \
2764 !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
2765 uint32_t instance = I3C_GetInstance(base);
2766 #endif
2767
2768 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
2769 /* Ungate the clock. */
2770 CLOCK_EnableClock(kI3cClocks[instance]);
2771 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
2772
2773 #if !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
2774 /* Reset the I3C module */
2775 RESET_PeripheralReset(kI3cResets[instance]);
2776 #endif
2777
2778 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
2779 uint8_t matchCount;
2780 /* Set as (slowClk(MHz) - 1) to generate 1us clock cycle for IBI request to drive SDA low. Note: Use BAMATCH = 1 to
2781 generate 1us clock cycle if slow clock is 1MHz. The value of 0 would not give a correct match indication. */
2782 if (slowClock_Hz != 0U)
2783 {
2784 matchCount = (uint8_t)(slowClock_Hz / 1000000UL) - 1U;
2785 matchCount = (matchCount == 0U) ? 1U : matchCount;
2786 }
2787 else
2788 {
2789 /* BAMATCH has default value based on Soc default slow clock after reset, using this default value when slowClock_Hz is 0. */
2790 matchCount = (uint8_t)((base->SCONFIG & I3C_SCONFIG_BAMATCH_MASK) >> I3C_SCONFIG_BAMATCH_SHIFT);
2791 }
2792 #endif
2793
2794 configValue = base->SCONFIG;
2795 configValue &=
2796 ~(I3C_SCONFIG_SADDR_MASK |
2797 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
2798 I3C_SCONFIG_BAMATCH_MASK |
2799 #endif
2800 I3C_SCONFIG_OFFLINE_MASK |
2801 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND)
2802 I3C_SCONFIG_IDRAND_MASK |
2803 #endif
2804 #if defined(FSL_FEATURE_I3C_HAS_HDROK) && FSL_FEATURE_I3C_HAS_HDROK
2805 I3C_SCONFIG_HDROK_MASK |
2806 #else
2807 I3C_SCONFIG_DDROK_MASK |
2808 #endif
2809 I3C_SCONFIG_S0IGNORE_MASK | I3C_SCONFIG_MATCHSS_MASK | I3C_SCONFIG_NACK_MASK | I3C_SCONFIG_SLVENA_MASK);
2810 configValue |= I3C_SCONFIG_SADDR(slaveConfig->staticAddr) |
2811 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_BAMATCH)
2812 I3C_SCONFIG_BAMATCH(matchCount) |
2813 #endif
2814 I3C_SCONFIG_OFFLINE(slaveConfig->offline) |
2815 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND)
2816 I3C_SCONFIG_IDRAND(slaveConfig->enableRandomPart) |
2817 #endif
2818 #if defined(FSL_FEATURE_I3C_HAS_HDROK) && FSL_FEATURE_I3C_HAS_HDROK
2819 I3C_SCONFIG_HDROK((0U != (slaveConfig->hdrMode & (uint8_t)kI3C_HDRModeDDR)) ? 1U : 0U) |
2820 #else
2821 I3C_SCONFIG_DDROK((0U != (slaveConfig->hdrMode & (uint8_t)kI3C_HDRModeDDR)) ? 1U : 0U) |
2822 #endif
2823 I3C_SCONFIG_S0IGNORE(slaveConfig->ignoreS0S1Error) |
2824 I3C_SCONFIG_MATCHSS(slaveConfig->matchSlaveStartStop) |
2825 I3C_SCONFIG_NACK(slaveConfig->nakAllRequest) | I3C_SCONFIG_SLVENA(slaveConfig->enableSlave);
2826
2827 base->SVENDORID &= ~I3C_SVENDORID_VID_MASK;
2828 base->SVENDORID |= I3C_SVENDORID_VID(slaveConfig->vendorID);
2829
2830 #if defined(FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND) && FSL_FEATURE_I3C_HAS_NO_SCONFIG_IDRAND
2831 base->SIDPARTNO = slaveConfig->partNumber;
2832 #else
2833 if (!slaveConfig->enableRandomPart)
2834 {
2835 base->SIDPARTNO = slaveConfig->partNumber;
2836 }
2837 #endif
2838
2839 base->SIDEXT &= ~(I3C_SIDEXT_BCR_MASK | I3C_SIDEXT_DCR_MASK);
2840 base->SIDEXT |= I3C_SIDEXT_BCR(slaveConfig->bcr) | I3C_SIDEXT_DCR(slaveConfig->dcr);
2841
2842 base->SMAXLIMITS &= ~(I3C_SMAXLIMITS_MAXRD_MASK | I3C_SMAXLIMITS_MAXWR_MASK);
2843 base->SMAXLIMITS |=
2844 (I3C_SMAXLIMITS_MAXRD(slaveConfig->maxReadLength) | I3C_SMAXLIMITS_MAXWR(slaveConfig->maxWriteLength));
2845
2846 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ) && FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ)
2847 if (slaveConfig->isHotJoin)
2848 {
2849 I3C_SlaveRequestEvent(base, kI3C_SlaveEventHotJoinReq);
2850 }
2851 #endif
2852 base->SCONFIG = configValue;
2853 }
2854
2855 /*!
2856 * brief Deinitializes the I3C master peripheral.
2857 *
2858 * This function disables the I3C master peripheral and gates the clock. It also performs a software
2859 * reset to restore the peripheral to reset conditions.
2860 *
2861 * param base The I3C peripheral base address.
2862 */
I3C_SlaveDeinit(I3C_Type * base)2863 void I3C_SlaveDeinit(I3C_Type *base)
2864 {
2865 uint32_t idx = I3C_GetInstance(base);
2866
2867 #if !(defined(FSL_FEATURE_I3C_HAS_NO_RESET) && FSL_FEATURE_I3C_HAS_NO_RESET)
2868 /* Reset the I3C module */
2869 RESET_PeripheralReset(kI3cResets[idx]);
2870 #endif
2871
2872 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
2873 /* Gate clock. */
2874 CLOCK_DisableClock(kI3cClocks[idx]);
2875 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
2876
2877 /* Reset handle pointer */
2878 s_i3cSlaveHandle[idx] = NULL;
2879 }
2880
2881 /*!
2882 * @brief Gets the I3C slave state.
2883 *
2884 * @param base The I3C peripheral base address.
2885 * @return I3C slave activity state, refer #i3c_slave_activity_state_t.
2886 */
I3C_SlaveGetActivityState(I3C_Type * base)2887 i3c_slave_activity_state_t I3C_SlaveGetActivityState(I3C_Type *base)
2888 {
2889 uint8_t activeState = (uint8_t)((base->SSTATUS & I3C_SSTATUS_ACTSTATE_MASK) >> I3C_SSTATUS_ACTSTATE_SHIFT);
2890 i3c_slave_activity_state_t returnCode;
2891 switch (activeState)
2892 {
2893 case (uint8_t)kI3C_SlaveNoLatency:
2894 returnCode = kI3C_SlaveNoLatency;
2895 break;
2896 case (uint8_t)kI3C_SlaveLatency1Ms:
2897 returnCode = kI3C_SlaveLatency1Ms;
2898 break;
2899 case (uint8_t)kI3C_SlaveLatency100Ms:
2900 returnCode = kI3C_SlaveLatency100Ms;
2901 break;
2902 case (uint8_t)kI3C_SlaveLatency10S:
2903 returnCode = kI3C_SlaveLatency10S;
2904 break;
2905 default:
2906 returnCode = kI3C_SlaveNoLatency;
2907 break;
2908 }
2909
2910 return returnCode;
2911 }
2912
2913 #if !(defined(FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ) && FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ)
2914 /*!
2915 * brief I3C slave request event.
2916 *
2917 * param base The I3C peripheral base address.
2918 * param event I3C slave event of type #i3c_slave_event_t
2919 * param data IBI data if In-band interrupt has data, only applicable for event type #kI3C_SlaveEventIBI
2920 */
I3C_SlaveRequestEvent(I3C_Type * base,i3c_slave_event_t event)2921 void I3C_SlaveRequestEvent(I3C_Type *base, i3c_slave_event_t event)
2922 {
2923 uint32_t ctrlValue = base->SCTRL;
2924
2925 ctrlValue &= ~I3C_SCTRL_EVENT_MASK;
2926 ctrlValue |= I3C_SCTRL_EVENT(event);
2927
2928 base->SCTRL = ctrlValue;
2929 }
2930
2931 /*!
2932 * brief I3C slave request event.
2933 * deprecated Do not use this function. It has been superseded by @ref I3C_SlaveRequestIBIWithData.
2934 *
2935 * param base The I3C peripheral base address.
2936 * param data IBI data
2937 * param dataSize IBI data size.
2938 */
I3C_SlaveRequestIBIWithSingleData(I3C_Type * base,uint8_t data,size_t dataSize)2939 void I3C_SlaveRequestIBIWithSingleData(I3C_Type *base, uint8_t data, size_t dataSize)
2940 {
2941 uint32_t ctrlValue = base->SCTRL;
2942
2943 ctrlValue &= ~(I3C_SCTRL_EVENT_MASK | I3C_SCTRL_IBIDATA_MASK);
2944 ctrlValue |= I3C_SCTRL_EVENT(1U) | I3C_SCTRL_IBIDATA(data);
2945
2946 base->SCTRL = ctrlValue;
2947 }
2948
2949 /*!
2950 * brief I3C slave request IBI event with data payload(mandatory and extended).
2951 *
2952 * param base The I3C peripheral base address.
2953 * param data Pointer to IBI data to be sent in the request.
2954 * param dataSize IBI data size.
2955 */
I3C_SlaveRequestIBIWithData(I3C_Type * base,uint8_t * data,size_t dataSize)2956 void I3C_SlaveRequestIBIWithData(I3C_Type *base, uint8_t *data, size_t dataSize)
2957 {
2958 assert((dataSize > 0U) && (dataSize <= 8U));
2959
2960 uint32_t ctrlValue;
2961
2962 #if (defined(I3C_IBIEXT1_MAX_MASK) && I3C_IBIEXT1_MAX_MASK)
2963 if (dataSize > 1U)
2964 {
2965 ctrlValue = I3C_IBIEXT1_EXT1(data[1]);
2966 if (dataSize > 2U)
2967 {
2968 ctrlValue |= I3C_IBIEXT1_EXT2(data[2]);
2969 }
2970 if (dataSize > 3U)
2971 {
2972 ctrlValue |= I3C_IBIEXT1_EXT3(data[3]);
2973 }
2974 ctrlValue |= I3C_IBIEXT1_CNT(dataSize - 1U);
2975 base->IBIEXT1 = ctrlValue;
2976 }
2977
2978 if (dataSize > 4U)
2979 {
2980 ctrlValue = I3C_IBIEXT2_EXT4(data[4]);
2981 if (dataSize > 5U)
2982 {
2983 ctrlValue |= I3C_IBIEXT2_EXT5(data[5]);
2984 }
2985 if (dataSize > 6U)
2986 {
2987 ctrlValue |= I3C_IBIEXT2_EXT6(data[6]);
2988 }
2989 if (dataSize > 7U)
2990 {
2991 ctrlValue |= I3C_IBIEXT2_EXT7(data[7]);
2992 }
2993 base->IBIEXT2 = ctrlValue;
2994 }
2995 #endif
2996
2997 ctrlValue = base->SCTRL;
2998 #if (defined(I3C_IBIEXT1_MAX_MASK) && I3C_IBIEXT1_MAX_MASK)
2999 ctrlValue &= ~(I3C_SCTRL_EVENT_MASK | I3C_SCTRL_IBIDATA_MASK | I3C_SCTRL_EXTDATA_MASK);
3000 ctrlValue |= I3C_SCTRL_EVENT(1U) | I3C_SCTRL_IBIDATA(data[0]) | I3C_SCTRL_EXTDATA(dataSize > 1U);
3001 #else
3002 ctrlValue &= ~(I3C_SCTRL_EVENT_MASK | I3C_SCTRL_IBIDATA_MASK);
3003 ctrlValue |= I3C_SCTRL_EVENT(1U) | I3C_SCTRL_IBIDATA(data[0]);
3004 #endif
3005 base->SCTRL = ctrlValue;
3006 }
3007 #endif /* !(defined(FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ) && FSL_FEATURE_I3C_HAS_NO_SLAVE_IBI_MR_HJ) */
3008
3009 /*!
3010 * brief Performs a polling send transfer on the I3C bus.
3011 *
3012 * param base The I3C peripheral base address.
3013 * param txBuff The pointer to the data to be transferred.
3014 * param txSize The length in bytes of the data to be transferred.
3015 * return Error or success status returned by API.
3016 */
I3C_SlaveSend(I3C_Type * base,const void * txBuff,size_t txSize)3017 status_t I3C_SlaveSend(I3C_Type *base, const void *txBuff, size_t txSize)
3018 {
3019 const uint8_t *buf = (const uint8_t *)((const void *)txBuff);
3020 status_t result = kStatus_Success;
3021
3022 assert(NULL != txBuff);
3023
3024 /* Send data buffer */
3025 while (0UL != txSize--)
3026 {
3027 /* Wait until there is room in the fifo. This also checks for errors. */
3028 result = I3C_SlaveWaitForTxReady(base);
3029 if (kStatus_Success != result)
3030 {
3031 return result;
3032 }
3033
3034 /* Write byte into I3C slave data register. */
3035 if (0UL != txSize)
3036 {
3037 base->SWDATAB = *buf++;
3038 }
3039 else
3040 {
3041 base->SWDATABE = *buf++;
3042 }
3043 }
3044
3045 return result;
3046 }
3047
3048 /*!
3049 * brief Performs a polling receive transfer on the I3C bus.
3050 *
3051 * param base The I3C peripheral base address.
3052 * param rxBuff The pointer to the data to be transferred.
3053 * param rxSize The length in bytes of the data to be transferred.
3054 * return Error or success status returned by API.
3055 */
I3C_SlaveReceive(I3C_Type * base,void * rxBuff,size_t rxSize)3056 status_t I3C_SlaveReceive(I3C_Type *base, void *rxBuff, size_t rxSize)
3057 {
3058 status_t result = kStatus_Success;
3059 uint8_t *buf;
3060
3061 assert(NULL != rxBuff);
3062
3063 /* Handle empty read. */
3064 if (0UL == rxSize)
3065 {
3066 return kStatus_Success;
3067 }
3068
3069 #if I3C_RETRY_TIMES
3070 uint32_t waitTimes = I3C_RETRY_TIMES;
3071 #endif
3072
3073 /* Receive data */
3074 buf = (uint8_t *)rxBuff;
3075 while (0UL != rxSize)
3076 {
3077 #if I3C_RETRY_TIMES
3078 if (--waitTimes == 0)
3079 {
3080 return kStatus_I3C_Timeout;
3081 }
3082 #endif
3083 /* Check for errors. */
3084 result = I3C_SlaveCheckAndClearError(base, I3C_SlaveGetErrorStatusFlags(base));
3085 if (kStatus_Success != result)
3086 {
3087 return result;
3088 }
3089
3090 /* Check RX data */
3091 if (0UL != (base->SDATACTRL & I3C_SDATACTRL_RXCOUNT_MASK))
3092 {
3093 *buf++ = (uint8_t)(base->SRDATAB & I3C_SRDATAB_DATA0_MASK);
3094 rxSize--;
3095 }
3096 }
3097
3098 return result;
3099 }
3100
3101 /*!
3102 * brief Creates a new handle for the I3C slave non-blocking APIs.
3103 *
3104 * The creation of a handle is for use with the non-blocking APIs. Once a handle
3105 * is created, there is not a corresponding destroy handle. If the user wants to
3106 * terminate a transfer, the I3C_SlaveTransferAbort() API shall be called.
3107 *
3108 * note The function also enables the NVIC IRQ for the input I3C. Need to notice
3109 * that on some SoCs the I3C IRQ is connected to INTMUX, in this case user needs to
3110 * enable the associated INTMUX IRQ in application.
3111
3112 * param base The I3C peripheral base address.
3113 * param[out] handle Pointer to the I3C slave driver handle.
3114 * param callback User provided pointer to the asynchronous callback function.
3115 * param userData User provided pointer to the application callback data.
3116 */
I3C_SlaveTransferCreateHandle(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_transfer_callback_t callback,void * userData)3117 void I3C_SlaveTransferCreateHandle(I3C_Type *base,
3118 i3c_slave_handle_t *handle,
3119 i3c_slave_transfer_callback_t callback,
3120 void *userData)
3121 {
3122 uint32_t instance;
3123
3124 assert(NULL != handle);
3125
3126 /* Clear out the handle. */
3127 (void)memset(handle, 0, sizeof(*handle));
3128
3129 /* Look up instance number */
3130 instance = I3C_GetInstance(base);
3131
3132 /* Save base and instance. */
3133 handle->callback = callback;
3134 handle->userData = userData;
3135
3136 /* Save Tx FIFO Size. */
3137 handle->txFifoSize =
3138 2U << ((base->SCAPABILITIES & I3C_SCAPABILITIES_FIFOTX_MASK) >> I3C_SCAPABILITIES_FIFOTX_SHIFT);
3139
3140 /* Save this handle for IRQ use. */
3141 s_i3cSlaveHandle[instance] = handle;
3142
3143 /* Set irq handler. */
3144 s_i3cSlaveIsr = I3C_SlaveTransferHandleIRQ;
3145
3146 /* Clear internal IRQ enables and enable NVIC IRQ. */
3147 I3C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags);
3148 (void)EnableIRQ(kI3cIrqs[instance]);
3149 }
3150
3151 /*!
3152 * brief Starts accepting slave transfers.
3153 *
3154 * Call this API after calling I2C_SlaveInit() and I3C_SlaveTransferCreateHandle() to start processing
3155 * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the
3156 * callback that was passed into the call to I3C_SlaveTransferCreateHandle(). The callback is always invoked
3157 * from the interrupt context.
3158 *
3159 * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to
3160 * the OR'd combination of #i3c_slave_transfer_event_t enumerators for the events you wish to receive.
3161 * The #kI3C_SlaveTransmitEvent and #kI3C_SlaveReceiveEvent events are always enabled and do not need
3162 * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and
3163 * receive events that are always enabled. In addition, the #kI3C_SlaveAllEvents constant is provided as
3164 * a convenient way to enable all events.
3165 *
3166 * param base The I3C peripheral base address.
3167 * param handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
3168 * param eventMask Bit mask formed by OR'ing together #i3c_slave_transfer_event_t enumerators to specify
3169 * which events to send to the callback. Other accepted values are 0 to get a default set of
3170 * only the transmit and receive events, and #kI3C_SlaveAllEvents to enable all events.
3171 *
3172 * retval #kStatus_Success Slave transfers were successfully started.
3173 * retval #kStatus_I3C_Busy Slave transfers have already been started on this handle.
3174 */
I3C_SlaveTransferNonBlocking(I3C_Type * base,i3c_slave_handle_t * handle,uint32_t eventMask)3175 status_t I3C_SlaveTransferNonBlocking(I3C_Type *base, i3c_slave_handle_t *handle, uint32_t eventMask)
3176 {
3177 assert(NULL != handle);
3178
3179 /* Return busy if another transaction is in progress. */
3180 if (handle->isBusy)
3181 {
3182 return kStatus_I3C_Busy;
3183 }
3184
3185 /* Disable I3C IRQ sources while we configure stuff. */
3186 I3C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags);
3187
3188 /* Clear transfer in handle. */
3189 (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
3190
3191 /* Set up event mask. tx and rx are always enabled. */
3192 handle->eventMask = eventMask | (uint32_t)kI3C_SlaveTransmitEvent | (uint32_t)kI3C_SlaveReceiveEvent;
3193
3194 /* Clear all flags. */
3195 I3C_SlaveClearStatusFlags(base, (uint32_t)kSlaveClearFlags);
3196
3197 /* Enable I3C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
3198 I3C_SlaveEnableInterrupts(base, (uint32_t)kSlaveIrqFlags);
3199
3200 return kStatus_Success;
3201 }
3202
3203 /*!
3204 * brief Gets the slave transfer status during a non-blocking transfer.
3205 * param base The I3C peripheral base address.
3206 * param handle Pointer to i2c_slave_handle_t structure.
3207 * param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not
3208 * required.
3209 * retval #kStatus_Success
3210 * retval #kStatus_NoTransferInProgress
3211 */
I3C_SlaveTransferGetCount(I3C_Type * base,i3c_slave_handle_t * handle,size_t * count)3212 status_t I3C_SlaveTransferGetCount(I3C_Type *base, i3c_slave_handle_t *handle, size_t *count)
3213 {
3214 assert(NULL != handle);
3215
3216 if (NULL == count)
3217 {
3218 return kStatus_InvalidArgument;
3219 }
3220
3221 /* Catch when there is not an active transfer. */
3222 if (!handle->isBusy)
3223 {
3224 *count = 0;
3225 return kStatus_NoTransferInProgress;
3226 }
3227
3228 /* For an active transfer, just return the count from the handle. */
3229 *count = handle->transferredCount;
3230
3231 return kStatus_Success;
3232 }
3233
3234 /*!
3235 * brief Aborts the slave non-blocking transfers.
3236 * note This API could be called at any time to stop slave for handling the bus events.
3237 * param base The I3C peripheral base address.
3238 * param handle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
3239 * retval #kStatus_Success
3240 * retval #kStatus_I3C_Idle
3241 */
I3C_SlaveTransferAbort(I3C_Type * base,i3c_slave_handle_t * handle)3242 void I3C_SlaveTransferAbort(I3C_Type *base, i3c_slave_handle_t *handle)
3243 {
3244 assert(NULL != handle);
3245
3246 /* Return idle if no transaction is in progress. */
3247 if (handle->isBusy)
3248 {
3249 /* Disable I3C IRQ sources. */
3250 I3C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags);
3251
3252 /* Reset transfer info. */
3253 (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
3254
3255 /* We're no longer busy. */
3256 handle->isBusy = false;
3257 }
3258 }
3259
I3C_SlaveTransferHandleGetStatusFlags(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_handleIrq_param_t * stateParams)3260 static bool I3C_SlaveTransferHandleGetStatusFlags(I3C_Type *base,
3261 i3c_slave_handle_t *handle,
3262 i3c_slave_handleIrq_param_t *stateParams)
3263 {
3264 assert(NULL != base && NULL != handle && NULL != stateParams);
3265 /* Check for a valid handle in case of a spurious interrupt. */
3266 uint32_t errFlags;
3267 stateParams->flags = I3C_SlaveGetStatusFlags(base);
3268 errFlags = I3C_SlaveGetErrorStatusFlags(base);
3269
3270 stateParams->pendingInts = I3C_SlaveGetPendingInterrupts(base);
3271 stateParams->enabledInts = I3C_SlaveGetEnabledInterrupts(base);
3272
3273 if (0UL != (errFlags & (uint32_t)kSlaveErrorFlags))
3274 {
3275 handle->transfer.event = (uint32_t)kI3C_SlaveCompletionEvent;
3276 handle->transfer.completionStatus = I3C_SlaveCheckAndClearError(base, errFlags);
3277
3278 if ((0UL != (handle->eventMask & (uint32_t)kI3C_SlaveCompletionEvent)) && (NULL != handle->callback))
3279 {
3280 handle->callback(base, &handle->transfer, handle->userData);
3281 }
3282 return false;
3283 }
3284 return true;
3285 }
3286
I3C_SlaveTransferHandleBusStart(I3C_Type * base,i3c_slave_transfer_t * xfer,uint32_t * pendingInts)3287 static void I3C_SlaveTransferHandleBusStart(I3C_Type *base, i3c_slave_transfer_t *xfer, uint32_t *pendingInts)
3288 {
3289 base->SDATACTRL |= I3C_SDATACTRL_FLUSHTB_MASK;
3290 xfer->txDataSize = 0;
3291 I3C_SlaveEnableInterrupts(base, (uint32_t)kI3C_SlaveTxReadyFlag);
3292 (*pendingInts) |= (uint32_t)kI3C_SlaveTxReadyFlag;
3293 }
3294
I3C_SlaveTransferHandleEventSent(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_transfer_t * xfer)3295 static void I3C_SlaveTransferHandleEventSent(I3C_Type *base, i3c_slave_handle_t *handle, i3c_slave_transfer_t *xfer)
3296 {
3297 xfer->event = (uint32_t)kI3C_SlaveRequestSentEvent;
3298 if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
3299 {
3300 handle->callback(base, xfer, handle->userData);
3301 }
3302 }
3303
I3C_SlaveTransferHandleReceivedCCC(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_transfer_t * xfer)3304 static void I3C_SlaveTransferHandleReceivedCCC(I3C_Type *base, i3c_slave_handle_t *handle, i3c_slave_transfer_t *xfer)
3305 {
3306 handle->isBusy = true;
3307 xfer->event = (uint32_t)kI3C_SlaveReceivedCCCEvent;
3308 if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
3309 {
3310 handle->callback(base, xfer, handle->userData);
3311 }
3312 }
3313
I3C_SlaveTransferHandleBusStop(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_handleIrq_param_t * stateParams)3314 static void I3C_SlaveTransferHandleBusStop(I3C_Type *base,
3315 i3c_slave_handle_t *handle,
3316 i3c_slave_handleIrq_param_t *stateParams)
3317 {
3318 assert(NULL != base && NULL != handle && NULL != stateParams);
3319 I3C_SlaveDisableInterrupts(base, (uint32_t)kI3C_SlaveTxReadyFlag);
3320 stateParams->pendingInts &= ~(uint32_t)kI3C_SlaveTxReadyFlag;
3321 base->SDATACTRL |= I3C_SDATACTRL_FLUSHTB_MASK | I3C_SDATACTRL_FLUSHFB_MASK;
3322 if (handle->isBusy)
3323 {
3324 handle->transfer.event = (uint32_t)kI3C_SlaveCompletionEvent;
3325 handle->transfer.completionStatus = kStatus_Success;
3326 handle->transfer.transferredCount = handle->transferredCount;
3327 handle->isBusy = false;
3328
3329 if (handle->wasTransmit)
3330 {
3331 /* Subtract one from the transmit count to offset the fact that I3C asserts the */
3332 /* tx flag before it sees the nack from the master-receiver, thus causing one more */
3333 /* count that the master actually receives. */
3334 --handle->transfer.transferredCount;
3335 handle->wasTransmit = false;
3336 }
3337
3338 if ((0UL != (handle->eventMask & handle->transfer.event)) && (NULL != handle->callback))
3339 {
3340 handle->callback(base, &handle->transfer, handle->userData);
3341 }
3342
3343 /* Clean up transfer info on completion, after the callback has been invoked. */
3344 (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
3345 }
3346 }
3347
I3C_SlaveTransferHandleMatched(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_transfer_t * xfer)3348 static void I3C_SlaveTransferHandleMatched(I3C_Type *base, i3c_slave_handle_t *handle, i3c_slave_transfer_t *xfer)
3349 {
3350 assert(NULL != base && NULL != handle && NULL != xfer);
3351 xfer->event = (uint32_t)kI3C_SlaveAddressMatchEvent;
3352 handle->isBusy = true;
3353 if ((0UL != (handle->eventMask & (uint32_t)kI3C_SlaveAddressMatchEvent)) && (NULL != handle->callback))
3354 {
3355 handle->callback(base, xfer, handle->userData);
3356 }
3357 }
3358
I3C_SlaveTransferHandleTxReady(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_handleIrq_param_t * stateParams)3359 static void I3C_SlaveTransferHandleTxReady(I3C_Type *base,
3360 i3c_slave_handle_t *handle,
3361 i3c_slave_handleIrq_param_t *stateParams)
3362 {
3363 assert(NULL != base && NULL != handle && NULL != stateParams);
3364 handle->wasTransmit = true;
3365
3366 /* If we're out of data, invoke callback to get more. */
3367 if ((NULL == handle->transfer.txData) || (0UL == handle->transfer.txDataSize))
3368 {
3369 handle->transfer.event = (uint32_t)kI3C_SlaveTransmitEvent;
3370 if (0UL != (stateParams->flags & (uint32_t)kI3C_SlaveBusHDRModeFlag))
3371 {
3372 handle->transfer.event |= (uint32_t)kI3C_SlaveHDRCommandMatchEvent;
3373 handle->isBusy = true;
3374 }
3375 if (NULL != handle->callback)
3376 {
3377 handle->callback(base, &handle->transfer, handle->userData);
3378 }
3379
3380 /* Clear the transferred count now that we have a new buffer. */
3381 handle->transferredCount = 0;
3382 }
3383
3384 if ((NULL == handle->transfer.txData) || (0UL == handle->transfer.txDataSize))
3385 {
3386 I3C_SlaveDisableInterrupts(base, (uint32_t)kI3C_SlaveTxReadyFlag);
3387 (stateParams->pendingInts) &= ~(uint32_t)kI3C_SlaveTxReadyFlag;
3388 }
3389
3390 /* Transmit a byte. */
3391 while ((handle->transfer.txDataSize != 0UL) && ((stateParams->txCount) != 0U))
3392 {
3393 if (handle->transfer.txDataSize > 1UL)
3394 {
3395 base->SWDATAB = *handle->transfer.txData++;
3396 }
3397 else
3398 {
3399 base->SWDATABE = *handle->transfer.txData++;
3400 I3C_SlaveDisableInterrupts(base, (uint32_t)kI3C_SlaveTxReadyFlag);
3401 }
3402 --(handle->transfer.txDataSize);
3403 ++(handle->transferredCount);
3404 (stateParams->txCount)--;
3405 }
3406 }
3407
I3C_SlaveTransferHandleRxReady(I3C_Type * base,i3c_slave_handle_t * handle,i3c_slave_handleIrq_param_t * stateParams)3408 static void I3C_SlaveTransferHandleRxReady(I3C_Type *base,
3409 i3c_slave_handle_t *handle,
3410 i3c_slave_handleIrq_param_t *stateParams)
3411 {
3412 assert(NULL != base && NULL != handle && NULL != stateParams);
3413 /* If we're out of room in the buffer, invoke callback to get another. */
3414 if ((NULL == handle->transfer.rxData) || (0UL == handle->transfer.rxDataSize))
3415 {
3416 handle->transfer.event = (uint32_t)kI3C_SlaveReceiveEvent;
3417 if (0UL != (stateParams->flags & (uint32_t)kI3C_SlaveBusHDRModeFlag))
3418 {
3419 handle->transfer.event |= (uint32_t)kI3C_SlaveHDRCommandMatchEvent;
3420 handle->isBusy = true;
3421 }
3422 if (NULL != handle->callback)
3423 {
3424 handle->callback(base, &handle->transfer, handle->userData);
3425 }
3426 handle->transferredCount = 0;
3427 }
3428 /* Receive a byte. */
3429 while ((stateParams->rxCount != 0U) && ((handle->transfer.rxData != NULL) && (handle->transfer.rxDataSize != 0UL)))
3430 {
3431 *(handle->transfer.rxData++) = (uint8_t)base->SRDATAB;
3432 --(handle->transfer.rxDataSize);
3433 ++(handle->transferredCount);
3434 (stateParams->rxCount)--;
3435 }
3436 }
3437
3438 /*!
3439 * brief Reusable routine to handle slave interrupts.
3440 * note This function does not need to be called unless you are reimplementing the
3441 * non blocking API's interrupt handler routines to add special functionality.
3442 * param base The I3C peripheral base address.
3443 * param intHandle Pointer to #i3c_slave_handle_t structure which stores the transfer state.
3444 */
I3C_SlaveTransferHandleIRQ(I3C_Type * base,void * intHandle)3445 void I3C_SlaveTransferHandleIRQ(I3C_Type *base, void *intHandle)
3446 {
3447 i3c_slave_handleIrq_param_t stateParams;
3448
3449 (void)memset(&stateParams, 0, sizeof(stateParams));
3450 i3c_slave_handle_t *handle = (i3c_slave_handle_t *)intHandle;
3451
3452 /* Check for a valid handle in case of a spurious interrupt. */
3453 if (NULL == handle)
3454 {
3455 return;
3456 }
3457
3458 /* Get status flags. */
3459 if (false == I3C_SlaveTransferHandleGetStatusFlags(base, handle, &stateParams))
3460 {
3461 return;
3462 }
3463
3464 /* Clear status flags. */
3465 I3C_SlaveClearStatusFlags(base, stateParams.flags);
3466
3467 if (0UL != (stateParams.flags & (uint32_t)kI3C_SlaveBusStartFlag))
3468 {
3469 I3C_SlaveTransferHandleBusStart(base, &handle->transfer, &stateParams.pendingInts);
3470 }
3471
3472 if (0UL != (stateParams.flags & (uint32_t)kI3C_SlaveEventSentFlag))
3473 {
3474 I3C_SlaveTransferHandleEventSent(base, handle, &handle->transfer);
3475 }
3476
3477 if (0UL != (stateParams.flags & (uint32_t)kI3C_SlaveReceivedCCCFlag))
3478 {
3479 I3C_SlaveTransferHandleReceivedCCC(base, handle, &handle->transfer);
3480 }
3481
3482 if (0UL != (stateParams.flags & (uint32_t)kI3C_SlaveMatchedFlag))
3483 {
3484 I3C_SlaveTransferHandleMatched(base, handle, &handle->transfer);
3485 }
3486
3487 /* Get fifo counts and compute room in tx fifo. */
3488 I3C_SlaveGetFifoCounts(base, &stateParams.rxCount, &stateParams.txCount);
3489 stateParams.txCount = handle->txFifoSize - stateParams.txCount;
3490
3491 /* Handle transmit and receive. */
3492 if ((0UL != (stateParams.flags & (uint32_t)kI3C_SlaveTxReadyFlag)) &&
3493 (0UL != (stateParams.pendingInts & (uint32_t)kI3C_SlaveTxReadyFlag)))
3494 {
3495 I3C_SlaveTransferHandleTxReady(base, handle, &stateParams);
3496 }
3497
3498 if ((0UL != (stateParams.flags & (uint32_t)kI3C_SlaveRxReadyFlag)) &&
3499 (0UL != (stateParams.enabledInts & (uint32_t)kI3C_SlaveRxReadyFlag)))
3500 {
3501 I3C_SlaveTransferHandleRxReady(base, handle, &stateParams);
3502 }
3503
3504 /* Handle stop event. */
3505 if (0UL != (stateParams.flags & (uint32_t)kI3C_SlaveBusStopFlag))
3506 {
3507 I3C_SlaveTransferHandleBusStop(base, handle, &stateParams);
3508 }
3509 }
3510
I3C_CommonIRQHandler(I3C_Type * base,uint32_t instance)3511 static void I3C_CommonIRQHandler(I3C_Type *base, uint32_t instance)
3512 {
3513 /* Check for master IRQ. */
3514 if (((uint32_t)kI3C_MasterOn == (base->MCONFIG & I3C_MCONFIG_MSTENA_MASK)) && (NULL != s_i3cMasterIsr))
3515 {
3516 /* Master mode. */
3517 s_i3cMasterIsr(base, s_i3cMasterHandle[instance]);
3518 }
3519
3520 /* Check for slave IRQ. */
3521 if ((I3C_SCONFIG_SLVENA_MASK == (base->SCONFIG & I3C_SCONFIG_SLVENA_MASK)) && (NULL != s_i3cSlaveIsr))
3522 {
3523 /* Slave mode. */
3524 s_i3cSlaveIsr(base, s_i3cSlaveHandle[instance]);
3525 }
3526 SDK_ISR_EXIT_BARRIER;
3527 }
3528
3529 #if defined(I3C)
3530 /* Implementation of I3C handler named in startup code. */
3531 void I3C0_DriverIRQHandler(void);
I3C0_DriverIRQHandler(void)3532 void I3C0_DriverIRQHandler(void)
3533 {
3534 I3C_CommonIRQHandler(I3C, 0);
3535 }
3536 #endif
3537
3538 #if defined(I3C0)
3539 /* Implementation of I3C0 handler named in startup code. */
3540 void I3C0_DriverIRQHandler(void);
I3C0_DriverIRQHandler(void)3541 void I3C0_DriverIRQHandler(void)
3542 {
3543 I3C_CommonIRQHandler(I3C0, 0);
3544 }
3545 #endif
3546
3547 #if defined(I3C1)
3548 /* Implementation of I3C1 handler named in startup code. */
3549 void I3C1_DriverIRQHandler(void);
I3C1_DriverIRQHandler(void)3550 void I3C1_DriverIRQHandler(void)
3551 {
3552 I3C_CommonIRQHandler(I3C1, 1);
3553 }
3554 #endif
3555
3556 #if defined(I3C2)
3557 /* Implementation of I3C2 handler named in startup code. */
3558 void I3C2_DriverIRQHandler(void);
I3C2_DriverIRQHandler(void)3559 void I3C2_DriverIRQHandler(void)
3560 {
3561 I3C_CommonIRQHandler(I3C2, 2);
3562 }
3563 #endif
3564
3565 #if defined(I3C3)
3566 /* Implementation of I3C3 handler named in startup code. */
3567 void I3C3_DriverIRQHandler(void);
I3C3_DriverIRQHandler(void)3568 void I3C3_DriverIRQHandler(void)
3569 {
3570 I3C_CommonIRQHandler(I3C3, 3);
3571 }
3572 #endif
3573