fsl_flexio_spi_edma.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*
  2. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2020 NXP
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include "fsl_flexio_spi_edma.h"
  9. /*******************************************************************************
  10. * Definitions
  11. ******************************************************************************/
  12. /* Component ID definition, used by tools. */
  13. #ifndef FSL_COMPONENT_ID
  14. #define FSL_COMPONENT_ID "platform.drivers.flexio_spi_edma"
  15. #endif
  16. /*<! Structure definition for spi_edma_private_handle_t. The structure is private. */
  17. typedef struct _flexio_spi_master_edma_private_handle
  18. {
  19. FLEXIO_SPI_Type *base;
  20. flexio_spi_master_edma_handle_t *handle;
  21. } flexio_spi_master_edma_private_handle_t;
  22. /*******************************************************************************
  23. * Prototypes
  24. ******************************************************************************/
  25. /*!
  26. * @brief EDMA callback function for FLEXIO SPI send transfer.
  27. *
  28. * @param handle EDMA handle pointer.
  29. * @param param Callback function parameter.
  30. */
  31. static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
  32. /*!
  33. * @brief EDMA callback function for FLEXIO SPI receive transfer.
  34. *
  35. * @param handle EDMA handle pointer.
  36. * @param param Callback function parameter.
  37. */
  38. static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
  39. /*!
  40. * @brief EDMA config for FLEXIO SPI transfer.
  41. *
  42. * @param base pointer to FLEXIO_SPI_Type structure.
  43. * @param handle pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
  44. * @param xfer Pointer to flexio spi transfer structure.
  45. */
  46. static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
  47. flexio_spi_master_edma_handle_t *handle,
  48. flexio_spi_transfer_t *xfer);
  49. /*******************************************************************************
  50. * Variables
  51. ******************************************************************************/
  52. /* Dummy data used to send */
  53. static const uint16_t s_dummyData = FLEXIO_SPI_DUMMYDATA;
  54. /*< @brief user configurable flexio spi handle count. */
  55. #define FLEXIO_SPI_HANDLE_COUNT 2
  56. /*<! Private handle only used for internally. */
  57. static flexio_spi_master_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_SPI_HANDLE_COUNT];
  58. /*******************************************************************************
  59. * Code
  60. ******************************************************************************/
  61. static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
  62. {
  63. tcds = tcds;
  64. flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
  65. /* Disable Tx DMA */
  66. if (transferDone)
  67. {
  68. FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, false);
  69. /* change the state */
  70. spiPrivateHandle->handle->txInProgress = false;
  71. /* All finished, call the callback */
  72. if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
  73. {
  74. if (spiPrivateHandle->handle->callback != NULL)
  75. {
  76. (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
  77. spiPrivateHandle->handle->userData);
  78. }
  79. }
  80. }
  81. }
  82. static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
  83. {
  84. tcds = tcds;
  85. flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
  86. if (transferDone)
  87. {
  88. /* Disable Rx dma */
  89. FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, false);
  90. /* change the state */
  91. spiPrivateHandle->handle->rxInProgress = false;
  92. /* All finished, call the callback */
  93. if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
  94. {
  95. if (spiPrivateHandle->handle->callback != NULL)
  96. {
  97. (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
  98. spiPrivateHandle->handle->userData);
  99. }
  100. }
  101. }
  102. }
  103. static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
  104. flexio_spi_master_edma_handle_t *handle,
  105. flexio_spi_transfer_t *xfer)
  106. {
  107. edma_transfer_config_t xferConfig = {0};
  108. flexio_spi_shift_direction_t direction = kFLEXIO_SPI_MsbFirst;
  109. uint8_t bytesPerFrame;
  110. /* Configure the values in handle. */
  111. switch (xfer->flags)
  112. {
  113. case (uint8_t)kFLEXIO_SPI_8bitMsb:
  114. bytesPerFrame = 1U;
  115. direction = kFLEXIO_SPI_MsbFirst;
  116. break;
  117. case (uint8_t)kFLEXIO_SPI_8bitLsb:
  118. bytesPerFrame = 1U;
  119. direction = kFLEXIO_SPI_LsbFirst;
  120. break;
  121. case (uint8_t)kFLEXIO_SPI_16bitMsb:
  122. bytesPerFrame = 2U;
  123. direction = kFLEXIO_SPI_MsbFirst;
  124. break;
  125. case (uint8_t)kFLEXIO_SPI_16bitLsb:
  126. bytesPerFrame = 2U;
  127. direction = kFLEXIO_SPI_LsbFirst;
  128. break;
  129. default:
  130. bytesPerFrame = 1U;
  131. direction = kFLEXIO_SPI_MsbFirst;
  132. assert(true);
  133. break;
  134. }
  135. /* Save total transfer size. */
  136. handle->transferSize = xfer->dataSize;
  137. /* Configure tx transfer EDMA. */
  138. xferConfig.destAddr = FLEXIO_SPI_GetTxDataRegisterAddress(base, direction);
  139. xferConfig.destOffset = 0;
  140. if (bytesPerFrame == 1U)
  141. {
  142. xferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
  143. xferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
  144. xferConfig.minorLoopBytes = 1U;
  145. }
  146. else
  147. {
  148. if (direction == kFLEXIO_SPI_MsbFirst)
  149. {
  150. xferConfig.destAddr -= 1U;
  151. }
  152. xferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
  153. xferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
  154. xferConfig.minorLoopBytes = 2U;
  155. }
  156. /* Configure DMA channel. */
  157. if (xfer->txData != NULL)
  158. {
  159. xferConfig.srcOffset = (int16_t)bytesPerFrame;
  160. xferConfig.srcAddr = (uint32_t)(xfer->txData);
  161. }
  162. else
  163. {
  164. /* Disable the source increasement and source set to dummyData. */
  165. xferConfig.srcOffset = 0;
  166. xferConfig.srcAddr = (uint32_t)(&s_dummyData);
  167. }
  168. xferConfig.majorLoopCounts = (xfer->dataSize / xferConfig.minorLoopBytes);
  169. /* Store the initially configured eDMA minor byte transfer count into the FLEXIO SPI handle */
  170. handle->nbytes = (uint8_t)xferConfig.minorLoopBytes;
  171. if (handle->txHandle != NULL)
  172. {
  173. (void)EDMA_SubmitTransfer(handle->txHandle, &xferConfig);
  174. }
  175. /* Configure rx transfer EDMA. */
  176. if (xfer->rxData != NULL)
  177. {
  178. xferConfig.srcAddr = FLEXIO_SPI_GetRxDataRegisterAddress(base, direction);
  179. if (bytesPerFrame == 2U)
  180. {
  181. if (direction == kFLEXIO_SPI_LsbFirst)
  182. {
  183. xferConfig.srcAddr -= 1U;
  184. }
  185. }
  186. xferConfig.srcOffset = 0;
  187. xferConfig.destAddr = (uint32_t)(xfer->rxData);
  188. xferConfig.destOffset = (int16_t)bytesPerFrame;
  189. (void)EDMA_SubmitTransfer(handle->rxHandle, &xferConfig);
  190. handle->rxInProgress = true;
  191. FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, true);
  192. EDMA_StartTransfer(handle->rxHandle);
  193. }
  194. /* Always start tx transfer. */
  195. if (handle->txHandle != NULL)
  196. {
  197. handle->txInProgress = true;
  198. FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, true);
  199. EDMA_StartTransfer(handle->txHandle);
  200. }
  201. }
  202. /*!
  203. * brief Initializes the FlexIO SPI master eDMA handle.
  204. *
  205. * This function initializes the FlexIO SPI master eDMA handle which can be used for other FlexIO SPI master
  206. * transactional
  207. * APIs.
  208. * For a specified FlexIO SPI instance, call this API once to get the initialized handle.
  209. *
  210. * param base Pointer to FLEXIO_SPI_Type structure.
  211. * param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
  212. * param callback SPI callback, NULL means no callback.
  213. * param userData callback function parameter.
  214. * param txHandle User requested eDMA handle for FlexIO SPI RX eDMA transfer.
  215. * param rxHandle User requested eDMA handle for FlexIO SPI TX eDMA transfer.
  216. * retval kStatus_Success Successfully create the handle.
  217. * retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
  218. */
  219. status_t FLEXIO_SPI_MasterTransferCreateHandleEDMA(FLEXIO_SPI_Type *base,
  220. flexio_spi_master_edma_handle_t *handle,
  221. flexio_spi_master_edma_transfer_callback_t callback,
  222. void *userData,
  223. edma_handle_t *txHandle,
  224. edma_handle_t *rxHandle)
  225. {
  226. assert(handle != NULL);
  227. uint8_t index = 0;
  228. /* Find the an empty handle pointer to store the handle. */
  229. for (index = 0U; index < (uint8_t)FLEXIO_SPI_HANDLE_COUNT; index++)
  230. {
  231. if (s_edmaPrivateHandle[index].base == NULL)
  232. {
  233. s_edmaPrivateHandle[index].base = base;
  234. s_edmaPrivateHandle[index].handle = handle;
  235. break;
  236. }
  237. }
  238. if (index == (uint16_t)FLEXIO_SPI_HANDLE_COUNT)
  239. {
  240. return kStatus_OutOfRange;
  241. }
  242. /* Set spi base to handle. */
  243. handle->txHandle = txHandle;
  244. handle->rxHandle = rxHandle;
  245. /* Register callback and userData. */
  246. handle->callback = callback;
  247. handle->userData = userData;
  248. /* Set SPI state to idle. */
  249. handle->txInProgress = false;
  250. handle->rxInProgress = false;
  251. /* Install callback for Tx/Rx dma channel. */
  252. if (handle->txHandle != NULL)
  253. {
  254. EDMA_SetCallback(handle->txHandle, FLEXIO_SPI_TxEDMACallback, &s_edmaPrivateHandle[index]);
  255. }
  256. if (handle->rxHandle != NULL)
  257. {
  258. EDMA_SetCallback(handle->rxHandle, FLEXIO_SPI_RxEDMACallback, &s_edmaPrivateHandle[index]);
  259. }
  260. return kStatus_Success;
  261. }
  262. /*!
  263. * brief Performs a non-blocking FlexIO SPI transfer using eDMA.
  264. *
  265. * note This interface returns immediately after transfer initiates. Call
  266. * FLEXIO_SPI_MasterGetTransferCountEDMA to poll the transfer status and check
  267. * whether the FlexIO SPI transfer is finished.
  268. *
  269. * param base Pointer to FLEXIO_SPI_Type structure.
  270. * param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
  271. * param xfer Pointer to FlexIO SPI transfer structure.
  272. * retval kStatus_Success Successfully start a transfer.
  273. * retval kStatus_InvalidArgument Input argument is invalid.
  274. * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
  275. */
  276. status_t FLEXIO_SPI_MasterTransferEDMA(FLEXIO_SPI_Type *base,
  277. flexio_spi_master_edma_handle_t *handle,
  278. flexio_spi_transfer_t *xfer)
  279. {
  280. assert(handle != NULL);
  281. assert(xfer != NULL);
  282. uint32_t dataMode = 0;
  283. uint16_t timerCmp = (uint16_t)base->flexioBase->TIMCMP[base->timerIndex[0]];
  284. timerCmp &= 0x00FFU;
  285. /* Check if the device is busy. */
  286. if ((handle->txInProgress) || (handle->rxInProgress))
  287. {
  288. return kStatus_FLEXIO_SPI_Busy;
  289. }
  290. /* Check if input parameter invalid. */
  291. if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
  292. {
  293. return kStatus_InvalidArgument;
  294. }
  295. /* configure data mode. */
  296. if ((xfer->flags == (uint8_t)kFLEXIO_SPI_8bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_8bitLsb))
  297. {
  298. dataMode = (8UL * 2UL - 1UL) << 8U;
  299. }
  300. else if ((xfer->flags == (uint8_t)kFLEXIO_SPI_16bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_16bitLsb))
  301. {
  302. dataMode = (16UL * 2UL - 1UL) << 8U;
  303. }
  304. else
  305. {
  306. dataMode = 8UL * 2UL - 1UL;
  307. }
  308. dataMode |= timerCmp;
  309. base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
  310. FLEXIO_SPI_EDMAConfig(base, handle, xfer);
  311. return kStatus_Success;
  312. }
  313. /*!
  314. * brief Gets the remaining bytes for FlexIO SPI eDMA transfer.
  315. *
  316. * param base Pointer to FLEXIO_SPI_Type structure.
  317. * param handle FlexIO SPI eDMA handle pointer.
  318. * param count Number of bytes transferred so far by the non-blocking transaction.
  319. */
  320. status_t FLEXIO_SPI_MasterTransferGetCountEDMA(FLEXIO_SPI_Type *base,
  321. flexio_spi_master_edma_handle_t *handle,
  322. size_t *count)
  323. {
  324. assert(handle != NULL);
  325. if (NULL == count)
  326. {
  327. return kStatus_InvalidArgument;
  328. }
  329. if (handle->rxInProgress)
  330. {
  331. *count =
  332. (handle->transferSize - (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(
  333. handle->rxHandle->base, handle->rxHandle->channel));
  334. }
  335. else
  336. {
  337. *count =
  338. (handle->transferSize - (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(
  339. handle->txHandle->base, handle->txHandle->channel));
  340. }
  341. return kStatus_Success;
  342. }
  343. /*!
  344. * brief Aborts a FlexIO SPI transfer using eDMA.
  345. *
  346. * param base Pointer to FLEXIO_SPI_Type structure.
  347. * param handle FlexIO SPI eDMA handle pointer.
  348. */
  349. void FLEXIO_SPI_MasterTransferAbortEDMA(FLEXIO_SPI_Type *base, flexio_spi_master_edma_handle_t *handle)
  350. {
  351. assert(handle != NULL);
  352. /* Disable dma. */
  353. EDMA_AbortTransfer(handle->txHandle);
  354. EDMA_AbortTransfer(handle->rxHandle);
  355. /* Disable DMA enable bit. */
  356. FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_DmaAllEnable, false);
  357. /* Set the handle state. */
  358. handle->txInProgress = false;
  359. handle->rxInProgress = false;
  360. }
  361. /*!
  362. * brief Performs a non-blocking FlexIO SPI transfer using eDMA.
  363. *
  364. * note This interface returns immediately after transfer initiates. Call
  365. * FLEXIO_SPI_SlaveGetTransferCountEDMA to poll the transfer status and
  366. * check whether the FlexIO SPI transfer is finished.
  367. *
  368. * param base Pointer to FLEXIO_SPI_Type structure.
  369. * param handle Pointer to flexio_spi_slave_edma_handle_t structure to store the transfer state.
  370. * param xfer Pointer to FlexIO SPI transfer structure.
  371. * retval kStatus_Success Successfully start a transfer.
  372. * retval kStatus_InvalidArgument Input argument is invalid.
  373. * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
  374. */
  375. status_t FLEXIO_SPI_SlaveTransferEDMA(FLEXIO_SPI_Type *base,
  376. flexio_spi_slave_edma_handle_t *handle,
  377. flexio_spi_transfer_t *xfer)
  378. {
  379. assert(handle != NULL);
  380. assert(xfer != NULL);
  381. uint32_t dataMode = 0U;
  382. /* Check if the device is busy. */
  383. if ((handle->txInProgress) || (handle->rxInProgress))
  384. {
  385. return kStatus_FLEXIO_SPI_Busy;
  386. }
  387. /* Check if input parameter invalid. */
  388. if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
  389. {
  390. return kStatus_InvalidArgument;
  391. }
  392. /* configure data mode. */
  393. if ((xfer->flags == (uint8_t)kFLEXIO_SPI_8bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_8bitLsb))
  394. {
  395. dataMode = 8U * 2U - 1U;
  396. }
  397. else if ((xfer->flags == (uint8_t)kFLEXIO_SPI_16bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_16bitLsb))
  398. {
  399. dataMode = 16U * 2U - 1U;
  400. }
  401. else
  402. {
  403. dataMode = 8U * 2U - 1U;
  404. }
  405. base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
  406. FLEXIO_SPI_EDMAConfig(base, handle, xfer);
  407. return kStatus_Success;
  408. }