fsl_flexio_i2s_edma.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*
  2. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2019 NXP
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include "fsl_flexio_i2s_edma.h"
  9. /* Component ID definition, used by tools. */
  10. #ifndef FSL_COMPONENT_ID
  11. #define FSL_COMPONENT_ID "platform.drivers.flexio_i2s_edma"
  12. #endif
  13. /*******************************************************************************
  14. * Definitations
  15. ******************************************************************************/
  16. /* Used for 32byte aligned */
  17. #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
  18. /*<! Structure definition for flexio_i2s_edma_private_handle_t. The structure is private. */
  19. typedef struct _flexio_i2s_edma_private_handle
  20. {
  21. FLEXIO_I2S_Type *base;
  22. flexio_i2s_edma_handle_t *handle;
  23. } flexio_i2s_edma_private_handle_t;
  24. /*!@brief _flexio_i2s_edma_transfer_state */
  25. enum
  26. {
  27. kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO I2S is busy */
  28. kFLEXIO_I2S_Idle, /*!< Transfer is done. */
  29. };
  30. /*<! Private handle only used for internally. */
  31. static flexio_i2s_edma_private_handle_t s_edmaPrivateHandle[2];
  32. /*******************************************************************************
  33. * Prototypes
  34. ******************************************************************************/
  35. /*!
  36. * @brief FLEXIO I2S EDMA callback for send.
  37. *
  38. * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
  39. * @param userData Parameter for user callback.
  40. * @param done If the DMA transfer finished.
  41. * @param tcds The TCD index.
  42. */
  43. static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  44. /*!
  45. * @brief FLEXIO I2S EDMA callback for receive.
  46. *
  47. * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
  48. * @param userData Parameter for user callback.
  49. * @param done If the DMA transfer finished.
  50. * @param tcds The TCD index.
  51. */
  52. static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  53. /*******************************************************************************
  54. * Code
  55. ******************************************************************************/
  56. static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  57. {
  58. flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
  59. flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
  60. /* If finished a block, call the callback function */
  61. (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
  62. flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  63. if (flexio_i2sHandle->callback != NULL)
  64. {
  65. (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
  66. }
  67. /* If all data finished, just stop the transfer */
  68. if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
  69. {
  70. FLEXIO_I2S_TransferAbortSendEDMA(privHandle->base, flexio_i2sHandle);
  71. }
  72. }
  73. static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  74. {
  75. flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
  76. flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
  77. /* If finished a block, call the callback function */
  78. (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
  79. flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  80. if (flexio_i2sHandle->callback != NULL)
  81. {
  82. (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
  83. }
  84. /* If all data finished, just stop the transfer */
  85. if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
  86. {
  87. FLEXIO_I2S_TransferAbortReceiveEDMA(privHandle->base, flexio_i2sHandle);
  88. }
  89. }
  90. /*!
  91. * brief Initializes the FlexIO I2S eDMA handle.
  92. *
  93. * This function initializes the FlexIO I2S master DMA handle which can be used for other FlexIO I2S master
  94. * transactional APIs.
  95. * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
  96. *
  97. * param base FlexIO I2S peripheral base address.
  98. * param handle FlexIO I2S eDMA handle pointer.
  99. * param callback FlexIO I2S eDMA callback function called while finished a block.
  100. * param userData User parameter for callback.
  101. * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
  102. */
  103. void FLEXIO_I2S_TransferTxCreateHandleEDMA(FLEXIO_I2S_Type *base,
  104. flexio_i2s_edma_handle_t *handle,
  105. flexio_i2s_edma_callback_t callback,
  106. void *userData,
  107. edma_handle_t *dmaHandle)
  108. {
  109. assert((handle != NULL) && (dmaHandle != NULL));
  110. /* Zero the handle. */
  111. (void)memset(handle, 0, sizeof(*handle));
  112. /* Set flexio_i2s base to handle */
  113. handle->dmaHandle = dmaHandle;
  114. handle->callback = callback;
  115. handle->userData = userData;
  116. /* Set FLEXIO I2S state to idle */
  117. handle->state = (uint32_t)kFLEXIO_I2S_Idle;
  118. s_edmaPrivateHandle[0].base = base;
  119. s_edmaPrivateHandle[0].handle = handle;
  120. /* Need to use scatter gather */
  121. EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
  122. /* Install callback for Tx dma channel */
  123. EDMA_SetCallback(dmaHandle, FLEXIO_I2S_TxEDMACallback, &s_edmaPrivateHandle[0]);
  124. }
  125. /*!
  126. * brief Initializes the FlexIO I2S Rx eDMA handle.
  127. *
  128. * This function initializes the FlexIO I2S slave DMA handle which can be used for other FlexIO I2S master transactional
  129. * APIs.
  130. * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
  131. *
  132. * param base FlexIO I2S peripheral base address.
  133. * param handle FlexIO I2S eDMA handle pointer.
  134. * param callback FlexIO I2S eDMA callback function called while finished a block.
  135. * param userData User parameter for callback.
  136. * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
  137. */
  138. void FLEXIO_I2S_TransferRxCreateHandleEDMA(FLEXIO_I2S_Type *base,
  139. flexio_i2s_edma_handle_t *handle,
  140. flexio_i2s_edma_callback_t callback,
  141. void *userData,
  142. edma_handle_t *dmaHandle)
  143. {
  144. assert((handle != NULL) && (dmaHandle != NULL));
  145. /* Zero the handle. */
  146. (void)memset(handle, 0, sizeof(*handle));
  147. /* Set flexio_i2s base to handle */
  148. handle->dmaHandle = dmaHandle;
  149. handle->callback = callback;
  150. handle->userData = userData;
  151. /* Set FLEXIO I2S state to idle */
  152. handle->state = (uint32_t)kFLEXIO_I2S_Idle;
  153. s_edmaPrivateHandle[1].base = base;
  154. s_edmaPrivateHandle[1].handle = handle;
  155. /* Need to use scatter gather */
  156. EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
  157. /* Install callback for Tx dma channel */
  158. EDMA_SetCallback(dmaHandle, FLEXIO_I2S_RxEDMACallback, &s_edmaPrivateHandle[1]);
  159. }
  160. /*!
  161. * brief Configures the FlexIO I2S Tx audio format.
  162. *
  163. * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
  164. * format to be transferred. This function also sets the eDMA parameter according to format.
  165. *
  166. * param base FlexIO I2S peripheral base address.
  167. * param handle FlexIO I2S eDMA handle pointer
  168. * param format Pointer to FlexIO I2S audio data format structure.
  169. * param srcClock_Hz FlexIO I2S clock source frequency in Hz, it should be 0 while in slave mode.
  170. */
  171. void FLEXIO_I2S_TransferSetFormatEDMA(FLEXIO_I2S_Type *base,
  172. flexio_i2s_edma_handle_t *handle,
  173. flexio_i2s_format_t *format,
  174. uint32_t srcClock_Hz)
  175. {
  176. assert((handle != NULL) && (format != NULL));
  177. /* Configure the audio format to FLEXIO I2S registers */
  178. if (srcClock_Hz != 0UL)
  179. {
  180. /* It is master */
  181. FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
  182. }
  183. else
  184. {
  185. FLEXIO_I2S_SlaveSetFormat(base, format);
  186. }
  187. /* Get the transfer size from format, this should be used in EDMA configuration */
  188. handle->bytesPerFrame = format->bitWidth / 8U;
  189. }
  190. /*!
  191. * brief Performs a non-blocking FlexIO I2S transfer using DMA.
  192. *
  193. * note This interface returned immediately after transfer initiates. Users should call
  194. * FLEXIO_I2S_GetTransferStatus to poll the transfer status and check whether the FlexIO I2S transfer is finished.
  195. *
  196. * param base FlexIO I2S peripheral base address.
  197. * param handle FlexIO I2S DMA handle pointer.
  198. * param xfer Pointer to DMA transfer structure.
  199. * retval kStatus_Success Start a FlexIO I2S eDMA send successfully.
  200. * retval kStatus_InvalidArgument The input arguments is invalid.
  201. * retval kStatus_TxBusy FlexIO I2S is busy sending data.
  202. */
  203. status_t FLEXIO_I2S_TransferSendEDMA(FLEXIO_I2S_Type *base,
  204. flexio_i2s_edma_handle_t *handle,
  205. flexio_i2s_transfer_t *xfer)
  206. {
  207. assert((handle != NULL) && (xfer != NULL));
  208. edma_transfer_config_t config = {0};
  209. uint32_t destAddr = FLEXIO_I2S_TxGetDataRegisterAddress(base) + (4UL - handle->bytesPerFrame);
  210. /* Check if input parameter invalid */
  211. if ((xfer->data == NULL) || (xfer->dataSize == 0U))
  212. {
  213. return kStatus_InvalidArgument;
  214. }
  215. if (handle->queue[handle->queueUser].data != NULL)
  216. {
  217. return kStatus_FLEXIO_I2S_QueueFull;
  218. }
  219. /* Change the state of handle */
  220. handle->state = (uint32_t)kFLEXIO_I2S_Busy;
  221. /* Update the queue state */
  222. handle->queue[handle->queueUser].data = xfer->data;
  223. handle->queue[handle->queueUser].dataSize = xfer->dataSize;
  224. handle->transferSize[handle->queueUser] = xfer->dataSize;
  225. handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  226. /* Prepare edma configure */
  227. EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (uint32_t *)destAddr, handle->bytesPerFrame,
  228. handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
  229. /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
  230. handle->nbytes = handle->bytesPerFrame;
  231. (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
  232. /* Start DMA transfer */
  233. EDMA_StartTransfer(handle->dmaHandle);
  234. /* Enable DMA enable bit */
  235. FLEXIO_I2S_TxEnableDMA(base, true);
  236. /* Enable FLEXIO I2S Tx clock */
  237. FLEXIO_I2S_Enable(base, true);
  238. return kStatus_Success;
  239. }
  240. /*!
  241. * brief Performs a non-blocking FlexIO I2S receive using eDMA.
  242. *
  243. * note This interface returned immediately after transfer initiates. Users should call
  244. * FLEXIO_I2S_GetReceiveRemainingBytes to poll the transfer status and check whether the FlexIO I2S transfer is
  245. * finished.
  246. *
  247. * param base FlexIO I2S peripheral base address.
  248. * param handle FlexIO I2S DMA handle pointer.
  249. * param xfer Pointer to DMA transfer structure.
  250. * retval kStatus_Success Start a FlexIO I2S eDMA receive successfully.
  251. * retval kStatus_InvalidArgument The input arguments is invalid.
  252. * retval kStatus_RxBusy FlexIO I2S is busy receiving data.
  253. */
  254. status_t FLEXIO_I2S_TransferReceiveEDMA(FLEXIO_I2S_Type *base,
  255. flexio_i2s_edma_handle_t *handle,
  256. flexio_i2s_transfer_t *xfer)
  257. {
  258. assert((handle != NULL) && (xfer != NULL));
  259. edma_transfer_config_t config = {0};
  260. uint32_t srcAddr = FLEXIO_I2S_RxGetDataRegisterAddress(base);
  261. /* Check if input parameter invalid */
  262. if ((xfer->data == NULL) || (xfer->dataSize == 0U))
  263. {
  264. return kStatus_InvalidArgument;
  265. }
  266. if (handle->queue[handle->queueUser].data != NULL)
  267. {
  268. return kStatus_FLEXIO_I2S_QueueFull;
  269. }
  270. /* Change the state of handle */
  271. handle->state = (uint32_t)kFLEXIO_I2S_Busy;
  272. /* Update queue state */
  273. handle->queue[handle->queueUser].data = xfer->data;
  274. handle->queue[handle->queueUser].dataSize = xfer->dataSize;
  275. handle->transferSize[handle->queueUser] = xfer->dataSize;
  276. handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  277. /* Prepare edma configure */
  278. EDMA_PrepareTransfer(&config, (uint32_t *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
  279. handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
  280. /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
  281. handle->nbytes = handle->bytesPerFrame;
  282. (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
  283. /* Start DMA transfer */
  284. EDMA_StartTransfer(handle->dmaHandle);
  285. /* Enable DMA enable bit */
  286. FLEXIO_I2S_RxEnableDMA(base, true);
  287. /* Enable FLEXIO I2S Rx clock */
  288. FLEXIO_I2S_Enable(base, true);
  289. return kStatus_Success;
  290. }
  291. /*!
  292. * brief Aborts a FlexIO I2S transfer using eDMA.
  293. *
  294. * param base FlexIO I2S peripheral base address.
  295. * param handle FlexIO I2S DMA handle pointer.
  296. */
  297. void FLEXIO_I2S_TransferAbortSendEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
  298. {
  299. assert(handle != NULL);
  300. /* Disable dma */
  301. EDMA_AbortTransfer(handle->dmaHandle);
  302. /* Disable DMA enable bit */
  303. FLEXIO_I2S_TxEnableDMA(base, false);
  304. /* Set the handle state */
  305. handle->state = (uint32_t)kFLEXIO_I2S_Idle;
  306. }
  307. /*!
  308. * brief Aborts a FlexIO I2S receive using eDMA.
  309. *
  310. * param base FlexIO I2S peripheral base address.
  311. * param handle FlexIO I2S DMA handle pointer.
  312. */
  313. void FLEXIO_I2S_TransferAbortReceiveEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
  314. {
  315. assert(handle != NULL);
  316. /* Disable dma */
  317. EDMA_AbortTransfer(handle->dmaHandle);
  318. /* Disable DMA enable bit */
  319. FLEXIO_I2S_RxEnableDMA(base, false);
  320. /* Set the handle state */
  321. handle->state = (uint32_t)kFLEXIO_I2S_Idle;
  322. }
  323. /*!
  324. * brief Gets the remaining bytes to be sent.
  325. *
  326. * param base FlexIO I2S peripheral base address.
  327. * param handle FlexIO I2S DMA handle pointer.
  328. * param count Bytes sent.
  329. * retval kStatus_Success Succeed get the transfer count.
  330. * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
  331. */
  332. status_t FLEXIO_I2S_TransferGetSendCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
  333. {
  334. assert(handle != NULL);
  335. status_t status = kStatus_Success;
  336. if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
  337. {
  338. status = kStatus_NoTransferInProgress;
  339. }
  340. else
  341. {
  342. *count = handle->transferSize[handle->queueDriver] -
  343. (uint32_t)handle->nbytes *
  344. EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
  345. }
  346. return status;
  347. }
  348. /*!
  349. * brief Get the remaining bytes to be received.
  350. *
  351. * param base FlexIO I2S peripheral base address.
  352. * param handle FlexIO I2S DMA handle pointer.
  353. * param count Bytes received.
  354. * retval kStatus_Success Succeed get the transfer count.
  355. * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
  356. */
  357. status_t FLEXIO_I2S_TransferGetReceiveCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
  358. {
  359. assert(handle != NULL);
  360. status_t status = kStatus_Success;
  361. if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
  362. {
  363. status = kStatus_NoTransferInProgress;
  364. }
  365. else
  366. {
  367. *count = handle->transferSize[handle->queueDriver] -
  368. (uint32_t)handle->nbytes *
  369. EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
  370. }
  371. return status;
  372. }