1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_flexio_uart_dma.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.flexio_uart_dma"
18 #endif
19
20 /*<! @brief Structure definition for DMA callback param pass in. */
21 typedef struct _flexio_uart_dma_private_handle
22 {
23 FLEXIO_UART_Type *base;
24 flexio_uart_dma_handle_t *handle;
25 } flexio_uart_dma_private_handle_t;
26
27 /*<! @brief uart transfer state. */
28 enum _flexio_uart_dma_transfer_states
29 {
30 kFLEXIO_UART_TxIdle, /* TX idle. */
31 kFLEXIO_UART_TxBusy, /* TX busy. */
32 kFLEXIO_UART_RxIdle, /* RX idle. */
33 kFLEXIO_UART_RxBusy /* RX busy. */
34 };
35
36 /*******************************************************************************
37 * Variables
38 ******************************************************************************/
39
40 /*< @brief user configurable flexio uart handle count. */
41 #define FLEXIO_UART_HANDLE_COUNT 2
42
43 /*<! Private handle only used for internally. */
44 static flexio_uart_dma_private_handle_t s_dmaPrivateHandle[FLEXIO_UART_HANDLE_COUNT];
45
46 /*******************************************************************************
47 * Prototypes
48 ******************************************************************************/
49
50 /*!
51 * @brief FLEXIO UART DMA send finished callback function.
52 *
53 * This function is called when FLEXIO UART DMA send finished. It disables the UART
54 * TX DMA request and sends @ref kStatus_FLEXIO_UART_TxIdle to FLEXIO UART callback.
55 *
56 * @param handle The DMA handle.
57 * @param param Callback function parameter.
58 */
59 static void FLEXIO_UART_TransferSendDMACallback(dma_handle_t *handle, void *param);
60
61 /*!
62 * @brief FLEXIO UART DMA receive finished callback function.
63 *
64 * This function is called when FLEXIO UART DMA receive finished. It disables the FLEXIO
65 * UART RX DMA request and sends @ref kStatus_FLEXIO_UART_RxIdle to UART callback.
66 *
67 * @param handle The DMA handle.
68 * @param param Callback function parameter.
69 */
70 static void FLEXIO_UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param);
71
72 /*******************************************************************************
73 * Code
74 ******************************************************************************/
75
FLEXIO_UART_TransferSendDMACallback(dma_handle_t * handle,void * param)76 static void FLEXIO_UART_TransferSendDMACallback(dma_handle_t *handle, void *param)
77 {
78 flexio_uart_dma_private_handle_t *uartPrivateHandle = (flexio_uart_dma_private_handle_t *)param;
79
80 /* Disable UART TX DMA. */
81 FLEXIO_UART_EnableTxDMA(uartPrivateHandle->base, false);
82
83 /* Disable interrupt. */
84 DMA_DisableInterrupts(handle->base, handle->channel);
85
86 uartPrivateHandle->handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
87
88 if (uartPrivateHandle->handle->callback != NULL)
89 {
90 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
91 kStatus_FLEXIO_UART_TxIdle, uartPrivateHandle->handle->userData);
92 }
93 }
94
FLEXIO_UART_TransferReceiveDMACallback(dma_handle_t * handle,void * param)95 static void FLEXIO_UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param)
96 {
97 flexio_uart_dma_private_handle_t *uartPrivateHandle = (flexio_uart_dma_private_handle_t *)param;
98
99 /* Disable UART RX DMA. */
100 FLEXIO_UART_EnableRxDMA(uartPrivateHandle->base, false);
101
102 /* Disable interrupt. */
103 DMA_DisableInterrupts(handle->base, handle->channel);
104
105 uartPrivateHandle->handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
106
107 if (uartPrivateHandle->handle->callback != NULL)
108 {
109 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
110 kStatus_FLEXIO_UART_RxIdle, uartPrivateHandle->handle->userData);
111 }
112 }
113
114 /*!
115 * brief Initializes the FLEXIO_UART handle which is used in transactional functions.
116 *
117 * param base Pointer to FLEXIO_UART_Type structure.
118 * param handle Pointer to flexio_uart_dma_handle_t structure.
119 * param callback FlexIO UART callback, NULL means no callback.
120 * param userData User callback function data.
121 * param txDmaHandle User requested DMA handle for TX DMA transfer.
122 * param rxDmaHandle User requested DMA handle for RX DMA transfer.
123 * retval kStatus_Success Successfully create the handle.
124 * retval kStatus_OutOfRange The FlexIO UART DMA type/handle table out of range.
125 */
FLEXIO_UART_TransferCreateHandleDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,flexio_uart_dma_transfer_callback_t callback,void * userData,dma_handle_t * txDmaHandle,dma_handle_t * rxDmaHandle)126 status_t FLEXIO_UART_TransferCreateHandleDMA(FLEXIO_UART_Type *base,
127 flexio_uart_dma_handle_t *handle,
128 flexio_uart_dma_transfer_callback_t callback,
129 void *userData,
130 dma_handle_t *txDmaHandle,
131 dma_handle_t *rxDmaHandle)
132 {
133 assert(handle != NULL);
134
135 dma_transfer_config_t dmaXferConfig;
136 uint8_t index = 0;
137
138 /* Find the an empty handle pointer to store the handle. */
139 for (index = 0U; index < (uint8_t)FLEXIO_UART_HANDLE_COUNT; index++)
140 {
141 if (s_dmaPrivateHandle[index].base == NULL)
142 {
143 s_dmaPrivateHandle[index].base = base;
144 s_dmaPrivateHandle[index].handle = handle;
145 break;
146 }
147 }
148
149 if (index == (uint8_t)FLEXIO_UART_HANDLE_COUNT)
150 {
151 return kStatus_OutOfRange;
152 }
153
154 (void)memset(handle, 0, sizeof(*handle));
155
156 handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
157 handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
158
159 handle->callback = callback;
160 handle->userData = userData;
161
162 handle->rxDmaHandle = rxDmaHandle;
163 handle->txDmaHandle = txDmaHandle;
164
165 /* Set DMA channel configuration. */
166 (void)memset(&dmaXferConfig, 0, sizeof(dmaXferConfig));
167 dmaXferConfig.srcSize = kDMA_Transfersize8bits;
168 dmaXferConfig.destSize = kDMA_Transfersize8bits;
169
170 /* Configure TX. */
171 if (txDmaHandle != NULL)
172 {
173 DMA_SetCallback(txDmaHandle, FLEXIO_UART_TransferSendDMACallback, &s_dmaPrivateHandle[index]);
174
175 DMA_ResetChannel(txDmaHandle->base, txDmaHandle->channel);
176
177 dmaXferConfig.destAddr = FLEXIO_UART_GetTxDataRegisterAddress(base);
178 dmaXferConfig.enableSrcIncrement = true;
179 dmaXferConfig.enableDestIncrement = false;
180 DMA_SetTransferConfig(txDmaHandle->base, txDmaHandle->channel, &dmaXferConfig);
181 }
182
183 /* Configure RX. */
184 if (rxDmaHandle != NULL)
185 {
186 DMA_SetCallback(rxDmaHandle, FLEXIO_UART_TransferReceiveDMACallback, &s_dmaPrivateHandle[index]);
187
188 DMA_ResetChannel(rxDmaHandle->base, rxDmaHandle->channel);
189
190 dmaXferConfig.destAddr = 0U;
191 dmaXferConfig.srcAddr = FLEXIO_UART_GetRxDataRegisterAddress(base);
192 dmaXferConfig.enableSrcIncrement = false;
193 dmaXferConfig.enableDestIncrement = true;
194 DMA_SetTransferConfig(rxDmaHandle->base, rxDmaHandle->channel, &dmaXferConfig);
195 }
196
197 return kStatus_Success;
198 }
199
200 /*!
201 * brief Sends data using DMA.
202 *
203 * This function send data using DMA. This is non-blocking function, which returns
204 * right away. When all data is sent out, the send callback function is called.
205 *
206 * param base Pointer to FLEXIO_UART_Type structure
207 * param handle Pointer to flexio_uart_dma_handle_t structure
208 * param xfer FLEXIO_UART DMA transfer structure, see #flexio_uart_transfer_t.
209 * retval kStatus_Success if succeed, others failed.
210 * retval kStatus_FLEXIO_UART_TxBusy Previous transfer on going.
211 */
FLEXIO_UART_TransferSendDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,flexio_uart_transfer_t * xfer)212 status_t FLEXIO_UART_TransferSendDMA(FLEXIO_UART_Type *base,
213 flexio_uart_dma_handle_t *handle,
214 flexio_uart_transfer_t *xfer)
215 {
216 assert(handle->txDmaHandle != NULL);
217
218 status_t status;
219
220 /* Return error if xfer invalid. */
221 if ((0U == xfer->dataSize) || (NULL == xfer->data))
222 {
223 return kStatus_InvalidArgument;
224 }
225
226 /* If previous TX not finished. */
227 if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
228 {
229 status = kStatus_FLEXIO_UART_TxBusy;
230 }
231 else
232 {
233 handle->txState = (uint8_t)kFLEXIO_UART_TxBusy;
234 handle->txDataSizeAll = xfer->dataSize;
235
236 /* Set transfer data address and data size. */
237 DMA_SetSourceAddress(handle->txDmaHandle->base, handle->txDmaHandle->channel, (uint32_t)xfer->data);
238 DMA_SetTransferSize(handle->txDmaHandle->base, handle->txDmaHandle->channel, xfer->dataSize);
239
240 /* Enable FLEXIO UART TX DMA. */
241 FLEXIO_UART_EnableTxDMA(base, true);
242
243 /* Enable DMA transfer complete interrupt and start transfer. */
244 DMA_EnableInterrupts(handle->txDmaHandle->base, handle->txDmaHandle->channel);
245 DMA_EnableChannelRequest(handle->txDmaHandle->base, handle->txDmaHandle->channel);
246
247 status = kStatus_Success;
248 }
249
250 return status;
251 }
252
253 /*!
254 * brief Receives data using DMA.
255 *
256 * This function receives data using DMA. This is non-blocking function, which returns
257 * right away. When all data is received, the receive callback function is called.
258 *
259 * param base Pointer to FLEXIO_UART_Type structure
260 * param handle Pointer to flexio_uart_dma_handle_t structure
261 * param xfer FLEXIO_UART DMA transfer structure, see #flexio_uart_transfer_t.
262 * retval kStatus_Success if succeed, others failed.
263 * retval kStatus_FLEXIO_UART_RxBusy Previous transfer on going.
264 */
FLEXIO_UART_TransferReceiveDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,flexio_uart_transfer_t * xfer)265 status_t FLEXIO_UART_TransferReceiveDMA(FLEXIO_UART_Type *base,
266 flexio_uart_dma_handle_t *handle,
267 flexio_uart_transfer_t *xfer)
268 {
269 assert(handle->rxDmaHandle != NULL);
270
271 status_t status;
272
273 /* Return error if xfer invalid. */
274 if ((0U == xfer->dataSize) || (NULL == xfer->data))
275 {
276 return kStatus_InvalidArgument;
277 }
278
279 /* If previous RX not finished. */
280 if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
281 {
282 status = kStatus_FLEXIO_UART_RxBusy;
283 }
284 else
285 {
286 handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
287 handle->rxDataSizeAll = xfer->dataSize;
288
289 /* Set transfer data address and data size. */
290 DMA_SetDestinationAddress(handle->rxDmaHandle->base, handle->rxDmaHandle->channel, (uint32_t)xfer->data);
291 DMA_SetTransferSize(handle->rxDmaHandle->base, handle->rxDmaHandle->channel, xfer->dataSize);
292
293 /* Enable FLEXIO UART RX DMA. */
294 FLEXIO_UART_EnableRxDMA(base, true);
295
296 /* Enable DMA transfer complete interrupt and start transfer. */
297 DMA_EnableInterrupts(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
298 DMA_EnableChannelRequest(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
299
300 status = kStatus_Success;
301 }
302
303 return status;
304 }
305
306 /*!
307 * brief Aborts the sent data which using DMA.
308 *
309 * This function aborts the sent data which using DMA.
310 *
311 * param base Pointer to FLEXIO_UART_Type structure
312 * param handle Pointer to flexio_uart_dma_handle_t structure
313 */
FLEXIO_UART_TransferAbortSendDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle)314 void FLEXIO_UART_TransferAbortSendDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle)
315 {
316 assert(handle->txDmaHandle != NULL);
317
318 /* Disable FLEXIO UART TX DMA. */
319 FLEXIO_UART_EnableTxDMA(base, false);
320
321 /* Stop transfer. */
322 DMA_StopTransfer(handle->txDmaHandle);
323
324 /* Write DMA->DSR[DONE] to abort transfer and clear status. */
325 DMA_ClearChannelStatusFlags(handle->txDmaHandle->base, handle->txDmaHandle->channel,
326 (uint32_t)kDMA_TransactionsDoneFlag);
327
328 handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
329 }
330
331 /*!
332 * brief Aborts the receive data which using DMA.
333 *
334 * This function aborts the receive data which using DMA.
335 *
336 * param base Pointer to FLEXIO_UART_Type structure
337 * param handle Pointer to flexio_uart_dma_handle_t structure
338 */
FLEXIO_UART_TransferAbortReceiveDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle)339 void FLEXIO_UART_TransferAbortReceiveDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle)
340 {
341 assert(handle->rxDmaHandle != NULL);
342
343 /* Disable FLEXIO UART RX DMA. */
344 FLEXIO_UART_EnableRxDMA(base, false);
345
346 /* Stop transfer. */
347 DMA_StopTransfer(handle->rxDmaHandle);
348
349 /* Write DMA->DSR[DONE] to abort transfer and clear status. */
350 DMA_ClearChannelStatusFlags(handle->rxDmaHandle->base, handle->rxDmaHandle->channel,
351 (uint32_t)kDMA_TransactionsDoneFlag);
352
353 handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
354 }
355
356 /*!
357 * brief Gets the number of bytes sent out.
358 *
359 * This function gets the number of bytes sent out.
360 *
361 * param base Pointer to FLEXIO_UART_Type structure
362 * param handle Pointer to flexio_uart_dma_handle_t structure
363 * param count Number of bytes sent so far by the non-blocking transaction.
364 * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
365 * retval kStatus_Success Successfully return the count.
366 */
FLEXIO_UART_TransferGetSendCountDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,size_t * count)367 status_t FLEXIO_UART_TransferGetSendCountDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle, size_t *count)
368 {
369 assert(handle != NULL);
370 assert(handle->txDmaHandle != NULL);
371 assert(count != NULL);
372
373 if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
374 {
375 return kStatus_NoTransferInProgress;
376 }
377
378 *count = handle->txDataSizeAll - DMA_GetRemainingBytes(handle->txDmaHandle->base, handle->txDmaHandle->channel);
379
380 return kStatus_Success;
381 }
382
383 /*!
384 * brief Gets the number of bytes received.
385 *
386 * This function gets the number of bytes received.
387 *
388 * param base Pointer to FLEXIO_UART_Type structure
389 * param handle Pointer to flexio_uart_dma_handle_t structure
390 * param count Number of bytes received so far by the non-blocking transaction.
391 * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
392 * retval kStatus_Success Successfully return the count.
393 */
FLEXIO_UART_TransferGetReceiveCountDMA(FLEXIO_UART_Type * base,flexio_uart_dma_handle_t * handle,size_t * count)394 status_t FLEXIO_UART_TransferGetReceiveCountDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle, size_t *count)
395 {
396 assert(handle != NULL);
397 assert(handle->rxDmaHandle != NULL);
398 assert(count != NULL);
399
400 if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
401 {
402 return kStatus_NoTransferInProgress;
403 }
404
405 *count = handle->rxDataSizeAll - DMA_GetRemainingBytes(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
406
407 return kStatus_Success;
408 }
409