fsl_flexio_i2s_edma.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * The Clear BSD License
  3. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  4. * Copyright 2016-2017 NXP
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted (subject to the limitations in the disclaimer below) provided
  9. * that the following conditions are met:
  10. *
  11. * o Redistributions of source code must retain the above copyright notice, this list
  12. * of conditions and the following disclaimer.
  13. *
  14. * o Redistributions in binary form must reproduce the above copyright notice, this
  15. * list of conditions and the following disclaimer in the documentation and/or
  16. * other materials provided with the distribution.
  17. *
  18. * o Neither the name of the copyright holder nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  27. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "fsl_flexio_i2s_edma.h"
  35. /* Component ID definition, used by tools. */
  36. #ifndef FSL_COMPONENT_ID
  37. #define FSL_COMPONENT_ID "platform.drivers.flexio_i2s_edma"
  38. #endif
  39. /*******************************************************************************
  40. * Definitations
  41. ******************************************************************************/
  42. /* Used for 32byte aligned */
  43. #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32) & ~0x1FU)
  44. /*<! Structure definition for flexio_i2s_edma_private_handle_t. The structure is private. */
  45. typedef struct _flexio_i2s_edma_private_handle
  46. {
  47. FLEXIO_I2S_Type *base;
  48. flexio_i2s_edma_handle_t *handle;
  49. } flexio_i2s_edma_private_handle_t;
  50. enum _flexio_i2s_edma_transfer_state
  51. {
  52. kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO I2S is busy */
  53. kFLEXIO_I2S_Idle, /*!< Transfer is done. */
  54. };
  55. /*<! Private handle only used for internally. */
  56. static flexio_i2s_edma_private_handle_t s_edmaPrivateHandle[2];
  57. /*******************************************************************************
  58. * Prototypes
  59. ******************************************************************************/
  60. /*!
  61. * @brief FLEXIO I2S EDMA callback for send.
  62. *
  63. * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
  64. * @param userData Parameter for user callback.
  65. * @param done If the DMA transfer finished.
  66. * @param tcds The TCD index.
  67. */
  68. static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  69. /*!
  70. * @brief FLEXIO I2S EDMA callback for receive.
  71. *
  72. * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
  73. * @param userData Parameter for user callback.
  74. * @param done If the DMA transfer finished.
  75. * @param tcds The TCD index.
  76. */
  77. static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  78. /*******************************************************************************
  79. * Code
  80. ******************************************************************************/
  81. static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  82. {
  83. flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
  84. flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
  85. /* If finished a blcok, call the callback function */
  86. memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
  87. flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  88. if (flexio_i2sHandle->callback)
  89. {
  90. (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
  91. }
  92. /* If all data finished, just stop the transfer */
  93. if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
  94. {
  95. FLEXIO_I2S_TransferAbortSendEDMA(privHandle->base, flexio_i2sHandle);
  96. }
  97. }
  98. static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  99. {
  100. flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
  101. flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
  102. /* If finished a blcok, call the callback function */
  103. memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
  104. flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  105. if (flexio_i2sHandle->callback)
  106. {
  107. (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
  108. }
  109. /* If all data finished, just stop the transfer */
  110. if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
  111. {
  112. FLEXIO_I2S_TransferAbortReceiveEDMA(privHandle->base, flexio_i2sHandle);
  113. }
  114. }
  115. void FLEXIO_I2S_TransferTxCreateHandleEDMA(FLEXIO_I2S_Type *base,
  116. flexio_i2s_edma_handle_t *handle,
  117. flexio_i2s_edma_callback_t callback,
  118. void *userData,
  119. edma_handle_t *dmaHandle)
  120. {
  121. assert(handle && dmaHandle);
  122. /* Zero the handle. */
  123. memset(handle, 0, sizeof(*handle));
  124. /* Set flexio_i2s base to handle */
  125. handle->dmaHandle = dmaHandle;
  126. handle->callback = callback;
  127. handle->userData = userData;
  128. /* Set FLEXIO I2S state to idle */
  129. handle->state = kFLEXIO_I2S_Idle;
  130. s_edmaPrivateHandle[0].base = base;
  131. s_edmaPrivateHandle[0].handle = handle;
  132. /* Need to use scatter gather */
  133. EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
  134. /* Install callback for Tx dma channel */
  135. EDMA_SetCallback(dmaHandle, FLEXIO_I2S_TxEDMACallback, &s_edmaPrivateHandle[0]);
  136. }
  137. void FLEXIO_I2S_TransferRxCreateHandleEDMA(FLEXIO_I2S_Type *base,
  138. flexio_i2s_edma_handle_t *handle,
  139. flexio_i2s_edma_callback_t callback,
  140. void *userData,
  141. edma_handle_t *dmaHandle)
  142. {
  143. assert(handle && dmaHandle);
  144. /* Zero the handle. */
  145. memset(handle, 0, sizeof(*handle));
  146. /* Set flexio_i2s base to handle */
  147. handle->dmaHandle = dmaHandle;
  148. handle->callback = callback;
  149. handle->userData = userData;
  150. /* Set FLEXIO I2S state to idle */
  151. handle->state = kFLEXIO_I2S_Idle;
  152. s_edmaPrivateHandle[1].base = base;
  153. s_edmaPrivateHandle[1].handle = handle;
  154. /* Need to use scatter gather */
  155. EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
  156. /* Install callback for Tx dma channel */
  157. EDMA_SetCallback(dmaHandle, FLEXIO_I2S_RxEDMACallback, &s_edmaPrivateHandle[1]);
  158. }
  159. void FLEXIO_I2S_TransferSetFormatEDMA(FLEXIO_I2S_Type *base,
  160. flexio_i2s_edma_handle_t *handle,
  161. flexio_i2s_format_t *format,
  162. uint32_t srcClock_Hz)
  163. {
  164. assert(handle && format);
  165. /* Configure the audio format to FLEXIO I2S registers */
  166. if (srcClock_Hz != 0)
  167. {
  168. /* It is master */
  169. FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
  170. }
  171. else
  172. {
  173. FLEXIO_I2S_SlaveSetFormat(base, format);
  174. }
  175. /* Get the tranfer size from format, this should be used in EDMA configuration */
  176. handle->bytesPerFrame = format->bitWidth / 8U;
  177. }
  178. status_t FLEXIO_I2S_TransferSendEDMA(FLEXIO_I2S_Type *base,
  179. flexio_i2s_edma_handle_t *handle,
  180. flexio_i2s_transfer_t *xfer)
  181. {
  182. assert(handle && xfer);
  183. edma_transfer_config_t config = {0};
  184. uint32_t destAddr = FLEXIO_I2S_TxGetDataRegisterAddress(base) + (4U - handle->bytesPerFrame);
  185. /* Check if input parameter invalid */
  186. if ((xfer->data == NULL) || (xfer->dataSize == 0U))
  187. {
  188. return kStatus_InvalidArgument;
  189. }
  190. if (handle->queue[handle->queueUser].data)
  191. {
  192. return kStatus_FLEXIO_I2S_QueueFull;
  193. }
  194. /* Change the state of handle */
  195. handle->state = kFLEXIO_I2S_Busy;
  196. /* Update the queue state */
  197. handle->queue[handle->queueUser].data = xfer->data;
  198. handle->queue[handle->queueUser].dataSize = xfer->dataSize;
  199. handle->transferSize[handle->queueUser] = xfer->dataSize;
  200. handle->queueUser = (handle->queueUser + 1) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  201. /* Prepare edma configure */
  202. EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (void *)destAddr, handle->bytesPerFrame,
  203. handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
  204. /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
  205. handle->nbytes = handle->bytesPerFrame;
  206. EDMA_SubmitTransfer(handle->dmaHandle, &config);
  207. /* Start DMA transfer */
  208. EDMA_StartTransfer(handle->dmaHandle);
  209. /* Enable DMA enable bit */
  210. FLEXIO_I2S_TxEnableDMA(base, true);
  211. /* Enable FLEXIO I2S Tx clock */
  212. FLEXIO_I2S_Enable(base, true);
  213. return kStatus_Success;
  214. }
  215. status_t FLEXIO_I2S_TransferReceiveEDMA(FLEXIO_I2S_Type *base,
  216. flexio_i2s_edma_handle_t *handle,
  217. flexio_i2s_transfer_t *xfer)
  218. {
  219. assert(handle && xfer);
  220. edma_transfer_config_t config = {0};
  221. uint32_t srcAddr = FLEXIO_I2S_RxGetDataRegisterAddress(base) + (4U - handle->bytesPerFrame);
  222. /* Check if input parameter invalid */
  223. if ((xfer->data == NULL) || (xfer->dataSize == 0U))
  224. {
  225. return kStatus_InvalidArgument;
  226. }
  227. if (handle->queue[handle->queueUser].data)
  228. {
  229. return kStatus_FLEXIO_I2S_QueueFull;
  230. }
  231. /* Change the state of handle */
  232. handle->state = kFLEXIO_I2S_Busy;
  233. /* Update queue state */
  234. handle->queue[handle->queueUser].data = xfer->data;
  235. handle->queue[handle->queueUser].dataSize = xfer->dataSize;
  236. handle->transferSize[handle->queueUser] = xfer->dataSize;
  237. handle->queueUser = (handle->queueUser + 1) % FLEXIO_I2S_XFER_QUEUE_SIZE;
  238. /* Prepare edma configure */
  239. EDMA_PrepareTransfer(&config, (void *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
  240. handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
  241. /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
  242. handle->nbytes = handle->bytesPerFrame;
  243. EDMA_SubmitTransfer(handle->dmaHandle, &config);
  244. /* Start DMA transfer */
  245. EDMA_StartTransfer(handle->dmaHandle);
  246. /* Enable DMA enable bit */
  247. FLEXIO_I2S_RxEnableDMA(base, true);
  248. /* Enable FLEXIO I2S Rx clock */
  249. FLEXIO_I2S_Enable(base, true);
  250. return kStatus_Success;
  251. }
  252. void FLEXIO_I2S_TransferAbortSendEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
  253. {
  254. assert(handle);
  255. /* Disable dma */
  256. EDMA_AbortTransfer(handle->dmaHandle);
  257. /* Disable DMA enable bit */
  258. FLEXIO_I2S_TxEnableDMA(base, false);
  259. /* Set the handle state */
  260. handle->state = kFLEXIO_I2S_Idle;
  261. }
  262. void FLEXIO_I2S_TransferAbortReceiveEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
  263. {
  264. assert(handle);
  265. /* Disable dma */
  266. EDMA_AbortTransfer(handle->dmaHandle);
  267. /* Disable DMA enable bit */
  268. FLEXIO_I2S_RxEnableDMA(base, false);
  269. /* Set the handle state */
  270. handle->state = kFLEXIO_I2S_Idle;
  271. }
  272. status_t FLEXIO_I2S_TransferGetSendCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
  273. {
  274. assert(handle);
  275. status_t status = kStatus_Success;
  276. if (handle->state != kFLEXIO_I2S_Busy)
  277. {
  278. status = kStatus_NoTransferInProgress;
  279. }
  280. else
  281. {
  282. *count = handle->transferSize[handle->queueDriver] -
  283. (uint32_t)handle->nbytes *
  284. EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
  285. }
  286. return status;
  287. }
  288. status_t FLEXIO_I2S_TransferGetReceiveCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
  289. {
  290. assert(handle);
  291. status_t status = kStatus_Success;
  292. if (handle->state != kFLEXIO_I2S_Busy)
  293. {
  294. status = kStatus_NoTransferInProgress;
  295. }
  296. else
  297. {
  298. *count = handle->transferSize[handle->queueDriver] -
  299. (uint32_t)handle->nbytes *
  300. EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
  301. }
  302. return status;
  303. }