fsl_flexio_spi_edma.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. * The Clear BSD License
  3. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  4. * Copyright 2016-2017 NXP
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted (subject to the limitations in the disclaimer below) provided
  9. * that the following conditions are met:
  10. *
  11. * o Redistributions of source code must retain the above copyright notice, this list
  12. * of conditions and the following disclaimer.
  13. *
  14. * o Redistributions in binary form must reproduce the above copyright notice, this
  15. * list of conditions and the following disclaimer in the documentation and/or
  16. * other materials provided with the distribution.
  17. *
  18. * o Neither the name of the copyright holder nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  27. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "fsl_flexio_spi_edma.h"
  35. /*******************************************************************************
  36. * Definitions
  37. ******************************************************************************/
  38. /* Component ID definition, used by tools. */
  39. #ifndef FSL_COMPONENT_ID
  40. #define FSL_COMPONENT_ID "platform.drivers.flexio_spi_edma"
  41. #endif
  42. /*<! Structure definition for spi_edma_private_handle_t. The structure is private. */
  43. typedef struct _flexio_spi_master_edma_private_handle
  44. {
  45. FLEXIO_SPI_Type *base;
  46. flexio_spi_master_edma_handle_t *handle;
  47. } flexio_spi_master_edma_private_handle_t;
  48. /*******************************************************************************
  49. * Prototypes
  50. ******************************************************************************/
  51. /*!
  52. * @brief EDMA callback function for FLEXIO SPI send transfer.
  53. *
  54. * @param handle EDMA handle pointer.
  55. * @param param Callback function parameter.
  56. */
  57. static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
  58. /*!
  59. * @brief EDMA callback function for FLEXIO SPI receive transfer.
  60. *
  61. * @param handle EDMA handle pointer.
  62. * @param param Callback function parameter.
  63. */
  64. static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
  65. /*!
  66. * @brief EDMA config for FLEXIO SPI transfer.
  67. *
  68. * @param base pointer to FLEXIO_SPI_Type structure.
  69. * @param handle pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
  70. * @param xfer Pointer to flexio spi transfer structure.
  71. */
  72. static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
  73. flexio_spi_master_edma_handle_t *handle,
  74. flexio_spi_transfer_t *xfer);
  75. /*******************************************************************************
  76. * Variables
  77. ******************************************************************************/
  78. /* Dummy data used to send */
  79. static const uint16_t s_dummyData = FLEXIO_SPI_DUMMYDATA;
  80. /*< @brief user configurable flexio spi handle count. */
  81. #define FLEXIO_SPI_HANDLE_COUNT 2
  82. /*<! Private handle only used for internally. */
  83. static flexio_spi_master_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_SPI_HANDLE_COUNT];
  84. /*******************************************************************************
  85. * Code
  86. ******************************************************************************/
  87. static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
  88. {
  89. tcds = tcds;
  90. flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
  91. /* Disable Tx DMA */
  92. if (transferDone)
  93. {
  94. FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, kFLEXIO_SPI_TxDmaEnable, false);
  95. /* change the state */
  96. spiPrivateHandle->handle->txInProgress = false;
  97. /* All finished, call the callback */
  98. if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
  99. {
  100. if (spiPrivateHandle->handle->callback)
  101. {
  102. (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
  103. spiPrivateHandle->handle->userData);
  104. }
  105. }
  106. }
  107. }
  108. static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
  109. {
  110. tcds = tcds;
  111. flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
  112. if (transferDone)
  113. {
  114. /* Disable Rx dma */
  115. FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, kFLEXIO_SPI_RxDmaEnable, false);
  116. /* change the state */
  117. spiPrivateHandle->handle->rxInProgress = false;
  118. /* All finished, call the callback */
  119. if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
  120. {
  121. if (spiPrivateHandle->handle->callback)
  122. {
  123. (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
  124. spiPrivateHandle->handle->userData);
  125. }
  126. }
  127. }
  128. }
  129. static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
  130. flexio_spi_master_edma_handle_t *handle,
  131. flexio_spi_transfer_t *xfer)
  132. {
  133. edma_transfer_config_t xferConfig;
  134. flexio_spi_shift_direction_t direction;
  135. uint8_t bytesPerFrame;
  136. /* Configure the values in handle. */
  137. switch (xfer->flags)
  138. {
  139. case kFLEXIO_SPI_8bitMsb:
  140. bytesPerFrame = 1;
  141. direction = kFLEXIO_SPI_MsbFirst;
  142. break;
  143. case kFLEXIO_SPI_8bitLsb:
  144. bytesPerFrame = 1;
  145. direction = kFLEXIO_SPI_LsbFirst;
  146. break;
  147. case kFLEXIO_SPI_16bitMsb:
  148. bytesPerFrame = 2;
  149. direction = kFLEXIO_SPI_MsbFirst;
  150. break;
  151. case kFLEXIO_SPI_16bitLsb:
  152. bytesPerFrame = 2;
  153. direction = kFLEXIO_SPI_LsbFirst;
  154. break;
  155. default:
  156. bytesPerFrame = 1U;
  157. direction = kFLEXIO_SPI_MsbFirst;
  158. assert(true);
  159. break;
  160. }
  161. /* Save total transfer size. */
  162. handle->transferSize = xfer->dataSize;
  163. /* Configure tx transfer EDMA. */
  164. xferConfig.destAddr = FLEXIO_SPI_GetTxDataRegisterAddress(base, direction);
  165. xferConfig.destOffset = 0;
  166. if (bytesPerFrame == 1U)
  167. {
  168. xferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
  169. xferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
  170. xferConfig.minorLoopBytes = 1;
  171. }
  172. else
  173. {
  174. if (direction == kFLEXIO_SPI_MsbFirst)
  175. {
  176. xferConfig.destAddr -= 1U;
  177. }
  178. xferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
  179. xferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
  180. xferConfig.minorLoopBytes = 2;
  181. }
  182. /* Configure DMA channel. */
  183. if (xfer->txData)
  184. {
  185. xferConfig.srcOffset = bytesPerFrame;
  186. xferConfig.srcAddr = (uint32_t)(xfer->txData);
  187. }
  188. else
  189. {
  190. /* Disable the source increasement and source set to dummyData. */
  191. xferConfig.srcOffset = 0;
  192. xferConfig.srcAddr = (uint32_t)(&s_dummyData);
  193. }
  194. xferConfig.majorLoopCounts = (xfer->dataSize / xferConfig.minorLoopBytes);
  195. /* Store the initially configured eDMA minor byte transfer count into the FLEXIO SPI handle */
  196. handle->nbytes = xferConfig.minorLoopBytes;
  197. if (handle->txHandle)
  198. {
  199. EDMA_SubmitTransfer(handle->txHandle, &xferConfig);
  200. }
  201. /* Configure tx transfer EDMA. */
  202. if (xfer->rxData)
  203. {
  204. xferConfig.srcAddr = FLEXIO_SPI_GetRxDataRegisterAddress(base, direction);
  205. if (bytesPerFrame == 2U)
  206. {
  207. if (direction == kFLEXIO_SPI_LsbFirst)
  208. {
  209. xferConfig.srcAddr -= 1U;
  210. }
  211. }
  212. xferConfig.srcOffset = 0;
  213. xferConfig.destAddr = (uint32_t)(xfer->rxData);
  214. xferConfig.destOffset = bytesPerFrame;
  215. EDMA_SubmitTransfer(handle->rxHandle, &xferConfig);
  216. handle->rxInProgress = true;
  217. FLEXIO_SPI_EnableDMA(base, kFLEXIO_SPI_RxDmaEnable, true);
  218. EDMA_StartTransfer(handle->rxHandle);
  219. }
  220. /* Always start Tx transfer. */
  221. if (handle->txHandle)
  222. {
  223. handle->txInProgress = true;
  224. FLEXIO_SPI_EnableDMA(base, kFLEXIO_SPI_TxDmaEnable, true);
  225. EDMA_StartTransfer(handle->txHandle);
  226. }
  227. }
  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. uint8_t index = 0;
  237. /* Find the an empty handle pointer to store the handle. */
  238. for (index = 0; index < FLEXIO_SPI_HANDLE_COUNT; index++)
  239. {
  240. if (s_edmaPrivateHandle[index].base == NULL)
  241. {
  242. s_edmaPrivateHandle[index].base = base;
  243. s_edmaPrivateHandle[index].handle = handle;
  244. break;
  245. }
  246. }
  247. if (index == FLEXIO_SPI_HANDLE_COUNT)
  248. {
  249. return kStatus_OutOfRange;
  250. }
  251. /* Set spi base to handle. */
  252. handle->txHandle = txHandle;
  253. handle->rxHandle = rxHandle;
  254. /* Register callback and userData. */
  255. handle->callback = callback;
  256. handle->userData = userData;
  257. /* Set SPI state to idle. */
  258. handle->txInProgress = false;
  259. handle->rxInProgress = false;
  260. /* Install callback for Tx/Rx dma channel. */
  261. if (handle->txHandle)
  262. {
  263. EDMA_SetCallback(handle->txHandle, FLEXIO_SPI_TxEDMACallback, &s_edmaPrivateHandle[index]);
  264. }
  265. if (handle->rxHandle)
  266. {
  267. EDMA_SetCallback(handle->rxHandle, FLEXIO_SPI_RxEDMACallback, &s_edmaPrivateHandle[index]);
  268. }
  269. return kStatus_Success;
  270. }
  271. status_t FLEXIO_SPI_MasterTransferEDMA(FLEXIO_SPI_Type *base,
  272. flexio_spi_master_edma_handle_t *handle,
  273. flexio_spi_transfer_t *xfer)
  274. {
  275. assert(handle);
  276. assert(xfer);
  277. uint32_t dataMode = 0;
  278. uint16_t timerCmp = base->flexioBase->TIMCMP[base->timerIndex[0]];
  279. timerCmp &= 0x00FFU;
  280. /* Check if the device is busy. */
  281. if ((handle->txInProgress) || (handle->rxInProgress))
  282. {
  283. return kStatus_FLEXIO_SPI_Busy;
  284. }
  285. /* Check if input parameter invalid. */
  286. if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
  287. {
  288. return kStatus_InvalidArgument;
  289. }
  290. /* configure data mode. */
  291. if ((xfer->flags == kFLEXIO_SPI_8bitMsb) || (xfer->flags == kFLEXIO_SPI_8bitLsb))
  292. {
  293. dataMode = (8 * 2 - 1U) << 8U;
  294. }
  295. else if ((xfer->flags == kFLEXIO_SPI_16bitMsb) || (xfer->flags == kFLEXIO_SPI_16bitLsb))
  296. {
  297. dataMode = (16 * 2 - 1U) << 8U;
  298. }
  299. else
  300. {
  301. dataMode = 8 * 2 - 1U;
  302. }
  303. dataMode |= timerCmp;
  304. base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
  305. FLEXIO_SPI_EDMAConfig(base, handle, xfer);
  306. return kStatus_Success;
  307. }
  308. status_t FLEXIO_SPI_MasterTransferGetCountEDMA(FLEXIO_SPI_Type *base,
  309. flexio_spi_master_edma_handle_t *handle,
  310. size_t *count)
  311. {
  312. assert(handle);
  313. if (!count)
  314. {
  315. return kStatus_InvalidArgument;
  316. }
  317. if (handle->rxInProgress)
  318. {
  319. *count = (handle->transferSize -
  320. (uint32_t)handle->nbytes *
  321. EDMA_GetRemainingMajorLoopCount(handle->rxHandle->base, handle->rxHandle->channel));
  322. }
  323. else
  324. {
  325. *count = (handle->transferSize -
  326. (uint32_t)handle->nbytes *
  327. EDMA_GetRemainingMajorLoopCount(handle->txHandle->base, handle->txHandle->channel));
  328. }
  329. return kStatus_Success;
  330. }
  331. void FLEXIO_SPI_MasterTransferAbortEDMA(FLEXIO_SPI_Type *base, flexio_spi_master_edma_handle_t *handle)
  332. {
  333. assert(handle);
  334. /* Disable dma. */
  335. EDMA_StopTransfer(handle->txHandle);
  336. EDMA_StopTransfer(handle->rxHandle);
  337. /* Disable DMA enable bit. */
  338. FLEXIO_SPI_EnableDMA(base, kFLEXIO_SPI_DmaAllEnable, false);
  339. /* Set the handle state. */
  340. handle->txInProgress = false;
  341. handle->rxInProgress = false;
  342. }
  343. status_t FLEXIO_SPI_SlaveTransferEDMA(FLEXIO_SPI_Type *base,
  344. flexio_spi_slave_edma_handle_t *handle,
  345. flexio_spi_transfer_t *xfer)
  346. {
  347. assert(handle);
  348. assert(xfer);
  349. uint32_t dataMode = 0;
  350. /* Check if the device is busy. */
  351. if ((handle->txInProgress) || (handle->rxInProgress))
  352. {
  353. return kStatus_FLEXIO_SPI_Busy;
  354. }
  355. /* Check if input parameter invalid. */
  356. if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
  357. {
  358. return kStatus_InvalidArgument;
  359. }
  360. /* configure data mode. */
  361. if ((xfer->flags == kFLEXIO_SPI_8bitMsb) || (xfer->flags == kFLEXIO_SPI_8bitLsb))
  362. {
  363. dataMode = 8 * 2 - 1U;
  364. }
  365. else if ((xfer->flags == kFLEXIO_SPI_16bitMsb) || (xfer->flags == kFLEXIO_SPI_16bitLsb))
  366. {
  367. dataMode = 16 * 2 - 1U;
  368. }
  369. else
  370. {
  371. dataMode = 8 * 2 - 1U;
  372. }
  373. base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
  374. FLEXIO_SPI_EDMAConfig(base, handle, xfer);
  375. return kStatus_Success;
  376. }