drv_uspi.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2020-7-15 YHkuo First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_USPI)
  14. #define LOG_TAG "drv.uspi"
  15. #define DBG_ENABLE
  16. #define DBG_SECTION_NAME LOG_TAG
  17. #define DBG_LEVEL DBG_INFO
  18. #define DBG_COLOR
  19. #include <rtdbg.h>
  20. #include <rthw.h>
  21. #include <rtdevice.h>
  22. #include <rtdef.h>
  23. #include "NuMicro.h"
  24. #include <nu_bitutil.h>
  25. #if defined(BSP_USING_USPI_PDMA)
  26. #include <drv_pdma.h>
  27. #endif
  28. /* Private define ---------------------------------------------------------------*/
  29. #ifndef NU_SPI_USE_PDMA_MIN_THRESHOLD
  30. #define NU_SPI_USE_PDMA_MIN_THRESHOLD (128)
  31. #endif
  32. enum
  33. {
  34. USPI_START = -1,
  35. #if defined(BSP_USING_USPI0)
  36. USPI0_IDX,
  37. #endif
  38. USPI_CNT
  39. };
  40. /* Private typedef --------------------------------------------------------------*/
  41. struct nu_uspi
  42. {
  43. struct rt_spi_bus dev;
  44. char *name;
  45. USPI_T *uspi_base;
  46. struct rt_spi_configuration configuration;
  47. uint32_t dummy;
  48. #if defined(BSP_USING_USPI_PDMA)
  49. int16_t pdma_perp_tx;
  50. int8_t pdma_chanid_tx;
  51. int16_t pdma_perp_rx;
  52. int8_t pdma_chanid_rx;
  53. rt_sem_t m_psSemBus;
  54. #endif
  55. };
  56. typedef struct nu_uspi *uspi_t;
  57. /* Private functions ------------------------------------------------------------*/
  58. static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
  59. static rt_uint32_t nu_uspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
  60. static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
  61. uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
  62. static int nu_uspi_register_bus(struct nu_uspi *uspi_bus, const char *name);
  63. static void nu_uspi_drain_rxfifo(USPI_T *uspi_base);
  64. #if defined(BSP_USING_USPI_PDMA)
  65. static void nu_pdma_uspi_rx_cb_event(void *pvUserData, uint32_t u32EventFilter);
  66. static rt_err_t nu_pdma_uspi_rx_config(struct nu_uspi *uspi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word);
  67. static rt_err_t nu_pdma_uspi_tx_config(struct nu_uspi *uspi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word);
  68. static rt_ssize_t nu_uspi_pdma_transmit(struct nu_uspi *uspi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
  69. static rt_err_t nu_hw_uspi_pdma_allocate(struct nu_uspi *uspi_bus);
  70. #endif
  71. /* Public functions -------------------------------------------------------------*/
  72. /* Private variables ------------------------------------------------------------*/
  73. static struct rt_spi_ops nu_uspi_poll_ops =
  74. {
  75. .configure = nu_uspi_bus_configure,
  76. .xfer = nu_uspi_bus_xfer,
  77. };
  78. static struct nu_uspi nu_uspi_arr [] =
  79. {
  80. #if defined(BSP_USING_USPI0)
  81. {
  82. .name = "uspi0",
  83. .uspi_base = USPI0,
  84. #if defined(BSP_USING_USPI_PDMA)
  85. #if defined(BSP_USING_USPI0_PDMA)
  86. .pdma_perp_tx = PDMA_USCI0_TX,
  87. .pdma_perp_rx = PDMA_USCI0_RX,
  88. #else
  89. .pdma_perp_tx = NU_PDMA_UNUSED,
  90. .pdma_perp_rx = NU_PDMA_UNUSED,
  91. #endif //BSP_USING_USPI0_PDMA
  92. #endif //BSP_USING_USPI_PDMA
  93. },
  94. #endif
  95. }; /* uspi nu_uspi */
  96. static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device,
  97. struct rt_spi_configuration *configuration)
  98. {
  99. struct nu_uspi *uspi_bus;
  100. uint32_t u32SPIMode;
  101. uint32_t u32BusClock;
  102. rt_err_t ret = RT_EOK;
  103. void *pvUserData;
  104. RT_ASSERT(device);
  105. RT_ASSERT(configuration);
  106. uspi_bus = (struct nu_uspi *) device->bus;
  107. pvUserData = device->parent.user_data;
  108. /* Check mode */
  109. switch (configuration->mode & RT_SPI_MODE_3)
  110. {
  111. case RT_SPI_MODE_0:
  112. u32SPIMode = USPI_MODE_0;
  113. break;
  114. case RT_SPI_MODE_1:
  115. u32SPIMode = USPI_MODE_1;
  116. break;
  117. case RT_SPI_MODE_2:
  118. u32SPIMode = USPI_MODE_2;
  119. break;
  120. case RT_SPI_MODE_3:
  121. u32SPIMode = USPI_MODE_3;
  122. break;
  123. default:
  124. ret = -RT_EIO;
  125. goto exit_nu_uspi_bus_configure;
  126. }
  127. /* Check data width */
  128. if (!(configuration->data_width == 8 ||
  129. configuration->data_width == 16))
  130. {
  131. ret = -RT_EINVAL;
  132. goto exit_nu_uspi_bus_configure;
  133. }
  134. /* Try to set clock and get actual uspi bus clock */
  135. u32BusClock = USPI_SetBusClock(uspi_bus->uspi_base, configuration->max_hz);
  136. if (configuration->max_hz > u32BusClock)
  137. {
  138. LOG_W("%s clock max frequency is %dHz (!= %dHz)\n", uspi_bus->name, u32BusClock, configuration->max_hz);
  139. configuration->max_hz = u32BusClock;
  140. }
  141. /* Need to initialize new configuration? */
  142. if (rt_memcmp(configuration, &uspi_bus->configuration, sizeof(*configuration)) != 0)
  143. {
  144. rt_memcpy(&uspi_bus->configuration, configuration, sizeof(*configuration));
  145. USPI_Open(uspi_bus->uspi_base, USPI_MASTER, u32SPIMode, configuration->data_width, u32BusClock);
  146. if (configuration->mode & RT_SPI_CS_HIGH)
  147. {
  148. /* Set CS pin to LOW */
  149. if (pvUserData != RT_NULL)
  150. {
  151. // set to LOW */
  152. rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
  153. }
  154. else
  155. {
  156. USPI_SET_SS_LOW(uspi_bus->uspi_base);
  157. }
  158. }
  159. else
  160. {
  161. /* Set CS pin to HIGH */
  162. if (pvUserData != RT_NULL)
  163. {
  164. // set to HIGH */
  165. rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
  166. }
  167. else
  168. {
  169. /* Set CS pin to HIGH */
  170. USPI_SET_SS_HIGH(uspi_bus->uspi_base);
  171. }
  172. }
  173. if (configuration->mode & RT_SPI_MSB)
  174. {
  175. /* Set sequence to MSB first */
  176. USPI_SET_MSB_FIRST(uspi_bus->uspi_base);
  177. }
  178. else
  179. {
  180. /* Set sequence to LSB first */
  181. USPI_SET_LSB_FIRST(uspi_bus->uspi_base);
  182. }
  183. }
  184. /* Clear USPI RX FIFO */
  185. nu_uspi_drain_rxfifo(uspi_bus->uspi_base);
  186. exit_nu_uspi_bus_configure:
  187. return -(ret);
  188. }
  189. #if defined(BSP_USING_USPI_PDMA)
  190. static void nu_pdma_uspi_rx_cb_event(void *pvUserData, uint32_t u32EventFilter)
  191. {
  192. rt_err_t result;
  193. struct nu_uspi *uspi_bus = (struct nu_uspi *)pvUserData;
  194. RT_ASSERT(uspi_bus);
  195. result = rt_sem_release(uspi_bus->m_psSemBus);
  196. RT_ASSERT(result == RT_EOK);
  197. }
  198. static void nu_pdma_uspi_tx_cb_trigger(void *pvUserData, uint32_t u32UserData)
  199. {
  200. /* Get base address of spi register */
  201. USPI_T *uspi_base = (USPI_T *)pvUserData;
  202. /* Trigger TX/RX PDMA transfer. */
  203. USPI_TRIGGER_TX_RX_PDMA(uspi_base);
  204. }
  205. static void nu_pdma_uspi_rx_cb_disable(void *pvUserData, uint32_t u32UserData)
  206. {
  207. /* Get base address of spi register */
  208. USPI_T *uspi_base = (USPI_T *)pvUserData;
  209. /* Stop TX/RX DMA transfer. */
  210. USPI_DISABLE_TX_RX_PDMA(uspi_base);
  211. }
  212. static rt_err_t nu_pdma_uspi_rx_config(struct nu_uspi *uspi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word)
  213. {
  214. struct nu_pdma_chn_cb sChnCB;
  215. rt_err_t result;
  216. rt_uint8_t *dst_addr = NULL;
  217. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  218. /* Get base address of uspi register */
  219. USPI_T *uspi_base = uspi_bus->uspi_base;
  220. rt_uint8_t uspi_pdma_rx_chid = uspi_bus->pdma_chanid_rx;
  221. nu_pdma_filtering_set(uspi_pdma_rx_chid, NU_PDMA_EVENT_TRANSFER_DONE);
  222. /* Register ISR callback function */
  223. sChnCB.m_eCBType = eCBType_Event;
  224. sChnCB.m_pfnCBHandler = nu_pdma_uspi_rx_cb_event;
  225. sChnCB.m_pvUserData = (void *)uspi_bus;
  226. result = nu_pdma_callback_register(uspi_pdma_rx_chid, &sChnCB);
  227. if (result != RT_EOK)
  228. {
  229. goto exit_nu_pdma_uspi_rx_config;
  230. }
  231. /* Register Disable engine dma trigger callback function */
  232. sChnCB.m_eCBType = eCBType_Disable;
  233. sChnCB.m_pfnCBHandler = nu_pdma_uspi_rx_cb_disable;
  234. sChnCB.m_pvUserData = (void *)uspi_base;
  235. result = nu_pdma_callback_register(uspi_pdma_rx_chid, &sChnCB);
  236. if (result != RT_EOK)
  237. {
  238. goto exit_nu_pdma_uspi_rx_config;
  239. }
  240. if (pu8Buf == RT_NULL)
  241. {
  242. memctrl = eMemCtl_SrcFix_DstFix;
  243. dst_addr = (rt_uint8_t *) &uspi_bus->dummy;
  244. }
  245. else
  246. {
  247. memctrl = eMemCtl_SrcFix_DstInc;
  248. dst_addr = pu8Buf;
  249. }
  250. result = nu_pdma_channel_memctrl_set(uspi_pdma_rx_chid, memctrl);
  251. if (result != RT_EOK)
  252. {
  253. goto exit_nu_pdma_uspi_rx_config;
  254. }
  255. result = nu_pdma_transfer(uspi_pdma_rx_chid,
  256. bytes_per_word * 8,
  257. (uint32_t)&uspi_base->RXDAT,
  258. (uint32_t)dst_addr,
  259. i32RcvLen / bytes_per_word,
  260. 0);
  261. exit_nu_pdma_uspi_rx_config:
  262. return result;
  263. }
  264. static rt_err_t nu_pdma_uspi_tx_config(struct nu_uspi *uspi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word)
  265. {
  266. struct nu_pdma_chn_cb sChnCB;
  267. rt_err_t result;
  268. rt_uint8_t *src_addr = NULL;
  269. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  270. /* Get base address of uspi register */
  271. USPI_T *uspi_base = uspi_bus->uspi_base;
  272. rt_uint8_t uspi_pdma_tx_chid = uspi_bus->pdma_chanid_tx;
  273. if (pu8Buf == RT_NULL)
  274. {
  275. uspi_bus->dummy = 0;
  276. memctrl = eMemCtl_SrcFix_DstFix;
  277. src_addr = (rt_uint8_t *)&uspi_bus->dummy;
  278. }
  279. else
  280. {
  281. memctrl = eMemCtl_SrcInc_DstFix;
  282. src_addr = (rt_uint8_t *)pu8Buf;
  283. }
  284. /* Register Disable engine dma trigger callback function */
  285. sChnCB.m_eCBType = eCBType_Trigger;
  286. sChnCB.m_pfnCBHandler = nu_pdma_uspi_tx_cb_trigger;
  287. sChnCB.m_pvUserData = (void *)uspi_base;
  288. result = nu_pdma_callback_register(uspi_pdma_tx_chid, &sChnCB);
  289. if (result != RT_EOK)
  290. {
  291. goto exit_nu_pdma_uspi_tx_config;
  292. }
  293. result = nu_pdma_channel_memctrl_set(uspi_pdma_tx_chid, memctrl);
  294. if (result != RT_EOK)
  295. {
  296. goto exit_nu_pdma_uspi_tx_config;
  297. }
  298. result = nu_pdma_transfer(uspi_pdma_tx_chid,
  299. bytes_per_word * 8,
  300. (uint32_t)src_addr,
  301. (uint32_t)&uspi_base->TXDAT,
  302. i32SndLen / bytes_per_word,
  303. 0);
  304. exit_nu_pdma_uspi_tx_config:
  305. return result;
  306. }
  307. /**
  308. * USPI PDMA transfer
  309. **/
  310. static rt_ssize_t nu_uspi_pdma_transmit(struct nu_uspi *uspi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
  311. {
  312. rt_err_t result = RT_EOK;
  313. result = nu_pdma_uspi_rx_config(uspi_bus, recv_addr, length, bytes_per_word);
  314. RT_ASSERT(result == RT_EOK);
  315. result = nu_pdma_uspi_tx_config(uspi_bus, send_addr, length, bytes_per_word);
  316. RT_ASSERT(result == RT_EOK);
  317. /* Wait RX-PDMA transfer done */
  318. result = rt_sem_take(uspi_bus->m_psSemBus, RT_WAITING_FOREVER);
  319. RT_ASSERT(result == RT_EOK);
  320. return length;
  321. }
  322. static rt_err_t nu_hw_uspi_pdma_allocate(struct nu_uspi *uspi_bus)
  323. {
  324. /* Allocate USPI_TX nu_dma channel */
  325. if ((uspi_bus->pdma_chanid_tx = nu_pdma_channel_allocate(uspi_bus->pdma_perp_tx)) < 0)
  326. {
  327. goto exit_nu_hw_uspi_pdma_allocate;
  328. }
  329. /* Allocate USPI_RX nu_dma channel */
  330. else if ((uspi_bus->pdma_chanid_rx = nu_pdma_channel_allocate(uspi_bus->pdma_perp_rx)) < 0)
  331. {
  332. nu_pdma_channel_free(uspi_bus->pdma_chanid_tx);
  333. goto exit_nu_hw_uspi_pdma_allocate;
  334. }
  335. uspi_bus->m_psSemBus = rt_sem_create("uspibus_sem", 0, RT_IPC_FLAG_FIFO);
  336. RT_ASSERT(uspi_bus->m_psSemBus != RT_NULL);
  337. return RT_EOK;
  338. exit_nu_hw_uspi_pdma_allocate:
  339. return -(RT_ERROR);
  340. }
  341. #endif
  342. static void nu_uspi_drain_rxfifo(USPI_T *uspi_base)
  343. {
  344. while (USPI_IS_BUSY(uspi_base));
  345. // Drain USPI RX FIFO, make sure RX FIFO is empty
  346. while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  347. {
  348. USPI_ClearRxBuf(uspi_base);
  349. }
  350. }
  351. static int nu_uspi_read(USPI_T *uspi_base, uint8_t *recv_addr, uint8_t bytes_per_word)
  352. {
  353. int size = 0;
  354. // Read RX data
  355. if (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  356. {
  357. uint32_t val;
  358. // Read data from USPI RX FIFO
  359. switch (bytes_per_word)
  360. {
  361. case 2:
  362. val = USPI_READ_RX(uspi_base);
  363. nu_set16_le(recv_addr, val);
  364. break;
  365. case 1:
  366. *recv_addr = USPI_READ_RX(uspi_base);
  367. break;
  368. default:
  369. LOG_E("Data length is not supported.\n");
  370. break;
  371. }
  372. size = bytes_per_word;
  373. }
  374. return size;
  375. }
  376. static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t bytes_per_word)
  377. {
  378. // Wait USPI TX send data
  379. while (USPI_GET_TX_FULL_FLAG(uspi_base));
  380. // Input data to USPI TX
  381. switch (bytes_per_word)
  382. {
  383. case 2:
  384. USPI_WRITE_TX(uspi_base, nu_get16_le(send_addr));
  385. break;
  386. case 1:
  387. USPI_WRITE_TX(uspi_base, *((uint8_t *)send_addr));
  388. break;
  389. default:
  390. LOG_E("Data length is not supported.\n");
  391. break;
  392. }
  393. return bytes_per_word;
  394. }
  395. /**
  396. * @brief USPI bus polling
  397. * @param dev : The pointer of the specified USPI module.
  398. * @param send_addr : Source address
  399. * @param recv_addr : Destination address
  400. * @param length : Data length
  401. */
  402. static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
  403. uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
  404. {
  405. USPI_T *uspi_base = uspi_bus->uspi_base;
  406. // Write-only
  407. if ((send_addr != RT_NULL) && (recv_addr == RT_NULL))
  408. {
  409. while (length > 0)
  410. {
  411. send_addr += nu_uspi_write(uspi_base, send_addr, bytes_per_word);
  412. length -= bytes_per_word;
  413. }
  414. } // if (send_addr != RT_NULL && recv_addr == RT_NULL)
  415. // Read-only
  416. else if ((send_addr == RT_NULL) && (recv_addr != RT_NULL))
  417. {
  418. uspi_bus->dummy = 0;
  419. while (length > 0)
  420. {
  421. /* Input data to USPI TX FIFO */
  422. length -= nu_uspi_write(uspi_base, (const uint8_t *)&uspi_bus->dummy, bytes_per_word);
  423. /* Read data from USPI RX FIFO */
  424. while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
  425. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  426. }
  427. } // else if (send_addr == RT_NULL && recv_addr != RT_NULL)
  428. // Read&Write
  429. else
  430. {
  431. while (length > 0)
  432. {
  433. /* Input data to USPI TX FIFO */
  434. send_addr += nu_uspi_write(uspi_base, send_addr, bytes_per_word);
  435. length -= bytes_per_word;
  436. /* Read data from USPI RX FIFO */
  437. while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
  438. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  439. }
  440. } // else
  441. /* Wait USPI RX or drain USPI RX-FIFO */
  442. if (recv_addr)
  443. {
  444. // Wait USPI transmission done
  445. while (USPI_IS_BUSY(uspi_base))
  446. {
  447. while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  448. {
  449. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  450. }
  451. }
  452. while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  453. {
  454. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  455. }
  456. }
  457. else
  458. {
  459. /* Clear USPI RX FIFO */
  460. nu_uspi_drain_rxfifo(uspi_base);
  461. }
  462. }
  463. static void nu_uspi_transfer(struct nu_uspi *uspi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
  464. {
  465. RT_ASSERT(uspi_bus != RT_NULL);
  466. #if defined(BSP_USING_USPI_PDMA)
  467. /* PDMA transfer constrains */
  468. if ((uspi_bus->pdma_chanid_rx >= 0) &&
  469. !((uint32_t)tx % bytes_per_word) &&
  470. !((uint32_t)rx % bytes_per_word) &&
  471. (length >= NU_SPI_USE_PDMA_MIN_THRESHOLD))
  472. nu_uspi_pdma_transmit(uspi_bus, tx, rx, length, bytes_per_word);
  473. else
  474. nu_uspi_transmission_with_poll(uspi_bus, tx, rx, length, bytes_per_word);
  475. #else
  476. nu_uspi_transmission_with_poll(uspi_bus, tx, rx, length, bytes_per_word);
  477. #endif
  478. }
  479. static rt_uint32_t nu_uspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
  480. {
  481. struct nu_uspi *uspi_bus;
  482. struct rt_spi_configuration *configuration;
  483. uint8_t bytes_per_word;
  484. void *pvUserData;
  485. RT_ASSERT(device != RT_NULL);
  486. RT_ASSERT(device->bus != RT_NULL);
  487. RT_ASSERT(message != RT_NULL);
  488. uspi_bus = (struct nu_uspi *) device->bus;
  489. configuration = (struct rt_spi_configuration *)&uspi_bus->configuration;
  490. bytes_per_word = configuration->data_width / 8;
  491. pvUserData = device->parent.user_data;
  492. if ((message->length % bytes_per_word) != 0)
  493. {
  494. /* Say bye. */
  495. LOG_E("%s: error payload length(%d%%%d != 0).\n", uspi_bus->name, message->length, bytes_per_word);
  496. return 0;
  497. }
  498. if (message->length > 0)
  499. {
  500. if (message->cs_take && !(configuration->mode & RT_SPI_NO_CS))
  501. {
  502. if (pvUserData != RT_NULL)
  503. {
  504. if (configuration->mode & RT_SPI_CS_HIGH)
  505. {
  506. // set to HIGH */
  507. rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
  508. }
  509. else
  510. {
  511. // set to LOW */
  512. rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
  513. }
  514. }
  515. else
  516. {
  517. if (configuration->mode & RT_SPI_CS_HIGH)
  518. {
  519. USPI_SET_SS_HIGH(uspi_bus->uspi_base);
  520. }
  521. else
  522. {
  523. USPI_SET_SS_LOW(uspi_bus->uspi_base);
  524. }
  525. }
  526. }
  527. nu_uspi_transfer(uspi_bus, (uint8_t *)message->send_buf, (uint8_t *)message->recv_buf, message->length, bytes_per_word);
  528. if (message->cs_release && !(configuration->mode & RT_SPI_NO_CS))
  529. {
  530. if (pvUserData != RT_NULL)
  531. {
  532. if (configuration->mode & RT_SPI_CS_HIGH)
  533. {
  534. // set to LOW */
  535. rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
  536. }
  537. else
  538. {
  539. // set to HIGH */
  540. rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
  541. }
  542. }
  543. else
  544. {
  545. if (configuration->mode & RT_SPI_CS_HIGH)
  546. {
  547. USPI_SET_SS_LOW(uspi_bus->uspi_base);
  548. }
  549. else
  550. {
  551. USPI_SET_SS_HIGH(uspi_bus->uspi_base);
  552. }
  553. }
  554. }
  555. }
  556. return message->length;
  557. }
  558. static int nu_uspi_register_bus(struct nu_uspi *uspi_bus, const char *name)
  559. {
  560. return rt_spi_bus_register(&uspi_bus->dev, name, &nu_uspi_poll_ops);
  561. }
  562. /**
  563. * Hardware USPI Initial
  564. */
  565. static int rt_hw_uspi_init(void)
  566. {
  567. int i;
  568. for (i = (USPI_START + 1); i < USPI_CNT; i++)
  569. {
  570. nu_uspi_register_bus(&nu_uspi_arr[i], nu_uspi_arr[i].name);
  571. #if defined(BSP_USING_USPI_PDMA)
  572. nu_uspi_arr[i].pdma_chanid_tx = -1;
  573. nu_uspi_arr[i].pdma_chanid_rx = -1;
  574. if ((nu_uspi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_uspi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
  575. {
  576. if (nu_hw_uspi_pdma_allocate(&nu_uspi_arr[i]) != RT_EOK)
  577. {
  578. LOG_E("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_uspi_arr[i].name);
  579. }
  580. }
  581. #endif
  582. }
  583. return 0;
  584. }
  585. INIT_DEVICE_EXPORT(rt_hw_uspi_init);
  586. #endif //#if defined(BSP_USING_USPI)