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-11-11      Wayne            First version
10 *
11 ******************************************************************************/
12 #include <rtconfig.h>
13 
14 #if defined(BSP_USING_SPI)
15 
16 #define LOG_TAG                 "drv.spi"
17 #define DBG_ENABLE
18 #define DBG_SECTION_NAME        LOG_TAG
19 #define DBG_LEVEL               DBG_INFO
20 #define DBG_COLOR
21 #include <rtdbg.h>
22 
23 #include <rthw.h>
24 #include <rtdevice.h>
25 #include <rtdef.h>
26 
27 #include <drv_spi.h>
28 
29 
30 /* Private define ---------------------------------------------------------------*/
31 
32 #ifndef NU_SPI_USE_PDMA_MIN_THRESHOLD
33     #define NU_SPI_USE_PDMA_MIN_THRESHOLD (128)
34 #endif
35 
36 enum
37 {
38     SPI_START = -1,
39 #if defined(BSP_USING_SPI0)
40     SPI0_IDX,
41 #endif
42 #if defined(BSP_USING_SPI1)
43     SPI1_IDX,
44 #endif
45 #if defined(BSP_USING_SPI2)
46     SPI2_IDX,
47 #endif
48 #if defined(BSP_USING_SPI3)
49     SPI3_IDX,
50 #endif
51     SPI_CNT
52 };
53 
54 /* Private typedef --------------------------------------------------------------*/
55 
56 /* Private functions ------------------------------------------------------------*/
57 static void nu_spi_transmission_with_poll(struct nu_spi *spi_bus,
58         uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
59 static int nu_spi_register_bus(struct nu_spi *spi_bus, const char *name);
60 static rt_ssize_t nu_spi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
61 static rt_err_t nu_spi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
62 
63 #if defined(BSP_USING_SPI_PDMA)
64     static void nu_pdma_spi_rx_cb_event(void *pvUserData, uint32_t u32EventFilter);
65     static rt_err_t nu_pdma_spi_rx_config(struct nu_spi *spi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word);
66     static rt_err_t nu_pdma_spi_tx_config(struct nu_spi *spi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word);
67     static rt_ssize_t nu_spi_pdma_transmit(struct nu_spi *spi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
68 #endif
69 /* Public functions -------------------------------------------------------------*/
70 void nu_spi_transfer(struct nu_spi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word);
71 void nu_spi_drain_rxfifo(SPI_T *spi_base);
72 
73 /* Private variables ------------------------------------------------------------*/
74 static struct rt_spi_ops nu_spi_poll_ops =
75 {
76     .configure = nu_spi_bus_configure,
77     .xfer      = nu_spi_bus_xfer,
78 };
79 
80 static struct nu_spi nu_spi_arr [] =
81 {
82 #if defined(BSP_USING_SPI0)
83     {
84         .name = "spi0",
85         .spi_base = SPI0,
86         .rstidx = SPI0_RST,
87 #if defined(BSP_USING_SPI_PDMA)
88 #if defined(BSP_USING_SPI0_PDMA)
89         .pdma_perp_tx = PDMA_SPI0_TX,
90         .pdma_perp_rx = PDMA_SPI0_RX,
91 #else
92         .pdma_perp_tx = NU_PDMA_UNUSED,
93         .pdma_perp_rx = NU_PDMA_UNUSED,
94 #endif
95 #endif
96     },
97 #endif
98 #if defined(BSP_USING_SPI1)
99     {
100         .name = "spi1",
101         .spi_base = SPI1,
102         .rstidx = SPI1_RST,
103 #if defined(BSP_USING_SPI_PDMA)
104 #if defined(BSP_USING_SPI1_PDMA)
105         .pdma_perp_tx = PDMA_SPI1_TX,
106         .pdma_perp_rx = PDMA_SPI1_RX,
107 #else
108         .pdma_perp_tx = NU_PDMA_UNUSED,
109         .pdma_perp_rx = NU_PDMA_UNUSED,
110 #endif
111 #endif
112     },
113 #endif
114 #if defined(BSP_USING_SPI2)
115     {
116         .name = "spi2",
117         .spi_base = SPI2,
118         .rstidx = SPI2_RST,
119 #if defined(BSP_USING_SPI_PDMA)
120 #if defined(BSP_USING_SPI2_PDMA)
121         .pdma_perp_tx = PDMA_SPI2_TX,
122         .pdma_perp_rx = PDMA_SPI2_RX,
123 #else
124         .pdma_perp_tx = NU_PDMA_UNUSED,
125         .pdma_perp_rx = NU_PDMA_UNUSED,
126 #endif
127 #endif
128     },
129 #endif
130 #if defined(BSP_USING_SPI3)
131     {
132         .name = "spi3",
133         .spi_base = SPI3,
134         .rstidx = SPI3_RST,
135 #if defined(BSP_USING_SPI_PDMA)
136 #if defined(BSP_USING_SPI3_PDMA)
137         .pdma_perp_tx = PDMA_SPI3_TX,
138         .pdma_perp_rx = PDMA_SPI3_RX,
139 #else
140         .pdma_perp_tx = NU_PDMA_UNUSED,
141         .pdma_perp_rx = NU_PDMA_UNUSED,
142 #endif
143 #endif
144     },
145 #endif
146 }; /* spi nu_spi */
147 
nu_spi_bus_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)148 static rt_err_t nu_spi_bus_configure(struct rt_spi_device *device,
149                                      struct rt_spi_configuration *configuration)
150 {
151     struct nu_spi *spi_bus;
152     uint32_t u32SPIMode;
153     rt_err_t ret = RT_EOK;
154     void *pvUserData;
155 
156     RT_ASSERT(device);
157     RT_ASSERT(configuration);
158 
159     spi_bus = (struct nu_spi *) device->bus;
160     pvUserData = device->parent.user_data;
161 
162     /* Check mode */
163     switch (configuration->mode & RT_SPI_MODE_3)
164     {
165     case RT_SPI_MODE_0:
166         u32SPIMode = SPI_MODE_0;
167         break;
168     case RT_SPI_MODE_1:
169         u32SPIMode = SPI_MODE_1;
170         break;
171     case RT_SPI_MODE_2:
172         u32SPIMode = SPI_MODE_2;
173         break;
174     case RT_SPI_MODE_3:
175         u32SPIMode = SPI_MODE_3;
176         break;
177     default:
178         ret = -RT_EIO;
179         goto exit_nu_spi_bus_configure;
180     }
181 
182     /* Check data width */
183     if (!(configuration->data_width == 8  ||
184             configuration->data_width == 16 ||
185             configuration->data_width == 24 ||
186             configuration->data_width == 32))
187     {
188         ret = -RT_EINVAL;
189         goto exit_nu_spi_bus_configure;
190     }
191 
192     /* Need to initialize new configuration? */
193     if (rt_memcmp(configuration, &spi_bus->configuration, sizeof(*configuration)) != 0)
194     {
195         rt_memcpy(&spi_bus->configuration, configuration, sizeof(*configuration));
196 
197         SPI_Open(spi_bus->spi_base, SPI_MASTER, u32SPIMode, configuration->data_width, configuration->max_hz);
198 
199         if (configuration->mode & RT_SPI_CS_HIGH)
200         {
201             /* Set CS pin to LOW */
202             if (pvUserData != RT_NULL)
203             {
204                 // set to LOW */
205                 rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
206             }
207             else
208             {
209                 SPI_SET_SS_LOW(spi_bus->spi_base);
210             }
211         }
212         else
213         {
214             /* Set CS pin to HIGH */
215             if (pvUserData != RT_NULL)
216             {
217                 // set to HIGH */
218                 rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
219             }
220             else
221             {
222                 /* Set CS pin to HIGH */
223                 SPI_SET_SS_HIGH(spi_bus->spi_base);
224             }
225         }
226 
227         if (configuration->mode & RT_SPI_MSB)
228         {
229             /* Set sequence to MSB first */
230             SPI_SET_MSB_FIRST(spi_bus->spi_base);
231         }
232         else
233         {
234             /* Set sequence to LSB first */
235             SPI_SET_LSB_FIRST(spi_bus->spi_base);
236         }
237     }
238 
239     /* Clear SPI RX FIFO */
240     nu_spi_drain_rxfifo(spi_bus->spi_base);
241 
242 exit_nu_spi_bus_configure:
243 
244     return -(ret);
245 }
246 
247 #if defined(BSP_USING_SPI_PDMA)
nu_pdma_spi_rx_cb_event(void * pvUserData,uint32_t u32EventFilter)248 static void nu_pdma_spi_rx_cb_event(void *pvUserData, uint32_t u32EventFilter)
249 {
250     rt_err_t result = RT_EOK;
251     struct nu_spi *spi_bus = (struct nu_spi *)pvUserData;
252 
253     RT_ASSERT(spi_bus != RT_NULL);
254 
255     result = rt_sem_release(spi_bus->m_psSemBus);
256     RT_ASSERT(result == RT_EOK);
257 }
258 
nu_pdma_spi_tx_cb_trigger(void * pvUserData,uint32_t u32UserData)259 static void nu_pdma_spi_tx_cb_trigger(void *pvUserData, uint32_t u32UserData)
260 {
261     /* Get base address of spi register */
262     SPI_T *spi_base = (SPI_T *)pvUserData;
263 
264     /* Trigger TX/RX PDMA transfer. */
265     SPI_TRIGGER_TX_RX_PDMA(spi_base);
266 }
267 
nu_pdma_spi_rx_cb_disable(void * pvUserData,uint32_t u32UserData)268 static void nu_pdma_spi_rx_cb_disable(void *pvUserData, uint32_t u32UserData)
269 {
270     /* Get base address of spi register */
271     SPI_T *spi_base = (SPI_T *)pvUserData;
272 
273     /* Stop TX/RX DMA transfer. */
274     SPI_DISABLE_TX_RX_PDMA(spi_base);
275 }
276 
nu_pdma_spi_rx_config(struct nu_spi * spi_bus,uint8_t * pu8Buf,int32_t i32RcvLen,uint8_t bytes_per_word)277 static rt_err_t nu_pdma_spi_rx_config(struct nu_spi *spi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word)
278 {
279     struct nu_pdma_chn_cb sChnCB;
280 
281     rt_err_t result = RT_EOK;
282     rt_uint8_t *dst_addr = NULL;
283     nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
284 
285     /* Get base address of spi register */
286     SPI_T *spi_base = spi_bus->spi_base;
287 
288     rt_uint8_t spi_pdma_rx_chid = spi_bus->pdma_chanid_rx;
289 
290     nu_pdma_filtering_set(spi_pdma_rx_chid, NU_PDMA_EVENT_TRANSFER_DONE);
291 
292     /* Register ISR callback function */
293     sChnCB.m_eCBType = eCBType_Event;
294     sChnCB.m_pfnCBHandler = nu_pdma_spi_rx_cb_event;
295     sChnCB.m_pvUserData = (void *)spi_bus;
296     result = nu_pdma_callback_register(spi_pdma_rx_chid, &sChnCB);
297     if (result != RT_EOK)
298     {
299         goto exit_nu_pdma_spi_rx_config;
300     }
301 
302     /* Register Disable engine dma trigger callback function */
303     sChnCB.m_eCBType = eCBType_Disable;
304     sChnCB.m_pfnCBHandler = nu_pdma_spi_rx_cb_disable;
305     sChnCB.m_pvUserData = (void *)spi_base;
306     result = nu_pdma_callback_register(spi_pdma_rx_chid, &sChnCB);
307     if (result != RT_EOK)
308     {
309         goto exit_nu_pdma_spi_rx_config;
310     }
311 
312     if (pu8Buf == RT_NULL)
313     {
314         memctrl  = eMemCtl_SrcFix_DstFix;
315         dst_addr = (rt_uint8_t *) &spi_bus->dummy;
316     }
317     else
318     {
319         memctrl  = eMemCtl_SrcFix_DstInc;
320         dst_addr = pu8Buf;
321     }
322 
323     result = nu_pdma_channel_memctrl_set(spi_pdma_rx_chid, memctrl);
324     if (result != RT_EOK)
325     {
326         goto exit_nu_pdma_spi_rx_config;
327     }
328 
329     result = nu_pdma_transfer(spi_pdma_rx_chid,
330                               bytes_per_word * 8,
331                               (uint32_t)&spi_base->RX,
332                               (uint32_t)dst_addr,
333                               i32RcvLen / bytes_per_word,
334                               0);
335 exit_nu_pdma_spi_rx_config:
336 
337     return result;
338 }
339 
nu_pdma_spi_tx_config(struct nu_spi * spi_bus,const uint8_t * pu8Buf,int32_t i32SndLen,uint8_t bytes_per_word)340 static rt_err_t nu_pdma_spi_tx_config(struct nu_spi *spi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word)
341 {
342     struct nu_pdma_chn_cb sChnCB;
343 
344     rt_err_t result = RT_EOK;
345     rt_uint8_t *src_addr = NULL;
346     nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
347 
348     /* Get base address of spi register */
349     SPI_T *spi_base = spi_bus->spi_base;
350 
351     rt_uint8_t spi_pdma_tx_chid = spi_bus->pdma_chanid_tx;
352 
353     if (pu8Buf == RT_NULL)
354     {
355         spi_bus->dummy = 0;
356         memctrl = eMemCtl_SrcFix_DstFix;
357         src_addr = (rt_uint8_t *)&spi_bus->dummy;
358     }
359     else
360     {
361         memctrl = eMemCtl_SrcInc_DstFix;
362         src_addr = (rt_uint8_t *)pu8Buf;
363     }
364 
365     /* Register Disable engine dma trigger callback function */
366     sChnCB.m_eCBType = eCBType_Trigger;
367     sChnCB.m_pfnCBHandler = nu_pdma_spi_tx_cb_trigger;
368     sChnCB.m_pvUserData = (void *)spi_base;
369     result = nu_pdma_callback_register(spi_pdma_tx_chid, &sChnCB);
370     if (result != RT_EOK)
371     {
372         goto exit_nu_pdma_spi_tx_config;
373     }
374 
375     result = nu_pdma_channel_memctrl_set(spi_pdma_tx_chid, memctrl);
376     if (result != RT_EOK)
377     {
378         goto exit_nu_pdma_spi_tx_config;
379     }
380 
381     result = nu_pdma_transfer(spi_pdma_tx_chid,
382                               bytes_per_word * 8,
383                               (uint32_t)src_addr,
384                               (uint32_t)&spi_base->TX,
385                               i32SndLen / bytes_per_word,
386                               0);
387 exit_nu_pdma_spi_tx_config:
388 
389     return result;
390 }
391 
392 
393 /**
394  * SPI PDMA transfer
395  */
nu_spi_pdma_transmit(struct nu_spi * spi_bus,const uint8_t * send_addr,uint8_t * recv_addr,int length,uint8_t bytes_per_word)396 static rt_ssize_t nu_spi_pdma_transmit(struct nu_spi *spi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
397 {
398     rt_err_t result = RT_EOK;
399 
400     result = nu_pdma_spi_rx_config(spi_bus, recv_addr, length, bytes_per_word);
401     RT_ASSERT(result == RT_EOK);
402 
403     result = nu_pdma_spi_tx_config(spi_bus, send_addr, length, bytes_per_word);
404     RT_ASSERT(result == RT_EOK);
405 
406     /* Wait RX-PDMA transfer done */
407     result = rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
408     RT_ASSERT(result == RT_EOK);
409 
410     return length;
411 }
412 
nu_hw_spi_pdma_allocate(struct nu_spi * spi_bus)413 rt_err_t nu_hw_spi_pdma_allocate(struct nu_spi *spi_bus)
414 {
415     /* Allocate SPI_TX nu_dma channel */
416     if ((spi_bus->pdma_chanid_tx = nu_pdma_channel_allocate(spi_bus->pdma_perp_tx)) < 0)
417     {
418         goto exit_nu_hw_spi_pdma_allocate;
419     }
420     /* Allocate SPI_RX nu_dma channel */
421     else if ((spi_bus->pdma_chanid_rx = nu_pdma_channel_allocate(spi_bus->pdma_perp_rx)) < 0)
422     {
423         nu_pdma_channel_free(spi_bus->pdma_chanid_tx);
424         goto exit_nu_hw_spi_pdma_allocate;
425     }
426 
427     spi_bus->m_psSemBus = rt_sem_create("spibus_sem", 0, RT_IPC_FLAG_FIFO);
428     RT_ASSERT(spi_bus->m_psSemBus != RT_NULL);
429 
430     return RT_EOK;
431 
432 exit_nu_hw_spi_pdma_allocate:
433 
434     return -(RT_ERROR);
435 }
436 #endif /* #if defined(BSP_USING_SPI_PDMA) */
437 
nu_spi_drain_rxfifo(SPI_T * spi_base)438 void nu_spi_drain_rxfifo(SPI_T *spi_base)
439 {
440     while (SPI_IS_BUSY(spi_base));
441 
442     // Drain SPI RX FIFO, make sure RX FIFO is empty
443     while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
444     {
445         SPI_ClearRxFIFO(spi_base);
446     }
447 }
448 
nu_spi_read(SPI_T * spi_base,uint8_t * recv_addr,uint8_t bytes_per_word)449 static int nu_spi_read(SPI_T *spi_base, uint8_t *recv_addr, uint8_t bytes_per_word)
450 {
451     int size = 0;
452 
453     // Read RX data
454     if (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
455     {
456         uint32_t val;
457         // Read data from SPI RX FIFO
458         switch (bytes_per_word)
459         {
460         case 4:
461             val = SPI_READ_RX(spi_base);
462             nu_set32_le(recv_addr, val);
463             break;
464         case 3:
465             val = SPI_READ_RX(spi_base);
466             nu_set24_le(recv_addr, val);
467             break;
468         case 2:
469             val = SPI_READ_RX(spi_base);
470             nu_set16_le(recv_addr, val);
471             break;
472         case 1:
473             *recv_addr = SPI_READ_RX(spi_base);
474             break;
475         default:
476             LOG_E("Data length is not supported.\n");
477             break;
478         }
479         size = bytes_per_word;
480     }
481     return size;
482 }
483 
nu_spi_write(SPI_T * spi_base,const uint8_t * send_addr,uint8_t bytes_per_word)484 static int nu_spi_write(SPI_T *spi_base, const uint8_t *send_addr, uint8_t bytes_per_word)
485 {
486     // Wait SPI TX send data
487     while (SPI_GET_TX_FIFO_FULL_FLAG(spi_base));
488 
489     // Input data to SPI TX
490     switch (bytes_per_word)
491     {
492     case 4:
493         SPI_WRITE_TX(spi_base, nu_get32_le(send_addr));
494         break;
495     case 3:
496         SPI_WRITE_TX(spi_base, nu_get24_le(send_addr));
497         break;
498     case 2:
499         SPI_WRITE_TX(spi_base, nu_get16_le(send_addr));
500         break;
501     case 1:
502         SPI_WRITE_TX(spi_base, *((uint8_t *)send_addr));
503         break;
504     default:
505         LOG_E("Data length is not supported.\n");
506         break;
507     }
508 
509     return bytes_per_word;
510 }
511 
512 /**
513  * @brief SPI bus polling
514  * @param dev : The pointer of the specified SPI module.
515  * @param send_addr : Source address
516  * @param recv_addr : Destination address
517  * @param length    : Data length
518  */
nu_spi_transmission_with_poll(struct nu_spi * spi_bus,uint8_t * send_addr,uint8_t * recv_addr,int length,uint8_t bytes_per_word)519 static void nu_spi_transmission_with_poll(struct nu_spi *spi_bus,
520         uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
521 {
522     SPI_T *spi_base = spi_bus->spi_base;
523 
524     // Write-only
525     if ((send_addr != RT_NULL) && (recv_addr == RT_NULL))
526     {
527         while (length > 0)
528         {
529             send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
530             length -= bytes_per_word;
531         }
532     } // if (send_addr != RT_NULL && recv_addr == RT_NULL)
533     // Read-only
534     else if ((send_addr == RT_NULL) && (recv_addr != RT_NULL))
535     {
536         spi_bus->dummy = 0;
537         while (length > 0)
538         {
539             /* Input data to SPI TX FIFO */
540             length -= nu_spi_write(spi_base, (const uint8_t *)&spi_bus->dummy, bytes_per_word);
541 
542             /* Read data from RX FIFO */
543             recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
544         }
545     } // else if (send_addr == RT_NULL && recv_addr != RT_NULL)
546     // Read&Write
547     else
548     {
549         while (length > 0)
550         {
551             /* Input data to SPI TX FIFO */
552             send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
553             length -= bytes_per_word;
554 
555             /* Read data from RX FIFO */
556             recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
557         }
558     } // else
559 
560     /* Wait RX or drain RX-FIFO */
561     if (recv_addr)
562     {
563         // Wait SPI transmission done
564         while (SPI_IS_BUSY(spi_base))
565         {
566             while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
567             {
568                 recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
569             }
570         }
571 
572         while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
573         {
574             recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
575         }
576     }
577     else
578     {
579         /* Clear SPI RX FIFO */
580         nu_spi_drain_rxfifo(spi_base);
581     }
582 }
583 
nu_spi_transfer(struct nu_spi * spi_bus,uint8_t * tx,uint8_t * rx,int length,uint8_t bytes_per_word)584 void nu_spi_transfer(struct nu_spi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
585 {
586     RT_ASSERT(spi_bus != RT_NULL);
587 
588 #if defined(BSP_USING_SPI_PDMA)
589     /* DMA transfer constrains */
590     if ((spi_bus->pdma_chanid_rx >= 0) &&
591             !((uint32_t)tx % bytes_per_word) &&
592             !((uint32_t)rx % bytes_per_word) &&
593             (bytes_per_word != 3) &&
594             (length >= NU_SPI_USE_PDMA_MIN_THRESHOLD))
595         nu_spi_pdma_transmit(spi_bus, tx, rx, length, bytes_per_word);
596     else
597         nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
598 #else
599     nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
600 #endif
601 }
602 
nu_spi_bus_xfer(struct rt_spi_device * device,struct rt_spi_message * message)603 static rt_ssize_t nu_spi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
604 {
605     struct nu_spi *spi_bus;
606     struct rt_spi_configuration *configuration;
607     uint8_t bytes_per_word;
608     void *pvUserData;
609 
610     RT_ASSERT(device != RT_NULL);
611     RT_ASSERT(device->bus != RT_NULL);
612     RT_ASSERT(message != RT_NULL);
613 
614     spi_bus = (struct nu_spi *) device->bus;
615     configuration = (struct rt_spi_configuration *)&spi_bus->configuration;
616     bytes_per_word = configuration->data_width / 8;
617     pvUserData = device->parent.user_data;
618 
619     if ((message->length % bytes_per_word) != 0)
620     {
621         /* Say bye. */
622         LOG_E("%s: error payload length(%d%%%d != 0).\n", spi_bus->name, message->length, bytes_per_word);
623         return 0;
624     }
625 
626     if (message->length > 0)
627     {
628         if (message->cs_take && !(configuration->mode & RT_SPI_NO_CS))
629         {
630             if (pvUserData != RT_NULL)
631             {
632                 if (configuration->mode & RT_SPI_CS_HIGH)
633                 {
634                     // set to HIGH */
635                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
636                 }
637                 else
638                 {
639                     // set to LOW */
640                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
641                 }
642             }
643             else
644             {
645                 if (configuration->mode & RT_SPI_CS_HIGH)
646                 {
647                     SPI_SET_SS_HIGH(spi_bus->spi_base);
648                 }
649                 else
650                 {
651                     SPI_SET_SS_LOW(spi_bus->spi_base);
652                 }
653             }
654         }
655 
656         nu_spi_transfer(spi_bus, (uint8_t *)message->send_buf, (uint8_t *)message->recv_buf, message->length, bytes_per_word);
657 
658         if (message->cs_release && !(configuration->mode & RT_SPI_NO_CS))
659         {
660             if (pvUserData != RT_NULL)
661             {
662                 if (configuration->mode & RT_SPI_CS_HIGH)
663                 {
664                     // set to LOW */
665                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
666                 }
667                 else
668                 {
669                     // set to HIGH */
670                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
671                 }
672             }
673             else
674             {
675                 if (configuration->mode & RT_SPI_CS_HIGH)
676                 {
677                     SPI_SET_SS_LOW(spi_bus->spi_base);
678                 }
679                 else
680                 {
681                     SPI_SET_SS_HIGH(spi_bus->spi_base);
682                 }
683             }
684         }
685 
686     }
687 
688     return message->length;
689 }
690 
nu_spi_register_bus(struct nu_spi * spi_bus,const char * name)691 static int nu_spi_register_bus(struct nu_spi *spi_bus, const char *name)
692 {
693     return rt_spi_bus_register(&spi_bus->dev, name, &nu_spi_poll_ops);
694 }
695 
696 /**
697  * Hardware SPI Initial
698  */
rt_hw_spi_init(void)699 static int rt_hw_spi_init(void)
700 {
701     int i;
702 
703     for (i = (SPI_START + 1); i < SPI_CNT; i++)
704     {
705         nu_sys_ip_reset(nu_spi_arr[i].rstidx);
706 
707         nu_spi_register_bus(&nu_spi_arr[i], nu_spi_arr[i].name);
708 #if defined(BSP_USING_SPI_PDMA)
709         nu_spi_arr[i].pdma_chanid_tx = -1;
710         nu_spi_arr[i].pdma_chanid_rx = -1;
711         if ((nu_spi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_spi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
712         {
713             if (nu_hw_spi_pdma_allocate(&nu_spi_arr[i]) != RT_EOK)
714             {
715                 LOG_W("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_spi_arr[i].name);
716             }
717         }
718 #endif
719     }
720 
721     return 0;
722 }
723 
724 INIT_DEVICE_EXPORT(rt_hw_spi_init);
725 
726 #endif //#if defined(BSP_USING_SPI)
727