1 /*
2  * Copyright 2019 - 2020, NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #ifndef _FSL_PDM_EDMA_H_
8 #define _FSL_PDM_EDMA_H_
9 
10 #include "fsl_edma.h"
11 #include "fsl_pdm.h"
12 
13 /*!
14  * @addtogroup pdm_edma PDM EDMA Driver
15  * @ingroup pdm
16  * @{
17  */
18 
19 /*******************************************************************************
20  * Definitions
21  ******************************************************************************/
22 
23 /*! @name Driver version */
24 /*@{*/
25 #define FSL_PDM_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 6, 1)) /*!< Version 2.6.1 */
26 /*@}*/
27 
28 /*! @brief PDM edma handler */
29 typedef struct _pdm_edma_handle pdm_edma_handle_t;
30 
31 /*!@brief pdm multi channel interleave type */
32 typedef enum _pdm_edma_multi_channel_interleave
33 {
34     kPDM_EDMAMultiChannelInterleavePerChannelSample =
35         0U, /*!< multi channel PDM data interleave per channel sample
36              * -------------------------------------------------------------------------
37              * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
38              * -------------------------------------------------------------------------
39              */
40     kPDM_EDMAMultiChannelInterleavePerChannelBlock =
41         1U, /*!< multi channel PDM data interleave per channel block
42              * ----------------------------------------------------------------------------------------------------------------------------
43              * |CHANNEL0 | CHANNEL0 | CHANNEL0 | ...... | CHANNEL1 | CHANNEL 1 | CHANNEL 1 | ....| CHANNEL2 | CHANNEL 2
44              * | CHANNEL 2 | ....|
45              * ----------------------------------------------------------------------------------------------------------------------------
46              */
47 } pdm_edma_multi_channel_interleave_t;
48 
49 /*! @brief PDM edma transfer */
50 typedef struct _pdm_edma_transfer
51 {
52     volatile uint8_t *data;                  /*!< Data start address to transfer. */
53     volatile size_t dataSize;                /*!< Total Transfer bytes size. */
54     struct _pdm_edma_transfer *linkTransfer; /*!< linked transfer configurations */
55 } pdm_edma_transfer_t;
56 
57 /*! @brief PDM eDMA transfer callback function for finish and error */
58 typedef void (*pdm_edma_callback_t)(PDM_Type *base, pdm_edma_handle_t *handle, status_t status, void *userData);
59 
60 /*! @brief PDM DMA transfer handle, users should not touch the content of the handle.*/
61 struct _pdm_edma_handle
62 {
63     edma_handle_t *dmaHandle;     /*!< DMA handler for PDM send */
64     uint8_t count;                /*!< The transfer data count in a DMA request */
65     uint32_t receivedBytes;       /*!< total transfer count */
66     uint32_t state;               /*!< Internal state for PDM eDMA transfer */
67     pdm_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
68     bool isLoopTransfer;          /*!< loop transfer */
69     void *userData;               /*!< User callback parameter */
70     edma_tcd_t *tcd;              /*!< TCD pool for eDMA transfer. */
71     uint32_t tcdNum;              /*!< TCD number */
72     uint32_t tcdUser;             /*!< Index for user to queue transfer. */
73     uint32_t tcdDriver;           /*!< Index for driver to get the transfer data and size */
74     volatile uint32_t tcdUsedNum; /*!< Index for user to queue transfer. */
75 
76     pdm_edma_multi_channel_interleave_t interleaveType; /*!< multi channel transfer interleave type */
77 
78     uint8_t endChannel;  /*!< The last enabled channel */
79     uint8_t channelNums; /*!< total channel numbers */
80 };
81 
82 /*******************************************************************************
83  * APIs
84  ******************************************************************************/
85 #if defined(__cplusplus)
86 extern "C" {
87 #endif
88 
89 /*!
90  * @name PDM eDMA Transactional
91  * @{
92  */
93 
94 /*!
95  * @brief Install EDMA descriptor memory.
96  *
97  * @param handle Pointer to EDMA channel transfer handle.
98  * @param tcdAddr EDMA head descriptor address.
99  * @param tcdNum EDMA link descriptor address.
100  */
101 void PDM_TransferInstallEDMATCDMemory(pdm_edma_handle_t *handle, void *tcdAddr, size_t tcdNum);
102 
103 /*!
104  * @brief Initializes the PDM Rx eDMA handle.
105  *
106  * This function initializes the PDM slave DMA handle, which can be used for other PDM master transactional APIs.
107  * Usually, for a specified PDM instance, call this API once to get the initialized handle.
108  *
109  * @param base PDM base pointer.
110  * @param handle PDM eDMA handle pointer.
111  * @param callback Pointer to user callback function.
112  * @param userData User parameter passed to the callback function.
113  * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
114  */
115 void PDM_TransferCreateHandleEDMA(
116     PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle);
117 
118 /*!
119  * @brief Initializes the multi PDM channel interleave type.
120  *
121  * This function initializes the PDM DMA handle member interleaveType, it shall be called only when application would
122  * like to use type kPDM_EDMAMultiChannelInterleavePerChannelBlock, since the default interleaveType is
123  * kPDM_EDMAMultiChannelInterleavePerChannelSample always
124  *
125  * @param handle PDM eDMA handle pointer.
126  * @param multiChannelInterleaveType Multi channel interleave type.
127  */
128 void PDM_TransferSetMultiChannelInterleaveType(pdm_edma_handle_t *handle,
129                                                pdm_edma_multi_channel_interleave_t multiChannelInterleaveType);
130 
131 /*!
132  * @brief Configures the PDM channel.
133  *
134  * @param base PDM base pointer.
135  * @param handle PDM eDMA handle pointer.
136  * @param channel channel index.
137  * @param config pdm channel configurations.
138  */
139 void PDM_TransferSetChannelConfigEDMA(PDM_Type *base,
140                                       pdm_edma_handle_t *handle,
141                                       uint32_t channel,
142                                       const pdm_channel_config_t *config);
143 
144 /*!
145  * @brief Performs a non-blocking PDM receive using eDMA.
146  *
147  * @note This interface returns immediately after the transfer initiates. Call
148  * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished.
149  *
150  * 1. Scatter gather case:
151  * This functio support dynamic scatter gather and staic scatter gather,
152  * a. for the dynamic scatter gather case:
153  * Application should call PDM_TransferReceiveEDMA function continuously to make sure new receive request is submit
154  * before the previous one finish. b. for the static scatter gather case: Application should use the link transfer
155  * feature and make sure a loop link transfer is provided, such as:
156  * @code pdm_edma_transfer_t pdmXfer[2] =
157  *   {
158  *       {
159  *       .data  = s_buffer,
160  *       .dataSize = BUFFER_SIZE,
161  *       .linkTransfer = &pdmXfer[1],
162  *       },
163  *
164  *       {
165  *       .data  = &s_buffer[BUFFER_SIZE],
166  *       .dataSize = BUFFER_SIZE,
167  *       .linkTransfer = &pdmXfer[0]
168  *       },
169  *   };
170  * @endcode
171  *
172  * 2. Multi channel case:
173  * This function support receive multi pdm channel data, for example, if two channel is requested,
174  * @code
175  * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_0, &channelConfig);
176  * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_1, &channelConfig);
177  * PDM_TransferReceiveEDMA(DEMO_PDM, &s_pdmRxHandle_0, pdmXfer);
178  * @endcode
179  * The output data will be formatted as below if handle->interleaveType =
180  * kPDM_EDMAMultiChannelInterleavePerChannelSample :
181  * -------------------------------------------------------------------------
182  * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
183  * -------------------------------------------------------------------------
184  *
185  * The output data will be formatted as below if handle->interleaveType = kPDM_EDMAMultiChannelInterleavePerChannelBlock
186  * :
187  * ----------------------------------------------------------------------------------------------------------------------
188  * |CHANNEL3 | CHANNEL3 | CHANNEL3 | .... | CHANNEL4 | CHANNEL 4 | CHANNEL4 |....| CHANNEL5 | CHANNEL 5 | CHANNEL5
189  * |....|
190  * ----------------------------------------------------------------------------------------------------------------------
191  * Note: the dataSize of xfer is the total data size, while application using
192  * kPDM_EDMAMultiChannelInterleavePerChannelBlock, the buffer size for each PDM channel is channelSize = dataSize /
193  * channelNums, then there are limitation for this feature,
194  * 1. 3 DMIC array: the dataSize shall be 4 * (channelSize)
195  * The addtional buffer is mandantory for edma modulo feature.
196  * 2. The kPDM_EDMAMultiChannelInterleavePerChannelBlock feature support below dmic array only,
197  *    2 DMIC array: CHANNEL3, CHANNEL4
198  *    3 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5
199  *    4 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6
200  * Any other combinations is not support, that is to SAY, THE FEATURE SUPPORT RECEIVE START FROM CHANNEL3 ONLY AND 4
201  * MAXIMUM DMIC CHANNELS.
202  *
203  * @param base PDM base pointer
204  * @param handle PDM eDMA handle pointer.
205  * @param xfer Pointer to DMA transfer structure.
206  * @retval kStatus_Success Start a PDM eDMA receive successfully.
207  * @retval kStatus_InvalidArgument The input argument is invalid.
208  * @retval kStatus_RxBusy PDM is busy receiving data.
209  */
210 status_t PDM_TransferReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_transfer_t *xfer);
211 
212 /*!
213  * @brief Terminate all PDM receive.
214  *
215  * This function will clear all transfer slots buffered in the pdm queue. If users only want to abort the
216  * current transfer slot, please call PDM_TransferAbortReceiveEDMA.
217  *
218  * @param base PDM base pointer.
219  * @param handle PDM eDMA handle pointer.
220  */
221 void PDM_TransferTerminateReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle);
222 
223 /*!
224  * @brief Aborts a PDM receive using eDMA.
225  *
226  * This function only aborts the current transfer slots, the other transfer slots' information still kept
227  * in the handler. If users want to terminate all transfer slots, just call PDM_TransferTerminateReceiveEDMA.
228  *
229  * @param base PDM base pointer
230  * @param handle PDM eDMA handle pointer.
231  */
232 void PDM_TransferAbortReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle);
233 
234 /*!
235  * @brief Gets byte count received by PDM.
236  *
237  * @param base PDM base pointer
238  * @param handle PDM eDMA handle pointer.
239  * @param count Bytes count received by PDM.
240  * @retval kStatus_Success Succeed get the transfer count.
241  * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
242  */
243 status_t PDM_TransferGetReceiveCountEDMA(PDM_Type *base, pdm_edma_handle_t *handle, size_t *count);
244 
245 /*! @} */
246 
247 #if defined(__cplusplus)
248 }
249 #endif
250 
251 /*!
252  * @}
253  */
254 #endif
255