drv_uspi.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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-3-31 Philo 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. enum
  30. {
  31. USPI_START = -1,
  32. #if defined(BSP_USING_USPI0)
  33. USPI0_IDX,
  34. #endif
  35. #if defined(BSP_USING_USPI1)
  36. USPI1_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(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_size_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. #if defined(BSP_USING_USPI1)
  96. {
  97. .name = "uspi1",
  98. .uspi_base = USPI1,
  99. #if defined(BSP_USING_USPI_PDMA)
  100. #if defined(BSP_USING_USPI1_PDMA)
  101. .pdma_perp_tx = PDMA_USCI1_TX,
  102. .pdma_perp_rx = PDMA_USCI1_RX,
  103. #else
  104. .pdma_perp_tx = NU_PDMA_UNUSED,
  105. .pdma_perp_rx = NU_PDMA_UNUSED,
  106. #endif //BSP_USING_USPI1_PDMA
  107. #endif //BSP_USING_USPI_PDMA
  108. },
  109. #endif
  110. {0}
  111. }; /* uspi nu_uspi */
  112. static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device,
  113. struct rt_spi_configuration *configuration)
  114. {
  115. struct nu_uspi *uspi_bus;
  116. uint32_t u32SPIMode;
  117. uint32_t u32BusClock;
  118. rt_err_t ret = RT_EOK;
  119. RT_ASSERT(device != RT_NULL);
  120. RT_ASSERT(configuration != RT_NULL);
  121. uspi_bus = (struct nu_uspi *) device->bus;
  122. /* Check mode */
  123. switch (configuration->mode & RT_SPI_MODE_3)
  124. {
  125. case RT_SPI_MODE_0:
  126. u32SPIMode = USPI_MODE_0;
  127. break;
  128. case RT_SPI_MODE_1:
  129. u32SPIMode = USPI_MODE_1;
  130. break;
  131. case RT_SPI_MODE_2:
  132. u32SPIMode = USPI_MODE_2;
  133. break;
  134. case RT_SPI_MODE_3:
  135. u32SPIMode = USPI_MODE_3;
  136. break;
  137. default:
  138. ret = RT_EIO;
  139. goto exit_nu_uspi_bus_configure;
  140. }
  141. /* Check data width */
  142. if (!(configuration->data_width == 8 ||
  143. configuration->data_width == 16))
  144. {
  145. ret = RT_EINVAL;
  146. goto exit_nu_uspi_bus_configure;
  147. }
  148. /* Try to set clock and get actual uspi bus clock */
  149. u32BusClock = USPI_SetBusClock(uspi_bus->uspi_base, configuration->max_hz);
  150. if (configuration->max_hz > u32BusClock)
  151. {
  152. LOG_W("%s clock max frequency is %dHz (!= %dHz)\n", uspi_bus->name, u32BusClock, configuration->max_hz);
  153. configuration->max_hz = u32BusClock;
  154. }
  155. /* Need to initialize new configuration? */
  156. if (rt_memcmp(configuration, &uspi_bus->configuration, sizeof(*configuration)) != 0)
  157. {
  158. rt_memcpy(&uspi_bus->configuration, configuration, sizeof(*configuration));
  159. USPI_Open(uspi_bus->uspi_base, USPI_MASTER, u32SPIMode, configuration->data_width, u32BusClock);
  160. if (configuration->mode & RT_SPI_CS_HIGH)
  161. {
  162. /* Set CS pin to LOW */
  163. USPI_SET_SS_LOW(uspi_bus->uspi_base);
  164. }
  165. else
  166. {
  167. /* Set CS pin to HIGH */
  168. USPI_SET_SS_HIGH(uspi_bus->uspi_base);
  169. }
  170. if (configuration->mode & RT_SPI_MSB)
  171. {
  172. /* Set sequence to MSB first */
  173. USPI_SET_MSB_FIRST(uspi_bus->uspi_base);
  174. }
  175. else
  176. {
  177. /* Set sequence to LSB first */
  178. USPI_SET_LSB_FIRST(uspi_bus->uspi_base);
  179. }
  180. }
  181. /* Clear USPI RX FIFO */
  182. nu_uspi_drain_rxfifo(uspi_bus->uspi_base);
  183. exit_nu_uspi_bus_configure:
  184. return -(ret);
  185. }
  186. #if defined(BSP_USING_USPI_PDMA)
  187. static void nu_pdma_uspi_rx_cb(void *pvUserData, uint32_t u32EventFilter)
  188. {
  189. rt_err_t result;
  190. struct nu_uspi *uspi_bus = (struct nu_uspi *)pvUserData;
  191. RT_ASSERT(uspi_bus != RT_NULL);
  192. result = rt_sem_release(uspi_bus->m_psSemBus);
  193. RT_ASSERT(result == RT_EOK);
  194. }
  195. 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)
  196. {
  197. rt_err_t result;
  198. rt_uint8_t *dst_addr = NULL;
  199. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  200. /* Get base address of uspi register */
  201. USPI_T *uspi_base = uspi_bus->uspi_base;
  202. rt_uint8_t uspi_pdma_rx_chid = uspi_bus->pdma_chanid_rx;
  203. result = nu_pdma_callback_register(uspi_pdma_rx_chid,
  204. nu_pdma_uspi_rx_cb,
  205. (void *)uspi_bus,
  206. NU_PDMA_EVENT_TRANSFER_DONE);
  207. if (result != RT_EOK)
  208. {
  209. goto exit_nu_pdma_uspi_rx_config;
  210. }
  211. if (pu8Buf == RT_NULL)
  212. {
  213. memctrl = eMemCtl_SrcFix_DstFix;
  214. dst_addr = (rt_uint8_t *) &uspi_bus->dummy;
  215. }
  216. else
  217. {
  218. memctrl = eMemCtl_SrcFix_DstInc;
  219. dst_addr = pu8Buf;
  220. }
  221. result = nu_pdma_channel_memctrl_set(uspi_pdma_rx_chid, memctrl);
  222. if (result != RT_EOK)
  223. {
  224. goto exit_nu_pdma_uspi_rx_config;
  225. }
  226. result = nu_pdma_transfer(uspi_pdma_rx_chid,
  227. bytes_per_word * 8,
  228. (uint32_t)&uspi_base->RXDAT,
  229. (uint32_t)dst_addr,
  230. i32RcvLen / bytes_per_word,
  231. 0);
  232. exit_nu_pdma_uspi_rx_config:
  233. return result;
  234. }
  235. 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)
  236. {
  237. rt_err_t result;
  238. rt_uint8_t *src_addr = NULL;
  239. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  240. /* Get base address of uspi register */
  241. USPI_T *uspi_base = uspi_bus->uspi_base;
  242. rt_uint8_t uspi_pdma_tx_chid = uspi_bus->pdma_chanid_tx;
  243. if (pu8Buf == RT_NULL)
  244. {
  245. uspi_bus->dummy = 0;
  246. memctrl = eMemCtl_SrcFix_DstFix;
  247. src_addr = (rt_uint8_t *)&uspi_bus->dummy;
  248. }
  249. else
  250. {
  251. memctrl = eMemCtl_SrcInc_DstFix;
  252. src_addr = (rt_uint8_t *)pu8Buf;
  253. }
  254. result = nu_pdma_channel_memctrl_set(uspi_pdma_tx_chid, memctrl);
  255. if (result != RT_EOK)
  256. {
  257. goto exit_nu_pdma_uspi_tx_config;
  258. }
  259. result = nu_pdma_transfer(uspi_pdma_tx_chid,
  260. bytes_per_word * 8,
  261. (uint32_t)src_addr,
  262. (uint32_t)&uspi_base->TXDAT,
  263. i32SndLen / bytes_per_word,
  264. 0);
  265. exit_nu_pdma_uspi_tx_config:
  266. return result;
  267. }
  268. /**
  269. * USPI PDMA transfer
  270. **/
  271. static rt_size_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)
  272. {
  273. rt_err_t result;
  274. /* Get base address of uspi register */
  275. USPI_T *uspi_base = uspi_bus->uspi_base;
  276. result = nu_pdma_uspi_rx_config(uspi_bus, recv_addr, length, bytes_per_word);
  277. RT_ASSERT(result == RT_EOK);
  278. result = nu_pdma_uspi_tx_config(uspi_bus, send_addr, length, bytes_per_word);
  279. RT_ASSERT(result == RT_EOK);
  280. /* Trigger TX/RX at the same time. */
  281. USPI_TRIGGER_TX_RX_PDMA(uspi_base);
  282. /* Wait PDMA transfer done */
  283. result = rt_sem_take(uspi_bus->m_psSemBus, RT_WAITING_FOREVER);
  284. RT_ASSERT(result == RT_EOK);
  285. /* Stop DMA TX/RX transfer */
  286. USPI_DISABLE_TX_RX_PDMA(uspi_base);
  287. return result;
  288. }
  289. static rt_err_t nu_hw_uspi_pdma_allocate(struct nu_uspi *uspi_bus)
  290. {
  291. /* Allocate USPI_TX nu_dma channel */
  292. if ((uspi_bus->pdma_chanid_tx = nu_pdma_channel_allocate(uspi_bus->pdma_perp_tx)) < 0)
  293. {
  294. goto exit_nu_hw_uspi_pdma_allocate;
  295. }
  296. /* Allocate USPI_RX nu_dma channel */
  297. else if ((uspi_bus->pdma_chanid_rx = nu_pdma_channel_allocate(uspi_bus->pdma_perp_rx)) < 0)
  298. {
  299. nu_pdma_channel_free(uspi_bus->pdma_chanid_tx);
  300. goto exit_nu_hw_uspi_pdma_allocate;
  301. }
  302. uspi_bus->m_psSemBus = rt_sem_create("uspibus_sem", 0, RT_IPC_FLAG_FIFO);
  303. RT_ASSERT(uspi_bus->m_psSemBus != RT_NULL);
  304. return RT_EOK;
  305. exit_nu_hw_uspi_pdma_allocate:
  306. return -(RT_ERROR);
  307. }
  308. #endif
  309. static void nu_uspi_drain_rxfifo(USPI_T *uspi_base)
  310. {
  311. while (USPI_IS_BUSY(uspi_base));
  312. // Drain USPI RX FIFO, make sure RX FIFO is empty
  313. while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  314. {
  315. USPI_ClearRxBuf(uspi_base);
  316. }
  317. }
  318. static int nu_uspi_read(USPI_T *uspi_base, uint8_t *recv_addr, uint8_t bytes_per_word)
  319. {
  320. int size = 0;
  321. // Read RX data
  322. if (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  323. {
  324. uint32_t val;
  325. // Read data from USPI RX FIFO
  326. switch (bytes_per_word)
  327. {
  328. case 2:
  329. val = USPI_READ_RX(uspi_base);
  330. nu_set16_le(recv_addr, val);
  331. break;
  332. case 1:
  333. *recv_addr = USPI_READ_RX(uspi_base);
  334. break;
  335. default:
  336. LOG_E("Data length is not supported.\n");
  337. break;
  338. }
  339. size = bytes_per_word;
  340. }
  341. return size;
  342. }
  343. static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t bytes_per_word)
  344. {
  345. // Wait USPI TX send data
  346. while (USPI_GET_TX_FULL_FLAG(uspi_base));
  347. // Input data to USPI TX
  348. switch (bytes_per_word)
  349. {
  350. case 2:
  351. USPI_WRITE_TX(uspi_base, nu_get16_le(send_addr));
  352. break;
  353. case 1:
  354. USPI_WRITE_TX(uspi_base, *((uint8_t *)send_addr));
  355. break;
  356. default:
  357. LOG_E("Data length is not supported.\n");
  358. break;
  359. }
  360. return bytes_per_word;
  361. }
  362. /**
  363. * @brief USPI bus polling
  364. * @param dev : The pointer of the specified USPI module.
  365. * @param send_addr : Source address
  366. * @param recv_addr : Destination address
  367. * @param length : Data length
  368. */
  369. static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
  370. uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
  371. {
  372. USPI_T *uspi_base = uspi_bus->uspi_base;
  373. // Write-only
  374. if ((send_addr != RT_NULL) && (recv_addr == RT_NULL))
  375. {
  376. while (length > 0)
  377. {
  378. send_addr += nu_uspi_write(uspi_base, send_addr, bytes_per_word);
  379. length -= bytes_per_word;
  380. }
  381. } // if (send_addr != RT_NULL && recv_addr == RT_NULL)
  382. // Read-only
  383. else if ((send_addr == RT_NULL) && (recv_addr != RT_NULL))
  384. {
  385. uspi_bus->dummy = 0;
  386. while (length > 0)
  387. {
  388. /* Input data to USPI TX FIFO */
  389. length -= nu_uspi_write(uspi_base, (const uint8_t *)&uspi_bus->dummy, bytes_per_word);
  390. /* Read data from USPI RX FIFO */
  391. while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
  392. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  393. }
  394. } // else if (send_addr == RT_NULL && recv_addr != RT_NULL)
  395. // Read&Write
  396. else
  397. {
  398. while (length > 0)
  399. {
  400. /* Input data to USPI TX FIFO */
  401. send_addr += nu_uspi_write(uspi_base, send_addr, bytes_per_word);
  402. length -= bytes_per_word;
  403. /* Read data from USPI RX FIFO */
  404. while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
  405. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  406. }
  407. } // else
  408. /* Wait USPI RX or drain USPI RX-FIFO */
  409. if (recv_addr)
  410. {
  411. // Wait USPI transmission done
  412. while (USPI_IS_BUSY(uspi_base))
  413. {
  414. while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  415. {
  416. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  417. }
  418. }
  419. while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
  420. {
  421. recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
  422. }
  423. }
  424. else
  425. {
  426. /* Clear USPI RX FIFO */
  427. nu_uspi_drain_rxfifo(uspi_base);
  428. }
  429. }
  430. static void nu_uspi_transfer(struct nu_uspi *uspi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
  431. {
  432. #if defined(BSP_USING_USPI_PDMA)
  433. /* PDMA transfer constrains */
  434. if ((uspi_bus->pdma_chanid_rx >= 0) &&
  435. (!((uint32_t)tx % bytes_per_word)) &&
  436. (!((uint32_t)rx % bytes_per_word)))
  437. nu_uspi_pdma_transmit(uspi_bus, tx, rx, length, bytes_per_word);
  438. else
  439. nu_uspi_transmission_with_poll(uspi_bus, tx, rx, length, bytes_per_word);
  440. #else
  441. nu_uspi_transmission_with_poll(uspi_bus, tx, rx, length, bytes_per_word);
  442. #endif
  443. }
  444. static rt_uint32_t nu_uspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
  445. {
  446. struct nu_uspi *uspi_bus;
  447. struct rt_spi_configuration *configuration;
  448. uint8_t bytes_per_word;
  449. RT_ASSERT(device != RT_NULL);
  450. RT_ASSERT(device->bus != RT_NULL);
  451. RT_ASSERT(message != RT_NULL);
  452. uspi_bus = (struct nu_uspi *) device->bus;
  453. configuration = &uspi_bus->configuration;
  454. bytes_per_word = configuration->data_width / 8;
  455. if ((message->length % bytes_per_word) != 0)
  456. {
  457. /* Say bye. */
  458. LOG_E("%s: error payload length(%d%%%d != 0).\n", uspi_bus->name, message->length, bytes_per_word);
  459. return 0;
  460. }
  461. if (message->length > 0)
  462. {
  463. if (message->cs_take && !(configuration->mode & RT_SPI_NO_CS))
  464. {
  465. if (configuration->mode & RT_SPI_CS_HIGH)
  466. {
  467. USPI_SET_SS_HIGH(uspi_bus->uspi_base);
  468. }
  469. else
  470. {
  471. USPI_SET_SS_LOW(uspi_bus->uspi_base);
  472. }
  473. }
  474. nu_uspi_transfer(uspi_bus, (uint8_t *)message->send_buf, (uint8_t *)message->recv_buf, message->length, bytes_per_word);
  475. if (message->cs_release && !(configuration->mode & RT_SPI_NO_CS))
  476. {
  477. if (configuration->mode & RT_SPI_CS_HIGH)
  478. {
  479. USPI_SET_SS_LOW(uspi_bus->uspi_base);
  480. }
  481. else
  482. {
  483. USPI_SET_SS_HIGH(uspi_bus->uspi_base);
  484. }
  485. }
  486. }
  487. return message->length;
  488. }
  489. static int nu_uspi_register_bus(struct nu_uspi *uspi_bus, const char *name)
  490. {
  491. return rt_spi_bus_register(&uspi_bus->dev, name, &nu_uspi_poll_ops);
  492. }
  493. /**
  494. * Hardware USPI Initial
  495. */
  496. static int rt_hw_uspi_init(void)
  497. {
  498. int i;
  499. for (i = (USPI_START + 1); i < USPI_CNT; i++)
  500. {
  501. nu_uspi_register_bus(&nu_uspi_arr[i], nu_uspi_arr[i].name);
  502. #if defined(BSP_USING_USPI_PDMA)
  503. nu_uspi_arr[i].pdma_chanid_tx = -1;
  504. nu_uspi_arr[i].pdma_chanid_rx = -1;
  505. if ((nu_uspi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_uspi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
  506. {
  507. if (nu_hw_uspi_pdma_allocate(&nu_uspi_arr[i]) != RT_EOK)
  508. {
  509. LOG_E("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_uspi_arr[i].name);
  510. }
  511. }
  512. #endif
  513. }
  514. return 0;
  515. }
  516. INIT_DEVICE_EXPORT(rt_hw_uspi_init);
  517. #endif //#if defined(BSP_USING_USPI)