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_spi_edma.h"
10
11 /*******************************************************************************
12 * Definitons
13 ******************************************************************************/
14 /*<! Structure definition for spi_edma_private_handle_t. The structure is private. */
15 typedef struct _flexio_spi_master_edma_private_handle
16 {
17 FLEXIO_SPI_Type *base;
18 flexio_spi_master_edma_handle_t *handle;
19 } flexio_spi_master_edma_private_handle_t;
20
21 /*******************************************************************************
22 * Prototypes
23 ******************************************************************************/
24
25 /*!
26 * @brief EDMA callback function for FLEXIO SPI send transfer.
27 *
28 * @param handle EDMA handle pointer.
29 * @param param Callback function parameter.
30 */
31 static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
32
33 /*!
34 * @brief EDMA callback function for FLEXIO SPI receive transfer.
35 *
36 * @param handle EDMA handle pointer.
37 * @param param Callback function parameter.
38 */
39 static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
40
41 /*!
42 * @brief EDMA config for FLEXIO SPI transfer.
43 *
44 * @param base pointer to FLEXIO_SPI_Type structure.
45 * @param handle pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
46 * @param xfer Pointer to flexio spi transfer structure.
47 */
48 static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
49 flexio_spi_master_edma_handle_t *handle,
50 flexio_spi_transfer_t *xfer);
51
52 /*******************************************************************************
53 * Variables
54 ******************************************************************************/
55
56 /* Dummy data used to send */
57 static const uint16_t s_dummyData = FLEXIO_SPI_DUMMYDATA;
58
59 /*< @brief user configurable flexio spi handle count. */
60 #define FLEXIO_SPI_HANDLE_COUNT 2
61
62 /*<! Private handle only used for internally. */
63 static flexio_spi_master_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_SPI_HANDLE_COUNT];
64
65 /*******************************************************************************
66 * Code
67 ******************************************************************************/
68
FLEXIO_SPI_TxEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)69 static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
70 {
71 tcds = tcds;
72 flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
73
74 /* Disable Tx DMA */
75 if (transferDone)
76 {
77 FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, kFLEXIO_SPI_TxDmaEnable, false);
78
79 /* change the state */
80 spiPrivateHandle->handle->txInProgress = false;
81
82 /* All finished, call the callback */
83 if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
84 {
85 if (spiPrivateHandle->handle->callback)
86 {
87 (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
88 spiPrivateHandle->handle->userData);
89 }
90 }
91 }
92 }
93
FLEXIO_SPI_RxEDMACallback(edma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)94 static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
95 {
96 tcds = tcds;
97 flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
98
99 if (transferDone)
100 {
101 /* Disable Rx dma */
102 FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, kFLEXIO_SPI_RxDmaEnable, false);
103
104 /* change the state */
105 spiPrivateHandle->handle->rxInProgress = false;
106
107 /* All finished, call the callback */
108 if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
109 {
110 if (spiPrivateHandle->handle->callback)
111 {
112 (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
113 spiPrivateHandle->handle->userData);
114 }
115 }
116 }
117 }
118
FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type * base,flexio_spi_master_edma_handle_t * handle,flexio_spi_transfer_t * xfer)119 static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
120 flexio_spi_master_edma_handle_t *handle,
121 flexio_spi_transfer_t *xfer)
122 {
123 edma_transfer_config_t xferConfig;
124 flexio_spi_shift_direction_t direction;
125 uint8_t bytesPerFrame;
126
127 /* Configure the values in handle. */
128 switch (xfer->flags)
129 {
130 case kFLEXIO_SPI_8bitMsb:
131 bytesPerFrame = 1;
132 direction = kFLEXIO_SPI_MsbFirst;
133 break;
134 case kFLEXIO_SPI_8bitLsb:
135 bytesPerFrame = 1;
136 direction = kFLEXIO_SPI_LsbFirst;
137 break;
138 case kFLEXIO_SPI_16bitMsb:
139 bytesPerFrame = 2;
140 direction = kFLEXIO_SPI_MsbFirst;
141 break;
142 case kFLEXIO_SPI_16bitLsb:
143 bytesPerFrame = 2;
144 direction = kFLEXIO_SPI_LsbFirst;
145 break;
146 default:
147 bytesPerFrame = 1U;
148 direction = kFLEXIO_SPI_MsbFirst;
149 assert(true);
150 break;
151 }
152
153 /* Save total transfer size. */
154 handle->transferSize = xfer->dataSize;
155
156 /* Configure tx transfer EDMA. */
157 xferConfig.destAddr = FLEXIO_SPI_GetTxDataRegisterAddress(base, direction);
158 xferConfig.destOffset = 0;
159 if (bytesPerFrame == 1U)
160 {
161 xferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
162 xferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
163 xferConfig.minorLoopBytes = 1;
164 }
165 else
166 {
167 if (direction == kFLEXIO_SPI_MsbFirst)
168 {
169 xferConfig.destAddr -= 1U;
170 }
171 xferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
172 xferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
173 xferConfig.minorLoopBytes = 2;
174 }
175
176 /* Configure DMA channel. */
177 if (xfer->txData)
178 {
179 xferConfig.srcOffset = bytesPerFrame;
180 xferConfig.srcAddr = (uint32_t)(xfer->txData);
181 }
182 else
183 {
184 /* Disable the source increasement and source set to dummyData. */
185 xferConfig.srcOffset = 0;
186 xferConfig.srcAddr = (uint32_t)(&s_dummyData);
187 }
188
189 xferConfig.majorLoopCounts = (xfer->dataSize / xferConfig.minorLoopBytes);
190
191 /* Store the initially configured eDMA minor byte transfer count into the FLEXIO SPI handle */
192 handle->nbytes = xferConfig.minorLoopBytes;
193
194 if (handle->txHandle)
195 {
196 EDMA_SubmitTransfer(handle->txHandle, &xferConfig);
197 }
198
199 /* Configure tx transfer EDMA. */
200 if (xfer->rxData)
201 {
202 xferConfig.srcAddr = FLEXIO_SPI_GetRxDataRegisterAddress(base, direction);
203 if (bytesPerFrame == 2U)
204 {
205 if (direction == kFLEXIO_SPI_LsbFirst)
206 {
207 xferConfig.srcAddr -= 1U;
208 }
209 }
210 xferConfig.srcOffset = 0;
211 xferConfig.destAddr = (uint32_t)(xfer->rxData);
212 xferConfig.destOffset = bytesPerFrame;
213 EDMA_SubmitTransfer(handle->rxHandle, &xferConfig);
214 handle->rxInProgress = true;
215 FLEXIO_SPI_EnableDMA(base, kFLEXIO_SPI_RxDmaEnable, true);
216 EDMA_StartTransfer(handle->rxHandle);
217 }
218
219 /* Always start Tx transfer. */
220 if (handle->txHandle)
221 {
222 handle->txInProgress = true;
223 FLEXIO_SPI_EnableDMA(base, kFLEXIO_SPI_TxDmaEnable, true);
224 EDMA_StartTransfer(handle->txHandle);
225 }
226 }
227
FLEXIO_SPI_MasterTransferCreateHandleEDMA(FLEXIO_SPI_Type * base,flexio_spi_master_edma_handle_t * handle,flexio_spi_master_edma_transfer_callback_t callback,void * userData,edma_handle_t * txHandle,edma_handle_t * rxHandle)228 status_t FLEXIO_SPI_MasterTransferCreateHandleEDMA(FLEXIO_SPI_Type *base,
229 flexio_spi_master_edma_handle_t *handle,
230 flexio_spi_master_edma_transfer_callback_t callback,
231 void *userData,
232 edma_handle_t *txHandle,
233 edma_handle_t *rxHandle)
234 {
235 assert(handle);
236
237 uint8_t index = 0;
238
239 /* Find the an empty handle pointer to store the handle. */
240 for (index = 0; index < FLEXIO_SPI_HANDLE_COUNT; index++)
241 {
242 if (s_edmaPrivateHandle[index].base == NULL)
243 {
244 s_edmaPrivateHandle[index].base = base;
245 s_edmaPrivateHandle[index].handle = handle;
246 break;
247 }
248 }
249
250 if (index == FLEXIO_SPI_HANDLE_COUNT)
251 {
252 return kStatus_OutOfRange;
253 }
254
255 /* Set spi base to handle. */
256 handle->txHandle = txHandle;
257 handle->rxHandle = rxHandle;
258
259 /* Register callback and userData. */
260 handle->callback = callback;
261 handle->userData = userData;
262
263 /* Set SPI state to idle. */
264 handle->txInProgress = false;
265 handle->rxInProgress = false;
266
267 /* Install callback for Tx/Rx dma channel. */
268 if (handle->txHandle)
269 {
270 EDMA_SetCallback(handle->txHandle, FLEXIO_SPI_TxEDMACallback, &s_edmaPrivateHandle[index]);
271 }
272 if (handle->rxHandle)
273 {
274 EDMA_SetCallback(handle->rxHandle, FLEXIO_SPI_RxEDMACallback, &s_edmaPrivateHandle[index]);
275 }
276
277 return kStatus_Success;
278 }
279
FLEXIO_SPI_MasterTransferEDMA(FLEXIO_SPI_Type * base,flexio_spi_master_edma_handle_t * handle,flexio_spi_transfer_t * xfer)280 status_t FLEXIO_SPI_MasterTransferEDMA(FLEXIO_SPI_Type *base,
281 flexio_spi_master_edma_handle_t *handle,
282 flexio_spi_transfer_t *xfer)
283 {
284 assert(handle);
285 assert(xfer);
286
287 uint32_t dataMode = 0;
288 uint16_t timerCmp = base->flexioBase->TIMCMP[base->timerIndex[0]];
289
290 timerCmp &= 0x00FFU;
291
292 /* Check if the device is busy. */
293 if ((handle->txInProgress) || (handle->rxInProgress))
294 {
295 return kStatus_FLEXIO_SPI_Busy;
296 }
297
298 /* Check if input parameter invalid. */
299 if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
300 {
301 return kStatus_InvalidArgument;
302 }
303
304 /* configure data mode. */
305 if ((xfer->flags == kFLEXIO_SPI_8bitMsb) || (xfer->flags == kFLEXIO_SPI_8bitLsb))
306 {
307 dataMode = (8 * 2 - 1U) << 8U;
308 }
309 else if ((xfer->flags == kFLEXIO_SPI_16bitMsb) || (xfer->flags == kFLEXIO_SPI_16bitLsb))
310 {
311 dataMode = (16 * 2 - 1U) << 8U;
312 }
313 else
314 {
315 dataMode = 8 * 2 - 1U;
316 }
317
318 dataMode |= timerCmp;
319
320 base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
321
322 FLEXIO_SPI_EDMAConfig(base, handle, xfer);
323
324 return kStatus_Success;
325 }
326
FLEXIO_SPI_MasterTransferGetCountEDMA(FLEXIO_SPI_Type * base,flexio_spi_master_edma_handle_t * handle,size_t * count)327 status_t FLEXIO_SPI_MasterTransferGetCountEDMA(FLEXIO_SPI_Type *base,
328 flexio_spi_master_edma_handle_t *handle,
329 size_t *count)
330 {
331 assert(handle);
332
333 if (!count)
334 {
335 return kStatus_InvalidArgument;
336 }
337
338 if (handle->rxInProgress)
339 {
340 *count = (handle->transferSize -
341 (uint32_t)handle->nbytes *
342 EDMA_GetRemainingMajorLoopCount(handle->rxHandle->base, handle->rxHandle->channel));
343 }
344 else
345 {
346 *count = (handle->transferSize -
347 (uint32_t)handle->nbytes *
348 EDMA_GetRemainingMajorLoopCount(handle->txHandle->base, handle->txHandle->channel));
349 }
350
351 return kStatus_Success;
352 }
353
FLEXIO_SPI_MasterTransferAbortEDMA(FLEXIO_SPI_Type * base,flexio_spi_master_edma_handle_t * handle)354 void FLEXIO_SPI_MasterTransferAbortEDMA(FLEXIO_SPI_Type *base, flexio_spi_master_edma_handle_t *handle)
355 {
356 assert(handle);
357
358 /* Disable dma. */
359 EDMA_StopTransfer(handle->txHandle);
360 EDMA_StopTransfer(handle->rxHandle);
361
362 /* Disable DMA enable bit. */
363 FLEXIO_SPI_EnableDMA(base, kFLEXIO_SPI_DmaAllEnable, false);
364
365 /* Set the handle state. */
366 handle->txInProgress = false;
367 handle->rxInProgress = false;
368 }
369
FLEXIO_SPI_SlaveTransferEDMA(FLEXIO_SPI_Type * base,flexio_spi_slave_edma_handle_t * handle,flexio_spi_transfer_t * xfer)370 status_t FLEXIO_SPI_SlaveTransferEDMA(FLEXIO_SPI_Type *base,
371 flexio_spi_slave_edma_handle_t *handle,
372 flexio_spi_transfer_t *xfer)
373 {
374 assert(handle);
375 assert(xfer);
376
377 uint32_t dataMode = 0;
378
379 /* Check if the device is busy. */
380 if ((handle->txInProgress) || (handle->rxInProgress))
381 {
382 return kStatus_FLEXIO_SPI_Busy;
383 }
384
385 /* Check if input parameter invalid. */
386 if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
387 {
388 return kStatus_InvalidArgument;
389 }
390
391 /* configure data mode. */
392 if ((xfer->flags == kFLEXIO_SPI_8bitMsb) || (xfer->flags == kFLEXIO_SPI_8bitLsb))
393 {
394 dataMode = 8 * 2 - 1U;
395 }
396 else if ((xfer->flags == kFLEXIO_SPI_16bitMsb) || (xfer->flags == kFLEXIO_SPI_16bitLsb))
397 {
398 dataMode = 16 * 2 - 1U;
399 }
400 else
401 {
402 dataMode = 8 * 2 - 1U;
403 }
404
405 base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
406
407 FLEXIO_SPI_EDMAConfig(base, handle, xfer);
408
409 return kStatus_Success;
410 }
411