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_edma.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
16 typedef struct _flexio_uart_edma_private_handle
17 {
18 FLEXIO_UART_Type *base;
19 flexio_uart_edma_handle_t *handle;
20 } flexio_uart_edma_private_handle_t;
21
22 /* UART EDMA transfer handle. */
23 enum _flexio_uart_edma_tansfer_states
24 {
25 kFLEXIO_UART_TxIdle, /* TX idle. */
26 kFLEXIO_UART_TxBusy, /* TX busy. */
27 kFLEXIO_UART_RxIdle, /* RX idle. */
28 kFLEXIO_UART_RxBusy /* RX busy. */
29 };
30
31 /*******************************************************************************
32 * Definitions
33 ******************************************************************************/
34 /*< @brief user configurable flexio uart handle count. */
35 #define FLEXIO_UART_HANDLE_COUNT 2
36
37 /*<! Private handle only used for internally. */
38 static flexio_uart_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_UART_HANDLE_COUNT];
39
40 /*******************************************************************************
41 * Prototypes
42 ******************************************************************************/
43
44 /*!
45 * @brief FLEXIO UART EDMA send finished callback function.
46 *
47 * This function is called when FLEXIO UART EDMA send finished. It disables the UART
48 * TX EDMA request and sends @ref kStatus_FLEXIO_UART_TxIdle to FLEXIO UART callback.
49 *
50 * @param handle The EDMA handle.
51 * @param param Callback function parameter.
52 */
53 static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
54
55 /*!
56 * @brief FLEXIO UART EDMA receive finished callback function.
57 *
58 * This function is called when FLEXIO UART EDMA receive finished. It disables the UART
59 * RX EDMA request and sends @ref kStatus_FLEXIO_UART_RxIdle to UART callback.
60 *
61 * @param handle The EDMA handle.
62 * @param param Callback function parameter.
63 */
64 static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
65 void *param,
66 bool transferDone,
67 uint32_t tcds);
68
69 /*******************************************************************************
70 * Code
71 ******************************************************************************/
72
FLEXIO_UART_TransferSendEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)73 static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
74 {
75 flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
76
77 assert(uartPrivateHandle->handle);
78
79 /* Avoid the warning for unused variables. */
80 handle = handle;
81 tcds = tcds;
82
83 if (transferDone)
84 {
85 FLEXIO_UART_TransferAbortSendEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
86
87 if (uartPrivateHandle->handle->callback)
88 {
89 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
90 kStatus_FLEXIO_UART_TxIdle, uartPrivateHandle->handle->userData);
91 }
92 }
93 }
94
FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)95 static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
96 void *param,
97 bool transferDone,
98 uint32_t tcds)
99 {
100 flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
101
102 assert(uartPrivateHandle->handle);
103
104 /* Avoid the warning for unused variables. */
105 handle = handle;
106 tcds = tcds;
107
108 if (transferDone)
109 {
110 /* Disable transfer. */
111 FLEXIO_UART_TransferAbortReceiveEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
112
113 if (uartPrivateHandle->handle->callback)
114 {
115 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
116 kStatus_FLEXIO_UART_RxIdle, uartPrivateHandle->handle->userData);
117 }
118 }
119 }
120
FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_edma_transfer_callback_t callback,void * userData,edma_handle_t * txEdmaHandle,edma_handle_t * rxEdmaHandle)121 status_t FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type *base,
122 flexio_uart_edma_handle_t *handle,
123 flexio_uart_edma_transfer_callback_t callback,
124 void *userData,
125 edma_handle_t *txEdmaHandle,
126 edma_handle_t *rxEdmaHandle)
127 {
128 assert(handle);
129
130 uint8_t index = 0;
131
132 /* Find the an empty handle pointer to store the handle. */
133 for (index = 0; index < FLEXIO_UART_HANDLE_COUNT; index++)
134 {
135 if (s_edmaPrivateHandle[index].base == NULL)
136 {
137 s_edmaPrivateHandle[index].base = base;
138 s_edmaPrivateHandle[index].handle = handle;
139 break;
140 }
141 }
142
143 if (index == FLEXIO_UART_HANDLE_COUNT)
144 {
145 return kStatus_OutOfRange;
146 }
147
148 memset(handle, 0, sizeof(*handle));
149
150 handle->rxState = kFLEXIO_UART_RxIdle;
151 handle->txState = kFLEXIO_UART_TxIdle;
152
153 handle->rxEdmaHandle = rxEdmaHandle;
154 handle->txEdmaHandle = txEdmaHandle;
155
156 handle->callback = callback;
157 handle->userData = userData;
158
159 /* Configure TX. */
160 if (txEdmaHandle)
161 {
162 EDMA_SetCallback(handle->txEdmaHandle, FLEXIO_UART_TransferSendEDMACallback, &s_edmaPrivateHandle);
163 }
164
165 /* Configure RX. */
166 if (rxEdmaHandle)
167 {
168 EDMA_SetCallback(handle->rxEdmaHandle, FLEXIO_UART_TransferReceiveEDMACallback, &s_edmaPrivateHandle);
169 }
170
171 return kStatus_Success;
172 }
173
FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_transfer_t * xfer)174 status_t FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type *base,
175 flexio_uart_edma_handle_t *handle,
176 flexio_uart_transfer_t *xfer)
177 {
178 assert(handle->txEdmaHandle);
179
180 edma_transfer_config_t xferConfig;
181 status_t status;
182
183 /* Return error if xfer invalid. */
184 if ((0U == xfer->dataSize) || (NULL == xfer->data))
185 {
186 return kStatus_InvalidArgument;
187 }
188
189 /* If previous TX not finished. */
190 if (kFLEXIO_UART_TxBusy == handle->txState)
191 {
192 status = kStatus_FLEXIO_UART_TxBusy;
193 }
194 else
195 {
196 handle->txState = kFLEXIO_UART_TxBusy;
197 handle->txDataSizeAll = xfer->dataSize;
198
199 /* Prepare transfer. */
200 EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
201 (void *)FLEXIO_UART_GetTxDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
202 xfer->dataSize, kEDMA_MemoryToPeripheral);
203
204 /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
205 handle->nbytes = sizeof(uint8_t);
206
207 /* Submit transfer. */
208 EDMA_SubmitTransfer(handle->txEdmaHandle, &xferConfig);
209 EDMA_StartTransfer(handle->txEdmaHandle);
210
211 /* Enable UART TX EDMA. */
212 FLEXIO_UART_EnableTxDMA(base, true);
213
214 status = kStatus_Success;
215 }
216
217 return status;
218 }
219
FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,flexio_uart_transfer_t * xfer)220 status_t FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type *base,
221 flexio_uart_edma_handle_t *handle,
222 flexio_uart_transfer_t *xfer)
223 {
224 assert(handle->rxEdmaHandle);
225
226 edma_transfer_config_t xferConfig;
227 status_t status;
228
229 /* Return error if xfer invalid. */
230 if ((0U == xfer->dataSize) || (NULL == xfer->data))
231 {
232 return kStatus_InvalidArgument;
233 }
234
235 /* If previous RX not finished. */
236 if (kFLEXIO_UART_RxBusy == handle->rxState)
237 {
238 status = kStatus_FLEXIO_UART_RxBusy;
239 }
240 else
241 {
242 handle->rxState = kFLEXIO_UART_RxBusy;
243 handle->rxDataSizeAll = xfer->dataSize;
244
245 /* Prepare transfer. */
246 EDMA_PrepareTransfer(&xferConfig, (void *)FLEXIO_UART_GetRxDataRegisterAddress(base), sizeof(uint8_t),
247 xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
248
249 /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
250 handle->nbytes = sizeof(uint8_t);
251
252 /* Submit transfer. */
253 EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
254 EDMA_StartTransfer(handle->rxEdmaHandle);
255
256 /* Enable UART RX EDMA. */
257 FLEXIO_UART_EnableRxDMA(base, true);
258
259 status = kStatus_Success;
260 }
261
262 return status;
263 }
264
FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle)265 void FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
266 {
267 assert(handle->txEdmaHandle);
268
269 /* Disable UART TX EDMA. */
270 FLEXIO_UART_EnableTxDMA(base, false);
271
272 /* Stop transfer. */
273 EDMA_StopTransfer(handle->txEdmaHandle);
274
275 handle->txState = kFLEXIO_UART_TxIdle;
276 }
277
FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle)278 void FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
279 {
280 assert(handle->rxEdmaHandle);
281
282 /* Disable UART RX EDMA. */
283 FLEXIO_UART_EnableRxDMA(base, false);
284
285 /* Stop transfer. */
286 EDMA_StopTransfer(handle->rxEdmaHandle);
287
288 handle->rxState = kFLEXIO_UART_RxIdle;
289 }
290
FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,size_t * count)291 status_t FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type *base,
292 flexio_uart_edma_handle_t *handle,
293 size_t *count)
294 {
295 assert(handle);
296 assert(handle->rxEdmaHandle);
297 assert(count);
298
299 if (kFLEXIO_UART_RxIdle == handle->rxState)
300 {
301 return kStatus_NoTransferInProgress;
302 }
303
304 *count = handle->rxDataSizeAll -
305 (uint32_t)handle->nbytes *
306 EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel);
307
308 return kStatus_Success;
309 }
310
FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type * base,flexio_uart_edma_handle_t * handle,size_t * count)311 status_t FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle, size_t *count)
312 {
313 assert(handle);
314 assert(handle->txEdmaHandle);
315 assert(count);
316
317 if (kFLEXIO_UART_TxIdle == handle->txState)
318 {
319 return kStatus_NoTransferInProgress;
320 }
321
322 *count = handle->txDataSizeAll -
323 (uint32_t)handle->nbytes *
324 EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel);
325
326 return kStatus_Success;
327 }
328