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