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