File indexing completed on 2025-05-11 08:23:00
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "fsl_lpi2c_edma.h"
0010 #include <stdlib.h>
0011 #include <string.h>
0012
0013
0014
0015
0016
0017
0018 #ifndef FSL_COMPONENT_ID
0019 #define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
0020 #endif
0021
0022
0023 #define ALIGN_32_MASK (0x1fU)
0024
0025
0026 enum _lpi2c_master_fifo_cmd
0027 {
0028 kTxDataCmd = LPI2C_MTDR_CMD(0x0U),
0029 kRxDataCmd = LPI2C_MTDR_CMD(0X1U),
0030 kStopCmd = LPI2C_MTDR_CMD(0x2U),
0031 kStartCmd = LPI2C_MTDR_CMD(0x4U),
0032 };
0033
0034
0035 enum _lpi2c_transfer_states
0036 {
0037 kIdleState = 0,
0038 kSendCommandState,
0039 kIssueReadCommandState,
0040 kTransferDataState,
0041 kStopState,
0042 kWaitForCompletionState,
0043 };
0044
0045
0046 typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle);
0078
0079
0080
0081
0082 static uint32_t lpi2c_edma_RecSetting = 0x02;
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
0106 lpi2c_master_edma_handle_t *handle,
0107 edma_handle_t *rxDmaHandle,
0108 edma_handle_t *txDmaHandle,
0109 lpi2c_master_edma_transfer_callback_t callback,
0110 void *userData)
0111 {
0112 assert(handle != NULL);
0113 assert(rxDmaHandle != NULL);
0114 assert(txDmaHandle != NULL);
0115
0116
0117 uint32_t instance = LPI2C_GetInstance(base);
0118
0119
0120 (void)memset(handle, 0, sizeof(*handle));
0121
0122
0123
0124 handle->base = base;
0125 handle->completionCallback = callback;
0126 handle->userData = userData;
0127 handle->rx = rxDmaHandle;
0128 handle->tx = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
0129
0130
0131 s_lpi2cMasterHandle[instance] = handle;
0132
0133
0134 s_lpi2cMasterIsr = LPI2C_MasterTransferEdmaHandleIRQ;
0135
0136
0137 (void)EnableIRQ(kLpi2cIrqs[instance]);
0138
0139
0140 EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
0141 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0142 {
0143 EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
0144 }
0145 }
0146
0147 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
0148 {
0149 lpi2c_master_transfer_t *xfer = &handle->transfer;
0150 uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
0151 uint32_t cmdCount = 0;
0152
0153
0154 if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
0155 {
0156 if (xfer->direction == kLPI2C_Read)
0157 {
0158
0159 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
0160 }
0161 }
0162 else
0163 {
0164
0165
0166
0167
0168 lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
0169
0170
0171 cmd[cmdCount++] =
0172 (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
0173
0174
0175 if (xfer->subaddressSize != 0U)
0176 {
0177 uint32_t subaddressRemaining = xfer->subaddressSize;
0178 while (0U != subaddressRemaining--)
0179 {
0180 uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
0181 cmd[cmdCount++] = subaddressByte;
0182 }
0183 }
0184
0185
0186 if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
0187 {
0188
0189 if (direction == kLPI2C_Write)
0190 {
0191 cmd[cmdCount++] = (uint16_t)kStartCmd |
0192 (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
0193 }
0194
0195
0196
0197 size_t tmpRxSize = xfer->dataSize;
0198 while (tmpRxSize != 0U)
0199 {
0200 if (tmpRxSize > 256U)
0201 {
0202 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(0xFFU);
0203 tmpRxSize -= 256U;
0204 }
0205 else
0206 {
0207 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
0208 tmpRxSize = 0U;
0209 }
0210 }
0211 }
0212 }
0213
0214 return cmdCount;
0215 }
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
0231 lpi2c_master_edma_handle_t *handle,
0232 lpi2c_master_transfer_t *transfer)
0233 {
0234 status_t result;
0235
0236 assert(handle != NULL);
0237 assert(transfer != NULL);
0238 assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
0239
0240
0241
0242
0243
0244
0245 if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > (256U * 4U)))
0246 {
0247 return kStatus_InvalidArgument;
0248 }
0249
0250
0251 if (handle->isBusy)
0252 {
0253 return kStatus_LPI2C_Busy;
0254 }
0255
0256
0257 LPI2C_MasterEnable(base, true);
0258 LPI2C_SlaveEnable(base, false);
0259
0260
0261 result = LPI2C_CheckForBusyBus(base);
0262 if (result != kStatus_Success)
0263 {
0264 return result;
0265 }
0266
0267
0268 handle->isBusy = true;
0269
0270
0271 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
0272 LPI2C_MasterEnableDMA(base, false, false);
0273
0274
0275 LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
0276
0277
0278 handle->transfer = *transfer;
0279
0280
0281 uint32_t commandCount = LPI2C_GenerateCommands(handle);
0282
0283
0284 if ((0U == commandCount) && (transfer->dataSize == 0U))
0285 {
0286 if (handle->completionCallback != NULL)
0287 {
0288 handle->completionCallback(base, handle, kStatus_Success, handle->userData);
0289 }
0290 return kStatus_Success;
0291 }
0292
0293
0294 EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
0295 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0296 {
0297 EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
0298 }
0299
0300
0301 edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
0302
0303 bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
0304 bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
0305
0306 edma_transfer_config_t transferConfig = {0};
0307 edma_tcd_t *linkTcd = NULL;
0308
0309
0310 if (hasSendData)
0311 {
0312 uint32_t *srcAddr = (uint32_t *)transfer->data;
0313 transferConfig.srcAddr = (uint32_t)srcAddr;
0314 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
0315 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
0316 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
0317 transferConfig.srcOffset = (int16_t)sizeof(uint8_t);
0318 transferConfig.destOffset = 0;
0319 transferConfig.minorLoopBytes = sizeof(uint8_t);
0320 transferConfig.majorLoopCounts = transfer->dataSize;
0321
0322
0323 handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
0324
0325 if (commandCount != 0U)
0326 {
0327
0328 EDMA_TcdReset(tcd);
0329 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
0330 EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
0331 linkTcd = tcd;
0332 }
0333 else
0334 {
0335
0336 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
0337 EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
0338 }
0339 }
0340 else if (hasReceiveData)
0341 {
0342 uint32_t *srcAddr = (uint32_t *)transfer->data;
0343
0344 transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
0345 transferConfig.destAddr = (uint32_t)srcAddr;
0346 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
0347 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
0348 transferConfig.srcOffset = 0;
0349 transferConfig.destOffset = (int16_t)sizeof(uint8_t);
0350 transferConfig.minorLoopBytes = sizeof(uint8_t);
0351 transferConfig.majorLoopCounts = transfer->dataSize;
0352
0353
0354 handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
0355
0356 if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
0357 {
0358
0359 EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
0360 EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
0361 }
0362 else
0363 {
0364
0365
0366
0367
0368 EDMA_TcdReset(tcd);
0369 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
0370 EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
0371
0372 transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
0373 transferConfig.destAddr = (uint32_t) & (base->MDER);
0374 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
0375 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
0376 transferConfig.srcOffset = 0;
0377 transferConfig.destOffset = (int16_t)sizeof(uint8_t);
0378 transferConfig.minorLoopBytes = sizeof(uint8_t);
0379 transferConfig.majorLoopCounts = 1;
0380
0381 edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
0382
0383 EDMA_TcdReset(tcdSetRxClearTxDMA);
0384 EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
0385 linkTcd = tcdSetRxClearTxDMA;
0386 }
0387 }
0388 else
0389 {
0390
0391 }
0392
0393
0394 if (commandCount != 0U)
0395 {
0396 transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
0397 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
0398 transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
0399 transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
0400 transferConfig.srcOffset = (int16_t)sizeof(uint16_t);
0401 transferConfig.destOffset = 0;
0402 transferConfig.minorLoopBytes = sizeof(uint16_t);
0403 transferConfig.majorLoopCounts = commandCount;
0404
0405 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
0406 }
0407
0408
0409 if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
0410 {
0411 EDMA_StartTransfer(handle->rx);
0412 }
0413
0414 if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
0415 {
0416 EDMA_StartTransfer(handle->tx);
0417 }
0418
0419
0420 LPI2C_MasterEnableDMA(base, true, true);
0421
0422
0423 LPI2C_MasterEnableInterrupts(base,
0424 (uint32_t)kLPI2C_MasterArbitrationLostFlag | (uint32_t)kLPI2C_MasterNackDetectFlag |
0425 (uint32_t)kLPI2C_MasterPinLowTimeoutFlag | (uint32_t)kLPI2C_MasterFifoErrFlag);
0426
0427 return result;
0428 }
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439 status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
0440 {
0441 assert(handle != NULL);
0442
0443 if (NULL == count)
0444 {
0445 return kStatus_InvalidArgument;
0446 }
0447
0448
0449 if (!handle->isBusy)
0450 {
0451 *count = 0;
0452 return kStatus_NoTransferInProgress;
0453 }
0454
0455 uint32_t remaining = handle->transfer.dataSize;
0456
0457
0458
0459 if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
0460 {
0461 if (handle->transfer.direction == kLPI2C_Write)
0462 {
0463 remaining =
0464 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
0465 }
0466 else
0467 {
0468 remaining =
0469 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
0470 }
0471 }
0472
0473 *count = handle->transfer.dataSize - remaining;
0474
0475 return kStatus_Success;
0476 }
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489 status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
0490 {
0491
0492 if (!handle->isBusy)
0493 {
0494 return kStatus_LPI2C_Idle;
0495 }
0496
0497
0498 EDMA_AbortTransfer(handle->rx);
0499 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0500 {
0501 EDMA_AbortTransfer(handle->tx);
0502 }
0503
0504
0505 base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
0506
0507
0508 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
0509
0510
0511 if ((LPI2C_MasterGetStatusFlags(base) &
0512 ((uint32_t)kLPI2C_MasterStopDetectFlag | (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
0513 {
0514
0515 base->MTDR = (uint32_t)kStopCmd;
0516 }
0517
0518
0519 handle->isBusy = false;
0520
0521 return kStatus_Success;
0522 }
0523
0524 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
0525 {
0526 lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
0527
0528 if (NULL == handle)
0529 {
0530 return;
0531 }
0532
0533
0534 status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
0535
0536
0537 handle->isBusy = false;
0538
0539 if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
0540 {
0541
0542 handle->base->MTDR = (uint32_t)kStopCmd;
0543 }
0544
0545
0546 if (handle->completionCallback != NULL)
0547 {
0548 handle->completionCallback(handle->base, handle, result, handle->userData);
0549 }
0550 }
0551
0552 static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle)
0553 {
0554 assert(lpi2cMasterEdmaHandle != NULL);
0555
0556 lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)lpi2cMasterEdmaHandle;
0557 uint32_t status = LPI2C_MasterGetStatusFlags(base);
0558 status_t result = kStatus_Success;
0559
0560
0561 EDMA_AbortTransfer(handle->rx);
0562 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0563 {
0564 EDMA_AbortTransfer(handle->tx);
0565 }
0566
0567
0568 handle->isBusy = false;
0569
0570
0571 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
0572
0573
0574 if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
0575 {
0576 result = kStatus_LPI2C_PinLowTimeout;
0577 }
0578 else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
0579 {
0580 result = kStatus_LPI2C_ArbitrationLost;
0581 }
0582 else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
0583 {
0584 result = kStatus_LPI2C_Nak;
0585 }
0586 else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
0587 {
0588 result = kStatus_LPI2C_FifoError;
0589 }
0590 else
0591 {
0592 ;
0593 }
0594
0595
0596 (void)LPI2C_MasterCheckAndClearError(base, status);
0597
0598
0599 if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
0600 {
0601 status = LPI2C_MasterGetStatusFlags(base);
0602
0603 if ((status & ((uint32_t)kLPI2C_MasterBusBusyFlag | (uint32_t)kLPI2C_MasterStopDetectFlag)) ==
0604 (uint32_t)kLPI2C_MasterBusBusyFlag)
0605 {
0606
0607 handle->base->MTDR = (uint32_t)kStopCmd;
0608 }
0609 }
0610
0611
0612 if (handle->completionCallback != NULL)
0613 {
0614 handle->completionCallback(base, handle, result, handle->userData);
0615 }
0616 }