1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2021 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_lpi2c_edma.h"
10 #include <stdlib.h>
11 #include <string.h>
12
13 /*
14 * $Coverage Justification Reference$
15 *
16 * $Justification fsl_lpi2c_edma_c_ref_1$
17 * Need multiple master and slave modules on bus to simulate the true branch
18 *
19 * $Justification fsl_lpi2c_edma_c_ref_2$
20 * FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(X) is a constant.
21 *
22 */
23
24 /*******************************************************************************
25 * Definitions
26 ******************************************************************************/
27
28 /* Component ID definition, used by tools. */
29 #ifndef FSL_COMPONENT_ID
30 #define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
31 #endif
32
33 /* @brief Mask to align an address to 32 bytes. */
34 #define ALIGN_32_MASK (0x1fU)
35
36 /* ! @brief LPI2C master fifo commands. */
37 enum _lpi2c_master_fifo_cmd
38 {
39 kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
40 kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
41 kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
42 kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
43 };
44
45 /*! @brief States for the state machine used by transactional APIs. */
46 enum _lpi2c_transfer_states
47 {
48 kIdleState = 0,
49 kSendCommandState,
50 kIssueReadCommandState,
51 kTransferDataState,
52 kStopState,
53 kWaitForCompletionState,
54 };
55
56 /*! @brief Typedef for interrupt handler. */
57 typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
58
59 /*******************************************************************************
60 * Prototypes
61 ******************************************************************************/
62
63 /*!
64 * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
65 * @param handle Master DMA driver handle.
66 * @return Number of command words.
67 */
68 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
69
70 /*!
71 * @brief DMA completion callback.
72 * @param dmaHandle DMA channel handle for the channel that completed.
73 * @param userData User data associated with the channel handle. For this callback, the user data is the
74 * LPI2C DMA driver handle.
75 * @param isTransferDone Whether the DMA transfer has completed.
76 * @param tcds Number of TCDs that completed.
77 */
78 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
79
80 /*!
81 * @brief LPI2C master edma transfer IRQ handle routine.
82 *
83 * This API handles the LPI2C bus error status and invoke callback if needed.
84 *
85 * @param base The LPI2C peripheral base address.
86 * @param lpi2cMasterEdmaHandle Pointer to the LPI2C master edma handle.
87 */
88 static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle);
89 /*******************************************************************************
90 * Variables
91 ******************************************************************************/
92
93 static uint32_t lpi2c_edma_RecSetting = 0x02;
94
95 /*******************************************************************************
96 * Code
97 ******************************************************************************/
98
99 /*!
100 * brief Create a new handle for the LPI2C master DMA APIs.
101 *
102 * The creation of a handle is for use with the DMA APIs. Once a handle
103 * is created, there is not a corresponding destroy handle. If the user wants to
104 * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
105 *
106 * For devices where the LPI2C send and receive DMA requests are OR'd together, the a txDmaHandle
107 * parameter is ignored and may be set to NULL.
108 *
109 * param base The LPI2C peripheral base address.
110 * param[out] handle Pointer to the LPI2C master driver handle.
111 * param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
112 * param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
113 * param callback User provided pointer to the asynchronous callback function.
114 * param userData User provided pointer to the application callback data.
115 */
LPI2C_MasterCreateEDMAHandle(LPI2C_Type * base,lpi2c_master_edma_handle_t * handle,edma_handle_t * rxDmaHandle,edma_handle_t * txDmaHandle,lpi2c_master_edma_transfer_callback_t callback,void * userData)116 void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
117 lpi2c_master_edma_handle_t *handle,
118 edma_handle_t *rxDmaHandle,
119 edma_handle_t *txDmaHandle,
120 lpi2c_master_edma_transfer_callback_t callback,
121 void *userData)
122 {
123 assert(handle != NULL);
124 assert(rxDmaHandle != NULL);
125 assert(txDmaHandle != NULL);
126
127 /* Look up instance number */
128 uint32_t instance = LPI2C_GetInstance(base);
129
130 /* Clear out the handle. */
131 (void)memset(handle, 0, sizeof(*handle));
132
133 /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
134 /* in order to make the transfer API code simpler. */
135 handle->base = base;
136 handle->completionCallback = callback;
137 handle->userData = userData;
138 handle->rx = rxDmaHandle;
139 handle->tx = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
140
141 /* Save the handle in global variables to support the double weak mechanism. */
142 s_lpi2cMasterHandle[instance] = handle;
143
144 /* Set LPI2C_MasterTransferEdmaHandleIRQ as LPI2C DMA IRQ handler */
145 s_lpi2cMasterIsr = LPI2C_MasterTransferEdmaHandleIRQ;
146
147 /* Enable interrupt in NVIC. */
148 (void)EnableIRQ(kLpi2cIrqs[instance]);
149
150 /* Set DMA channel completion callbacks. */
151 EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
152 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
153 {
154 EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
155 }
156 }
157
LPI2C_GenerateCommands(lpi2c_master_edma_handle_t * handle)158 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
159 {
160 lpi2c_master_transfer_t *xfer = &handle->transfer;
161 uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
162 uint32_t cmdCount = 0;
163
164 /* Handle no start option. */
165 if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
166 {
167 if (xfer->direction == kLPI2C_Read)
168 {
169 /* Need to issue read command first. */
170 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
171 }
172 }
173 else
174 {
175 /*
176 * Initial direction depends on whether a subaddress was provided, and of course the actual
177 * data transfer direction.
178 */
179 lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
180
181 /* Start command. */
182 cmd[cmdCount++] =
183 (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
184
185 /* Subaddress, MSB first. */
186 if (xfer->subaddressSize != 0U)
187 {
188 uint32_t subaddressRemaining = xfer->subaddressSize;
189 while (0U != subaddressRemaining--)
190 {
191 uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
192 cmd[cmdCount++] = subaddressByte;
193 }
194 }
195
196 /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
197 if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
198 {
199 /* Need to send repeated start if switching directions to read. */
200 if (direction == kLPI2C_Write)
201 {
202 cmd[cmdCount++] = (uint16_t)kStartCmd |
203 (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
204 }
205
206 /* Read command. A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when
207 the dataSize is larger than 0x100U, push multiple read commands to MTDR until dataSize is reached. */
208 size_t tmpRxSize = xfer->dataSize;
209 while (tmpRxSize != 0U)
210 {
211 if (tmpRxSize > 256U)
212 {
213 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(0xFFU);
214 tmpRxSize -= 256U;
215 }
216 else
217 {
218 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
219 tmpRxSize = 0U;
220 }
221 }
222 }
223 }
224
225 return cmdCount;
226 }
227
228 /*!
229 * brief Performs a non-blocking DMA-based transaction on the I2C bus.
230 *
231 * The callback specified when the a handle was created is invoked when the transaction has
232 * completed.
233 *
234 * param base The LPI2C peripheral base address.
235 * param handle Pointer to the LPI2C master driver handle.
236 * param transfer The pointer to the transfer descriptor.
237 * retval #kStatus_Success The transaction was started successfully.
238 * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
239 * transaction is already in progress.
240 */
LPI2C_MasterTransferEDMA(LPI2C_Type * base,lpi2c_master_edma_handle_t * handle,lpi2c_master_transfer_t * transfer)241 status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
242 lpi2c_master_edma_handle_t *handle,
243 lpi2c_master_transfer_t *transfer)
244 {
245 status_t result;
246
247 assert(handle != NULL);
248 assert(transfer != NULL);
249 assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
250
251 /* Check transfer data size in read operation. */
252 /* A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when the dataSize is larger
253 than 0x100U, push multiple read commands to MTDR until dataSize is reached. LPI2C edma transfer uses linked
254 descriptor to transfer command and data, the command buffer is stored in handle. Allocate 4 command words to
255 carry read command which can cover nearly all use cases. */
256 if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > (256U * 4U)))
257 {
258 return kStatus_InvalidArgument;
259 }
260
261 /* Return busy if another transaction is in progress. */
262 if (handle->isBusy)
263 {
264 return kStatus_LPI2C_Busy;
265 }
266
267 /* Enable the master function and disable the slave function. */
268 LPI2C_MasterEnable(base, true);
269 LPI2C_SlaveEnable(base, false);
270
271 /* Return an error if the bus is already in use not by us. */
272 result = LPI2C_CheckForBusyBus(base);
273 /*
274 * $Branch Coverage Justification$
275 * $ref fsl_lpi2c_edma_c_ref_1$
276 */
277 if (result != kStatus_Success)
278 {
279 return result;
280 }
281
282 /* We're now busy. */
283 handle->isBusy = true;
284
285 /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
286 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
287 LPI2C_MasterEnableDMA(base, false, false);
288
289 /* Clear all flags. */
290 LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
291
292 /* Save transfer into handle. */
293 handle->transfer = *transfer;
294
295 /* Generate commands to send. */
296 uint32_t commandCount = LPI2C_GenerateCommands(handle);
297
298 /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
299 if ((0U == commandCount) && (transfer->dataSize == 0U))
300 {
301 if (handle->completionCallback != NULL)
302 {
303 handle->completionCallback(base, handle, kStatus_Success, handle->userData);
304 }
305 return kStatus_Success;
306 }
307
308 /* Reset DMA channels. */
309 EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
310 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
311 {
312 EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
313 }
314
315 /* Get a 32-byte aligned TCD pointer. */
316 edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
317
318 bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
319 bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
320
321 edma_transfer_config_t transferConfig = {0};
322 edma_tcd_t *linkTcd = NULL;
323
324 /* Set up data transmit. */
325 if (hasSendData)
326 {
327 uint32_t *srcAddr = (uint32_t *)transfer->data;
328 transferConfig.srcAddr = (uint32_t)srcAddr;
329 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
330 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
331 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
332 transferConfig.srcOffset = (int16_t)sizeof(uint8_t);
333 transferConfig.destOffset = 0;
334 transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to fill fifo */
335 transferConfig.majorLoopCounts = transfer->dataSize;
336
337 /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
338 handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
339
340 if (commandCount != 0U)
341 {
342 /* Create a software TCD, which will be chained after the commands. */
343 EDMA_TcdReset(tcd);
344 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
345 EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
346 linkTcd = tcd;
347 }
348 else
349 {
350 /* User is only transmitting data with no required commands, so this transfer can stand alone. */
351 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
352 EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
353 }
354 }
355 else if (hasReceiveData)
356 {
357 uint32_t *srcAddr = (uint32_t *)transfer->data;
358 /* Set up data receive. */
359 transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
360 transferConfig.destAddr = (uint32_t)srcAddr;
361 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
362 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
363 transferConfig.srcOffset = 0;
364 transferConfig.destOffset = (int16_t)sizeof(uint8_t);
365 transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to empty fifo */
366 transferConfig.majorLoopCounts = transfer->dataSize;
367
368 /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
369 handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
370
371 if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
372 {
373 /* We can put this receive transfer on its own DMA channel. */
374 EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
375 EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
376 }
377 else
378 {
379 /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
380 enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
381 and create another software TCD of transfering data and chain it onto the last TCD.
382 Notice that in this situation assume tx/rx uses same channel */
383 EDMA_TcdReset(tcd);
384 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
385 EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
386
387 transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
388 transferConfig.destAddr = (uint32_t) & (base->MDER);
389 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
390 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
391 transferConfig.srcOffset = 0;
392 transferConfig.destOffset = (int16_t)sizeof(uint8_t);
393 transferConfig.minorLoopBytes = sizeof(uint8_t);
394 transferConfig.majorLoopCounts = 1;
395
396 edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
397
398 EDMA_TcdReset(tcdSetRxClearTxDMA);
399 EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
400 linkTcd = tcdSetRxClearTxDMA;
401 }
402 }
403 else
404 {
405 /* No data to send */
406 }
407
408 /* Set up commands transfer. */
409 if (commandCount != 0U)
410 {
411 transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
412 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
413 transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
414 transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
415 transferConfig.srcOffset = (int16_t)sizeof(uint16_t);
416 transferConfig.destOffset = 0;
417 transferConfig.minorLoopBytes = sizeof(uint16_t); /* TODO optimize to fill fifo */
418 transferConfig.majorLoopCounts = commandCount;
419
420 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
421 }
422
423 /* Start DMA transfer. */
424 /*
425 * $Branch Coverage Justification$
426 * $ref fsl_lpi2c_edma_c_ref_2$
427 */
428 if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
429 {
430 EDMA_StartTransfer(handle->rx);
431 }
432 /*
433 * $Branch Coverage Justification$
434 * $ref fsl_lpi2c_edma_c_ref_2$
435 */
436 if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
437 {
438 EDMA_StartTransfer(handle->tx);
439 }
440
441 /* Enable DMA in both directions. This actually kicks of the transfer. */
442 LPI2C_MasterEnableDMA(base, true, true);
443
444 /* Enable all LPI2C master interrupts */
445 LPI2C_MasterEnableInterrupts(base,
446 (uint32_t)kLPI2C_MasterArbitrationLostFlag | (uint32_t)kLPI2C_MasterNackDetectFlag |
447 (uint32_t)kLPI2C_MasterPinLowTimeoutFlag | (uint32_t)kLPI2C_MasterFifoErrFlag);
448
449 return result;
450 }
451
452 /*!
453 * brief Returns number of bytes transferred so far.
454 *
455 * param base The LPI2C peripheral base address.
456 * param handle Pointer to the LPI2C master driver handle.
457 * param[out] count Number of bytes transferred so far by the non-blocking transaction.
458 * retval #kStatus_Success
459 * retval #kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
460 */
LPI2C_MasterTransferGetCountEDMA(LPI2C_Type * base,lpi2c_master_edma_handle_t * handle,size_t * count)461 status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
462 {
463 assert(handle != NULL);
464
465 if (NULL == count)
466 {
467 return kStatus_InvalidArgument;
468 }
469
470 /* Catch when there is not an active transfer. */
471 if (!handle->isBusy)
472 {
473 *count = 0;
474 return kStatus_NoTransferInProgress;
475 }
476
477 uint32_t remaining = handle->transfer.dataSize;
478
479 /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
480 /* we do nothing and return the number of transferred bytes as zero. */
481 if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
482 {
483 if (handle->transfer.direction == kLPI2C_Write)
484 {
485 remaining =
486 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
487 }
488 else
489 {
490 remaining =
491 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
492 }
493 }
494
495 *count = handle->transfer.dataSize - remaining;
496
497 return kStatus_Success;
498 }
499
500 /*!
501 * brief Terminates a non-blocking LPI2C master transmission early.
502 *
503 * note It is not safe to call this function from an IRQ handler that has a higher priority than the
504 * eDMA peripheral's IRQ priority.
505 *
506 * param base The LPI2C peripheral base address.
507 * param handle Pointer to the LPI2C master driver handle.
508 * retval #kStatus_Success A transaction was successfully aborted.
509 * retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
510 */
LPI2C_MasterTransferAbortEDMA(LPI2C_Type * base,lpi2c_master_edma_handle_t * handle)511 status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
512 {
513 /* Catch when there is not an active transfer. */
514 if (!handle->isBusy)
515 {
516 return kStatus_LPI2C_Idle;
517 }
518
519 /* Terminate DMA transfers. */
520 EDMA_AbortTransfer(handle->rx);
521 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
522 {
523 EDMA_AbortTransfer(handle->tx);
524 }
525
526 /* Reset fifos. */
527 base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
528
529 /* Disable LPI2C interrupts. */
530 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
531
532 /* If master is still busy and has not send out stop signal yet. */
533 if ((LPI2C_MasterGetStatusFlags(base) &
534 ((uint32_t)kLPI2C_MasterStopDetectFlag | (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
535 {
536 /* Send a stop command to finalize the transfer. */
537 base->MTDR = (uint32_t)kStopCmd;
538 }
539
540 /* Reset handle. */
541 handle->isBusy = false;
542
543 return kStatus_Success;
544 }
545
LPI2C_MasterEDMACallback(edma_handle_t * dmaHandle,void * userData,bool isTransferDone,uint32_t tcds)546 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
547 {
548 lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
549
550 if (NULL == handle)
551 {
552 return;
553 }
554
555 /* Check for errors. */
556 status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
557
558 /* Done with this transaction. */
559 handle->isBusy = false;
560
561 if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
562 {
563 /* Send a stop command to finalize the transfer. */
564 handle->base->MTDR = (uint32_t)kStopCmd;
565 }
566
567 /* Invoke callback. */
568 if (handle->completionCallback != NULL)
569 {
570 handle->completionCallback(handle->base, handle, result, handle->userData);
571 }
572 }
573
LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type * base,void * lpi2cMasterEdmaHandle)574 static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle)
575 {
576 assert(lpi2cMasterEdmaHandle != NULL);
577
578 lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)lpi2cMasterEdmaHandle;
579 uint32_t status = LPI2C_MasterGetStatusFlags(base);
580 status_t result = kStatus_Success;
581
582 /* Terminate DMA transfers. */
583 EDMA_AbortTransfer(handle->rx);
584 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
585 {
586 EDMA_AbortTransfer(handle->tx);
587 }
588
589 /* Done with this transaction. */
590 handle->isBusy = false;
591
592 /* Disable LPI2C interrupts. */
593 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
594
595 /* Check error status */
596 if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
597 {
598 result = kStatus_LPI2C_PinLowTimeout;
599 }
600 /*
601 * $Branch Coverage Justification$
602 * $ref fsl_lpi2c_edma_c_ref_1$
603 */
604 else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
605 {
606 result = kStatus_LPI2C_ArbitrationLost;
607 }
608 else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
609 {
610 result = kStatus_LPI2C_Nak;
611 }
612 else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
613 {
614 result = kStatus_LPI2C_FifoError;
615 }
616 else
617 {
618 ; /* Intentional empty */
619 }
620
621 /* Clear error status. */
622 (void)LPI2C_MasterCheckAndClearError(base, status);
623
624 /* Send stop flag if needed */
625 if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
626 {
627 status = LPI2C_MasterGetStatusFlags(base);
628 /* If bus is still busy and the master has not generate stop flag */
629 if ((status & ((uint32_t)kLPI2C_MasterBusBusyFlag | (uint32_t)kLPI2C_MasterStopDetectFlag)) ==
630 (uint32_t)kLPI2C_MasterBusBusyFlag)
631 {
632 /* Send a stop command to finalize the transfer. */
633 handle->base->MTDR = (uint32_t)kStopCmd;
634 }
635 }
636
637 /* Invoke callback. */
638 if (handle->completionCallback != NULL)
639 {
640 handle->completionCallback(base, handle, result, handle->userData);
641 }
642 }
643