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 #ifndef _FSL_SAI_EDMA_H_ 9 #define _FSL_SAI_EDMA_H_ 10 11 #include "fsl_edma.h" 12 #include "fsl_sai.h" 13 14 /*! 15 * @addtogroup sai_edma SAI EDMA Driver 16 * @ingroup sai 17 * @{ 18 */ 19 20 /******************************************************************************* 21 * Definitions 22 ******************************************************************************/ 23 24 /*! @name Driver version */ 25 /*@{*/ 26 #define FSL_SAI_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 5, 1)) /*!< Version 2.5.1 */ 27 /*@}*/ 28 29 typedef struct sai_edma_handle sai_edma_handle_t; 30 31 /*! @brief SAI eDMA transfer callback function for finish and error */ 32 typedef void (*sai_edma_callback_t)(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData); 33 34 /*! @brief SAI DMA transfer handle, users should not touch the content of the handle.*/ 35 struct sai_edma_handle 36 { 37 edma_handle_t *dmaHandle; /*!< DMA handler for SAI send */ 38 uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */ 39 uint8_t bytesPerFrame; /*!< Bytes in a frame */ 40 uint8_t channelMask; /*!< Enabled channel mask value, reference _sai_channel_mask */ 41 uint8_t channelNums; /*!< total enabled channel nums */ 42 uint8_t channel; /*!< Which data channel */ 43 uint8_t count; /*!< The transfer data count in a DMA request */ 44 uint32_t state; /*!< Internal state for SAI eDMA transfer */ 45 sai_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */ 46 void *userData; /*!< User callback parameter */ 47 uint8_t tcd[(SAI_XFER_QUEUE_SIZE + 1U) * sizeof(edma_tcd_t)]; /*!< TCD pool for eDMA transfer. */ 48 sai_transfer_t saiQueue[SAI_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */ 49 size_t transferSize[SAI_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */ 50 volatile uint8_t queueUser; /*!< Index for user to queue transfer. */ 51 volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */ 52 }; 53 54 /******************************************************************************* 55 * APIs 56 ******************************************************************************/ 57 #if defined(__cplusplus) 58 extern "C" { 59 #endif 60 61 /*! 62 * @name eDMA Transactional 63 * @{ 64 */ 65 66 /*! 67 * @brief Initializes the SAI eDMA handle. 68 * 69 * This function initializes the SAI master DMA handle, which can be used for other SAI master transactional APIs. 70 * Usually, for a specified SAI instance, call this API once to get the initialized handle. 71 * 72 * @param base SAI base pointer. 73 * @param handle SAI eDMA handle pointer. 74 * @param base SAI peripheral base address. 75 * @param callback Pointer to user callback function. 76 * @param userData User parameter passed to the callback function. 77 * @param txDmaHandle eDMA handle pointer, this handle shall be static allocated by users. 78 */ 79 void SAI_TransferTxCreateHandleEDMA(I2S_Type *base, 80 sai_edma_handle_t *handle, 81 sai_edma_callback_t callback, 82 void *userData, 83 edma_handle_t *txDmaHandle); 84 85 /*! 86 * @brief Initializes the SAI Rx eDMA handle. 87 * 88 * This function initializes the SAI slave DMA handle, which can be used for other SAI master transactional APIs. 89 * Usually, for a specified SAI instance, call this API once to get the initialized handle. 90 * 91 * @param base SAI base pointer. 92 * @param handle SAI eDMA handle pointer. 93 * @param base SAI peripheral base address. 94 * @param callback Pointer to user callback function. 95 * @param userData User parameter passed to the callback function. 96 * @param rxDmaHandle eDMA handle pointer, this handle shall be static allocated by users. 97 */ 98 void SAI_TransferRxCreateHandleEDMA(I2S_Type *base, 99 sai_edma_handle_t *handle, 100 sai_edma_callback_t callback, 101 void *userData, 102 edma_handle_t *rxDmaHandle); 103 104 /*! 105 * @brief Configures the SAI Tx audio format. 106 * 107 * @deprecated Do not use this function. It has been superceded by @ref SAI_TransferTxSetConfigEDMA 108 * 109 * The audio format can be changed at run-time. This function configures the sample rate and audio data 110 * format to be transferred. This function also sets the eDMA parameter according to formatting requirements. 111 * 112 * @param base SAI base pointer. 113 * @param handle SAI eDMA handle pointer. 114 * @param format Pointer to SAI audio data format structure. 115 * @param mclkSourceClockHz SAI master clock source frequency in Hz. 116 * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If bit clock source is master 117 * clock, this value should equals to masterClockHz in format. 118 * @retval kStatus_Success Audio format set successfully. 119 * @retval kStatus_InvalidArgument The input argument is invalid. 120 */ 121 void SAI_TransferTxSetFormatEDMA(I2S_Type *base, 122 sai_edma_handle_t *handle, 123 sai_transfer_format_t *format, 124 uint32_t mclkSourceClockHz, 125 uint32_t bclkSourceClockHz); 126 127 /*! 128 * @brief Configures the SAI Rx audio format. 129 * 130 * @deprecated Do not use this function. It has been superceded by @ref SAI_TransferRxSetConfigEDMA 131 * 132 * The audio format can be changed at run-time. This function configures the sample rate and audio data 133 * format to be transferred. This function also sets the eDMA parameter according to formatting requirements. 134 * 135 * @param base SAI base pointer. 136 * @param handle SAI eDMA handle pointer. 137 * @param format Pointer to SAI audio data format structure. 138 * @param mclkSourceClockHz SAI master clock source frequency in Hz. 139 * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is the master 140 * clock, this value should equal to masterClockHz in format. 141 * @retval kStatus_Success Audio format set successfully. 142 * @retval kStatus_InvalidArgument The input argument is invalid. 143 */ 144 void SAI_TransferRxSetFormatEDMA(I2S_Type *base, 145 sai_edma_handle_t *handle, 146 sai_transfer_format_t *format, 147 uint32_t mclkSourceClockHz, 148 uint32_t bclkSourceClockHz); 149 150 /*! 151 * @brief Configures the SAI Tx. 152 * 153 * @note SAI eDMA supports data transfer in a multiple SAI channels if the FIFO Combine feature is supported. 154 * To activate the multi-channel transfer enable SAI channels by filling the channelMask 155 * of sai_transceiver_t with the corresponding values of _sai_channel_mask enum, enable the FIFO Combine 156 * mode by assigning kSAI_FifoCombineModeEnabledOnWrite to the fifoCombine member of sai_fifo_combine_t 157 * which is a member of sai_transceiver_t. 158 * This is an example of multi-channel data transfer configuration step. 159 * @code 160 * sai_transceiver_t config; 161 * SAI_GetClassicI2SConfig(&config, kSAI_WordWidth16bits, kSAI_Stereo, kSAI_Channel0Mask|kSAI_Channel1Mask); 162 * config.fifo.fifoCombine = kSAI_FifoCombineModeEnabledOnWrite; 163 * SAI_TransferTxSetConfigEDMA(I2S0, &edmaHandle, &config); 164 * @endcode 165 * 166 * @param base SAI base pointer. 167 * @param handle SAI eDMA handle pointer. 168 * @param saiConfig sai configurations. 169 */ 170 void SAI_TransferTxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig); 171 172 /*! 173 * @brief Configures the SAI Rx. 174 * 175 * @note SAI eDMA supports data transfer in a multiple SAI channels if the FIFO Combine feature is supported. 176 * To activate the multi-channel transfer enable SAI channels by filling the channelMask 177 * of sai_transceiver_t with the corresponding values of _sai_channel_mask enum, enable the FIFO Combine 178 * mode by assigning kSAI_FifoCombineModeEnabledOnRead to the fifoCombine member of sai_fifo_combine_t 179 * which is a member of sai_transceiver_t. 180 * This is an example of multi-channel data transfer configuration step. 181 * @code 182 * sai_transceiver_t config; 183 * SAI_GetClassicI2SConfig(&config, kSAI_WordWidth16bits, kSAI_Stereo, kSAI_Channel0Mask|kSAI_Channel1Mask); 184 * config.fifo.fifoCombine = kSAI_FifoCombineModeEnabledOnRead; 185 * SAI_TransferRxSetConfigEDMA(I2S0, &edmaHandle, &config); 186 * @endcode 187 * @param base SAI base pointer. 188 * @param handle SAI eDMA handle pointer. 189 * @param saiConfig sai configurations. 190 */ 191 void SAI_TransferRxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig); 192 193 /*! 194 * @brief Performs a non-blocking SAI transfer using DMA. 195 * 196 * @note This interface returns immediately after the transfer initiates. Call 197 * SAI_GetTransferStatus to poll the transfer status and check whether the SAI transfer is finished. 198 * 199 * This function support multi channel transfer, 200 * 1. for the sai IP support fifo combine mode, application should enable the fifo combine mode, no limitation 201 * on channel numbers 202 * 2. for the sai IP not support fifo combine mode, sai edma provide another solution which using 203 * EDMA modulo feature, but support 2 or 4 channels only. 204 * 205 * @param base SAI base pointer. 206 * @param handle SAI eDMA handle pointer. 207 * @param xfer Pointer to the DMA transfer structure. 208 * @retval kStatus_Success Start a SAI eDMA send successfully. 209 * @retval kStatus_InvalidArgument The input argument is invalid. 210 * @retval kStatus_TxBusy SAI is busy sending data. 211 */ 212 status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer); 213 214 /*! 215 * @brief Performs a non-blocking SAI receive using eDMA. 216 * 217 * @note This interface returns immediately after the transfer initiates. Call 218 * the SAI_GetReceiveRemainingBytes to poll the transfer status and check whether the SAI transfer is finished. 219 * 220 * This function support multi channel transfer, 221 * 1. for the sai IP support fifo combine mode, application should enable the fifo combine mode, no limitation 222 * on channel numbers 223 * 2. for the sai IP not support fifo combine mode, sai edma provide another solution which using 224 * EDMA modulo feature, but support 2 or 4 channels only. 225 * 226 * @param base SAI base pointer 227 * @param handle SAI eDMA handle pointer. 228 * @param xfer Pointer to DMA transfer structure. 229 * @retval kStatus_Success Start a SAI eDMA receive successfully. 230 * @retval kStatus_InvalidArgument The input argument is invalid. 231 * @retval kStatus_RxBusy SAI is busy receiving data. 232 */ 233 status_t SAI_TransferReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer); 234 235 /*! 236 * @brief Performs a non-blocking SAI loop transfer using eDMA. 237 * 238 * @note This function support loop transfer only,such as A->B->...->A, application must be aware of 239 * that the more counts of the loop transfer, then more tcd memory required, as the function use the tcd pool in 240 * sai_edma_handle_t, so application could redefine the SAI_XFER_QUEUE_SIZE to determine the proper TCD pool size. 241 * This function support one sai channel only. 242 * 243 * Once the loop transfer start, application can use function SAI_TransferAbortSendEDMA to stop the loop transfer. 244 * 245 * @param base SAI base pointer. 246 * @param handle SAI eDMA handle pointer. 247 * @param xfer Pointer to the DMA transfer structure, should be a array with elements counts >=1(loopTransferCount). 248 * @param loopTransferCount the counts of xfer array. 249 * @retval kStatus_Success Start a SAI eDMA send successfully. 250 * @retval kStatus_InvalidArgument The input argument is invalid. 251 */ 252 status_t SAI_TransferSendLoopEDMA(I2S_Type *base, 253 sai_edma_handle_t *handle, 254 sai_transfer_t *xfer, 255 uint32_t loopTransferCount); 256 257 /*! 258 * @brief Performs a non-blocking SAI loop transfer using eDMA. 259 * 260 * @note This function support loop transfer only,such as A->B->...->A, application must be aware of 261 * that the more counts of the loop transfer, then more tcd memory required, as the function use the tcd pool in 262 * sai_edma_handle_t, so application could redefine the SAI_XFER_QUEUE_SIZE to determine the proper TCD pool size. 263 * This function support one sai channel only. 264 * 265 * Once the loop transfer start, application can use function SAI_TransferAbortReceiveEDMA to stop the loop transfer. 266 * 267 * @param base SAI base pointer. 268 * @param handle SAI eDMA handle pointer. 269 * @param xfer Pointer to the DMA transfer structure, should be a array with elements counts >=1(loopTransferCount). 270 * @param loopTransferCount the counts of xfer array. 271 * @retval kStatus_Success Start a SAI eDMA receive successfully. 272 * @retval kStatus_InvalidArgument The input argument is invalid. 273 */ 274 status_t SAI_TransferReceiveLoopEDMA(I2S_Type *base, 275 sai_edma_handle_t *handle, 276 sai_transfer_t *xfer, 277 uint32_t loopTransferCount); 278 279 /*! 280 * @brief Terminate all SAI send. 281 * 282 * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the 283 * current transfer slot, please call SAI_TransferAbortSendEDMA. 284 * 285 * @param base SAI base pointer. 286 * @param handle SAI eDMA handle pointer. 287 */ 288 void SAI_TransferTerminateSendEDMA(I2S_Type *base, sai_edma_handle_t *handle); 289 290 /*! 291 * @brief Terminate all SAI receive. 292 * 293 * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the 294 * current transfer slot, please call SAI_TransferAbortReceiveEDMA. 295 * 296 * @param base SAI base pointer. 297 * @param handle SAI eDMA handle pointer. 298 */ 299 void SAI_TransferTerminateReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle); 300 301 /*! 302 * @brief Aborts a SAI transfer using eDMA. 303 * 304 * This function only aborts the current transfer slots, the other transfer slots' information still kept 305 * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateSendEDMA. 306 * 307 * @param base SAI base pointer. 308 * @param handle SAI eDMA handle pointer. 309 */ 310 void SAI_TransferAbortSendEDMA(I2S_Type *base, sai_edma_handle_t *handle); 311 312 /*! 313 * @brief Aborts a SAI receive using eDMA. 314 * 315 * This function only aborts the current transfer slots, the other transfer slots' information still kept 316 * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateReceiveEDMA. 317 * 318 * @param base SAI base pointer 319 * @param handle SAI eDMA handle pointer. 320 */ 321 void SAI_TransferAbortReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle); 322 323 /*! 324 * @brief Gets byte count sent by SAI. 325 * 326 * @param base SAI base pointer. 327 * @param handle SAI eDMA handle pointer. 328 * @param count Bytes count sent by SAI. 329 * @retval kStatus_Success Succeed get the transfer count. 330 * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress. 331 */ 332 status_t SAI_TransferGetSendCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count); 333 334 /*! 335 * @brief Gets byte count received by SAI. 336 * 337 * @param base SAI base pointer 338 * @param handle SAI eDMA handle pointer. 339 * @param count Bytes count received by SAI. 340 * @retval kStatus_Success Succeed get the transfer count. 341 * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress. 342 */ 343 status_t SAI_TransferGetReceiveCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count); 344 345 /*! 346 * @brief Gets valid transfer slot. 347 * 348 * This function can be used to query the valid transfer request slot that the application can submit. 349 * It should be called in the critical section, that means the application could call it in the corresponding callback 350 * function or disable IRQ before calling it in the application, otherwise, the returned value may not correct. 351 * 352 * @param base SAI base pointer 353 * @param handle SAI eDMA handle pointer. 354 * @retval valid slot count that application submit. 355 */ 356 uint32_t SAI_TransferGetValidTransferSlotsEDMA(I2S_Type *base, sai_edma_handle_t *handle); 357 358 /*! @} */ 359 360 #if defined(__cplusplus) 361 } 362 #endif 363 364 /*! 365 * @} 366 */ 367 #endif 368