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 * 2022-3-15       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 #if defined(BSP_USING_SPI4)
52     SPI4_IDX,
53 #endif
54 #if defined(BSP_USING_SPI5)
55     SPI5_IDX,
56 #endif
57 #if defined(BSP_USING_SPI6)
58     SPI6_IDX,
59 #endif
60 #if defined(BSP_USING_SPI7)
61     SPI7_IDX,
62 #endif
63 #if defined(BSP_USING_SPI8)
64     SPI8_IDX,
65 #endif
66 #if defined(BSP_USING_SPI9)
67     SPI9_IDX,
68 #endif
69 #if defined(BSP_USING_SPI10)
70     SPI10_IDX,
71 #endif
72     SPI_CNT
73 };
74 
75 /* Private typedef --------------------------------------------------------------*/
76 
77 /* Private functions ------------------------------------------------------------*/
78 static void nu_spi_transmission_with_poll(struct nu_spi *spi_bus,
79         uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
80 static int nu_spi_register_bus(struct nu_spi *spi_bus, const char *name);
81 static rt_ssize_t nu_spi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
82 static rt_err_t nu_spi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
83 
84 #if defined(BSP_USING_SPI_PDMA)
85     static void nu_pdma_spi_rx_cb_event(void *pvUserData, uint32_t u32EventFilter);
86     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);
87     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);
88     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);
89 #endif
90 /* Public functions -------------------------------------------------------------*/
91 void nu_spi_transfer(struct nu_spi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word);
92 void nu_spi_drain_rxfifo(SPI_T *spi_base);
93 
94 /* Private variables ------------------------------------------------------------*/
95 static struct rt_spi_ops nu_spi_poll_ops =
96 {
97     .configure = nu_spi_bus_configure,
98     .xfer      = nu_spi_bus_xfer,
99 };
100 
101 static struct nu_spi nu_spi_arr [] =
102 {
103 #if defined(BSP_USING_SPI0)
104     {
105         .name = "spi0",
106         .spi_base = SPI0,
107         .rstidx = SPI0_RST,
108 #if defined(BSP_USING_SPI_PDMA)
109 #if defined(BSP_USING_SPI0_PDMA)
110         .pdma_perp_tx = PDMA_SPI0_TX,
111         .pdma_perp_rx = PDMA_SPI0_RX,
112 #else
113         .pdma_perp_tx = NU_PDMA_UNUSED,
114         .pdma_perp_rx = NU_PDMA_UNUSED,
115 #endif
116 #endif
117     },
118 #endif
119 #if defined(BSP_USING_SPI1)
120     {
121         .name = "spi1",
122         .spi_base = SPI1,
123         .rstidx = SPI1_RST,
124 #if defined(BSP_USING_SPI_PDMA)
125 #if defined(BSP_USING_SPI1_PDMA)
126         .pdma_perp_tx = PDMA_SPI1_TX,
127         .pdma_perp_rx = PDMA_SPI1_RX,
128 #else
129         .pdma_perp_tx = NU_PDMA_UNUSED,
130         .pdma_perp_rx = NU_PDMA_UNUSED,
131 #endif
132 #endif
133     },
134 #endif
135 #if defined(BSP_USING_SPI2)
136     {
137         .name = "spi2",
138         .spi_base = SPI2,
139         .rstidx = SPI2_RST,
140 #if defined(BSP_USING_SPI_PDMA)
141 #if defined(BSP_USING_SPI2_PDMA)
142         .pdma_perp_tx = PDMA_SPI2_TX,
143         .pdma_perp_rx = PDMA_SPI2_RX,
144 #else
145         .pdma_perp_tx = NU_PDMA_UNUSED,
146         .pdma_perp_rx = NU_PDMA_UNUSED,
147 #endif
148 #endif
149     },
150 #endif
151 #if defined(BSP_USING_SPI3)
152     {
153         .name = "spi3",
154         .spi_base = SPI3,
155         .rstidx = SPI3_RST,
156 #if defined(BSP_USING_SPI_PDMA)
157 #if defined(BSP_USING_SPI3_PDMA)
158         .pdma_perp_tx = PDMA_SPI3_TX,
159         .pdma_perp_rx = PDMA_SPI3_RX,
160 #else
161         .pdma_perp_tx = NU_PDMA_UNUSED,
162         .pdma_perp_rx = NU_PDMA_UNUSED,
163 #endif
164 #endif
165     },
166 #endif
167 
168 #if defined(BSP_USING_SPI4)
169     {
170         .name = "spi4",
171         .spi_base = SPI4,
172         .rstidx = SPI4_RST,
173 #if defined(BSP_USING_SPI_PDMA)
174 #if defined(BSP_USING_SPI4_PDMA)
175         .pdma_perp_tx = PDMA_SPI4_TX,
176         .pdma_perp_rx = PDMA_SPI4_RX,
177 #else
178         .pdma_perp_tx = NU_PDMA_UNUSED,
179         .pdma_perp_rx = NU_PDMA_UNUSED,
180 #endif
181 #endif
182 
183     },
184 #endif
185 
186 #if defined(BSP_USING_SPI5)
187     {
188         .name = "spi5",
189         .spi_base = SPI5,
190         .rstidx = SPI5_RST,
191 #if defined(BSP_USING_SPI_PDMA)
192 #if defined(BSP_USING_SPI5_PDMA)
193         .pdma_perp_tx = PDMA_SPI5_TX,
194         .pdma_perp_rx = PDMA_SPI5_RX,
195 #else
196         .pdma_perp_tx = NU_PDMA_UNUSED,
197         .pdma_perp_rx = NU_PDMA_UNUSED,
198 #endif
199 #endif
200 
201     },
202 #endif
203 
204 #if defined(BSP_USING_SPI6)
205     {
206         .name = "spi6",
207         .spi_base = SPI6,
208         .rstidx = SPI6_RST,
209 #if defined(BSP_USING_SPI_PDMA)
210 #if defined(BSP_USING_SPI6_PDMA)
211         .pdma_perp_tx = PDMA_SPI6_TX,
212         .pdma_perp_rx = PDMA_SPI6_RX,
213 #else
214         .pdma_perp_tx = NU_PDMA_UNUSED,
215         .pdma_perp_rx = NU_PDMA_UNUSED,
216 #endif
217 #endif
218 
219     },
220 #endif
221 
222 #if defined(BSP_USING_SPI7)
223     {
224         .name = "spi7",
225         .spi_base = SPI7,
226         .rstidx = SPI7_RST,
227 #if defined(BSP_USING_SPI_PDMA)
228 #if defined(BSP_USING_SPI7_PDMA)
229         .pdma_perp_tx = PDMA_SPI7_TX,
230         .pdma_perp_rx = PDMA_SPI7_RX,
231 #else
232         .pdma_perp_tx = NU_PDMA_UNUSED,
233         .pdma_perp_rx = NU_PDMA_UNUSED,
234 #endif
235 #endif
236 
237     },
238 #endif
239 
240 #if defined(BSP_USING_SPI8)
241     {
242         .name = "spi8",
243         .spi_base = SPI8,
244         .rstidx = SPI8_RST,
245 #if defined(BSP_USING_SPI_PDMA)
246 #if defined(BSP_USING_SPI8_PDMA)
247         .pdma_perp_tx = PDMA_SPI8_TX,
248         .pdma_perp_rx = PDMA_SPI8_RX,
249 #else
250         .pdma_perp_tx = NU_PDMA_UNUSED,
251         .pdma_perp_rx = NU_PDMA_UNUSED,
252 #endif
253 #endif
254 
255     },
256 #endif
257 
258 #if defined(BSP_USING_SPI9)
259     {
260         .name = "spi9",
261         .spi_base = SPI9,
262         .rstidx = SPI9_RST,
263 #if defined(BSP_USING_SPI_PDMA)
264 #if defined(BSP_USING_SPI9_PDMA)
265         .pdma_perp_tx = PDMA_SPI9_TX,
266         .pdma_perp_rx = PDMA_SPI9_RX,
267 #else
268         .pdma_perp_tx = NU_PDMA_UNUSED,
269         .pdma_perp_rx = NU_PDMA_UNUSED,
270 #endif
271 #endif
272 
273     },
274 #endif
275 
276 #if defined(BSP_USING_SPI10)
277     {
278         .name = "spi10",
279         .spi_base = SPI10,
280         .rstidx = SPI10_RST,
281 #if defined(BSP_USING_SPI_PDMA)
282 #if defined(BSP_USING_SPI10_PDMA)
283         .pdma_perp_tx = PDMA_SPI10_TX,
284         .pdma_perp_rx = PDMA_SPI10_RX,
285 #else
286         .pdma_perp_tx = NU_PDMA_UNUSED,
287         .pdma_perp_rx = NU_PDMA_UNUSED,
288 #endif
289 #endif
290 
291     },
292 #endif
293 
294 }; /* spi nu_spi */
295 
nu_spi_bus_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)296 static rt_err_t nu_spi_bus_configure(struct rt_spi_device *device,
297                                      struct rt_spi_configuration *configuration)
298 {
299     struct nu_spi *spi_bus;
300     uint32_t u32SPIMode;
301     uint32_t u32BusClock;
302     rt_err_t ret = RT_EOK;
303     void *pvUserData;
304 
305     RT_ASSERT(device);
306     RT_ASSERT(configuration);
307 
308     spi_bus = (struct nu_spi *) device->bus;
309     pvUserData = device->parent.user_data;
310 
311     /* Check mode */
312     switch (configuration->mode & RT_SPI_MODE_3)
313     {
314     case RT_SPI_MODE_0:
315         u32SPIMode = SPI_MODE_0;
316         break;
317     case RT_SPI_MODE_1:
318         u32SPIMode = SPI_MODE_1;
319         break;
320     case RT_SPI_MODE_2:
321         u32SPIMode = SPI_MODE_2;
322         break;
323     case RT_SPI_MODE_3:
324         u32SPIMode = SPI_MODE_3;
325         break;
326     default:
327         ret = -RT_EIO;
328         goto exit_nu_spi_bus_configure;
329     }
330 
331     /* Check data width */
332     if (!(configuration->data_width == 8  ||
333             configuration->data_width == 16 ||
334             configuration->data_width == 24 ||
335             configuration->data_width == 32))
336     {
337         ret = -RT_EINVAL;
338         goto exit_nu_spi_bus_configure;
339     }
340 
341     /* Try to set clock and get actual spi bus clock */
342     u32BusClock = SPI_SetBusClock(spi_bus->spi_base, configuration->max_hz);
343     if (configuration->max_hz > u32BusClock)
344     {
345         LOG_W("%s clock max frequency is %dHz (!= %dHz)\n", spi_bus->name, u32BusClock, configuration->max_hz);
346         configuration->max_hz = u32BusClock;
347     }
348 
349     /* Need to initialize new configuration? */
350     if (rt_memcmp(configuration, &spi_bus->configuration, sizeof(*configuration)) != 0)
351     {
352         rt_memcpy(&spi_bus->configuration, configuration, sizeof(*configuration));
353 
354         SPI_Open(spi_bus->spi_base, SPI_MASTER, u32SPIMode, configuration->data_width, u32BusClock);
355 
356         if (configuration->mode & RT_SPI_CS_HIGH)
357         {
358             /* Set CS pin to LOW */
359             if (pvUserData != RT_NULL)
360             {
361                 // set to LOW */
362                 rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
363             }
364             else
365             {
366                 SPI_SET_SS_LOW(spi_bus->spi_base);
367             }
368         }
369         else
370         {
371             /* Set CS pin to HIGH */
372             if (pvUserData != RT_NULL)
373             {
374                 // set to HIGH */
375                 rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
376             }
377             else
378             {
379                 /* Set CS pin to HIGH */
380                 SPI_SET_SS_HIGH(spi_bus->spi_base);
381             }
382         }
383 
384         if (configuration->mode & RT_SPI_MSB)
385         {
386             /* Set sequence to MSB first */
387             SPI_SET_MSB_FIRST(spi_bus->spi_base);
388         }
389         else
390         {
391             /* Set sequence to LSB first */
392             SPI_SET_LSB_FIRST(spi_bus->spi_base);
393         }
394     }
395 
396     /* Clear SPI RX FIFO */
397     nu_spi_drain_rxfifo(spi_bus->spi_base);
398 
399 exit_nu_spi_bus_configure:
400 
401     return -(ret);
402 }
403 
404 #if defined(BSP_USING_SPI_PDMA)
nu_pdma_spi_rx_cb_event(void * pvUserData,uint32_t u32EventFilter)405 static void nu_pdma_spi_rx_cb_event(void *pvUserData, uint32_t u32EventFilter)
406 {
407     rt_err_t result;
408     struct nu_spi *spi_bus = (struct nu_spi *)pvUserData;
409 
410     RT_ASSERT(spi_bus);
411 
412     result = rt_sem_release(spi_bus->m_psSemBus);
413     RT_ASSERT(result == RT_EOK);
414 }
415 
nu_pdma_spi_tx_cb_trigger(void * pvUserData,uint32_t u32UserData)416 static void nu_pdma_spi_tx_cb_trigger(void *pvUserData, uint32_t u32UserData)
417 {
418     /* Get base address of spi register */
419     SPI_T *spi_base = (SPI_T *)pvUserData;
420 
421     /* Trigger TX/RX PDMA transfer. */
422     SPI_TRIGGER_TX_RX_PDMA(spi_base);
423 }
424 
nu_pdma_spi_rx_cb_disable(void * pvUserData,uint32_t u32UserData)425 static void nu_pdma_spi_rx_cb_disable(void *pvUserData, uint32_t u32UserData)
426 {
427     /* Get base address of spi register */
428     SPI_T *spi_base = (SPI_T *)pvUserData;
429 
430     /* Stop TX/RX DMA transfer. */
431     SPI_DISABLE_TX_RX_PDMA(spi_base);
432 }
433 
nu_pdma_spi_rx_config(struct nu_spi * spi_bus,uint8_t * pu8Buf,int32_t i32RcvLen,uint8_t bytes_per_word)434 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)
435 {
436     struct nu_pdma_chn_cb sChnCB;
437 
438     rt_err_t result;
439     rt_uint8_t *dst_addr = NULL;
440     nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
441 
442     /* Get base address of spi register */
443     SPI_T *spi_base = spi_bus->spi_base;
444 
445     rt_uint8_t spi_pdma_rx_chid = spi_bus->pdma_chanid_rx;
446 
447     nu_pdma_filtering_set(spi_pdma_rx_chid, NU_PDMA_EVENT_TRANSFER_DONE);
448 
449     /* Register ISR callback function */
450     sChnCB.m_eCBType = eCBType_Event;
451     sChnCB.m_pfnCBHandler = nu_pdma_spi_rx_cb_event;
452     sChnCB.m_pvUserData = (void *)spi_bus;
453     result = nu_pdma_callback_register(spi_pdma_rx_chid, &sChnCB);
454     if (result != RT_EOK)
455     {
456         goto exit_nu_pdma_spi_rx_config;
457     }
458 
459     /* Register Disable engine dma trigger callback function */
460     sChnCB.m_eCBType = eCBType_Disable;
461     sChnCB.m_pfnCBHandler = nu_pdma_spi_rx_cb_disable;
462     sChnCB.m_pvUserData = (void *)spi_base;
463     result = nu_pdma_callback_register(spi_pdma_rx_chid, &sChnCB);
464     if (result != RT_EOK)
465     {
466         goto exit_nu_pdma_spi_rx_config;
467     }
468 
469     if (pu8Buf == RT_NULL)
470     {
471         memctrl  = eMemCtl_SrcFix_DstFix;
472         dst_addr = (rt_uint8_t *) &spi_bus->dummy;
473     }
474     else
475     {
476         memctrl  = eMemCtl_SrcFix_DstInc;
477         dst_addr = pu8Buf;
478     }
479 
480     result = nu_pdma_channel_memctrl_set(spi_pdma_rx_chid, memctrl);
481     if (result != RT_EOK)
482     {
483         goto exit_nu_pdma_spi_rx_config;
484     }
485 
486     result = nu_pdma_transfer(spi_pdma_rx_chid,
487                               bytes_per_word * 8,
488                               (uint32_t)&spi_base->RX,
489                               (uint32_t)dst_addr,
490                               i32RcvLen / bytes_per_word,
491                               0);
492 exit_nu_pdma_spi_rx_config:
493 
494     return result;
495 }
496 
nu_pdma_spi_tx_config(struct nu_spi * spi_bus,const uint8_t * pu8Buf,int32_t i32SndLen,uint8_t bytes_per_word)497 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)
498 {
499     struct nu_pdma_chn_cb sChnCB;
500 
501     rt_err_t result;
502     rt_uint8_t *src_addr = NULL;
503     nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
504 
505     /* Get base address of spi register */
506     SPI_T *spi_base = spi_bus->spi_base;
507 
508     rt_uint8_t spi_pdma_tx_chid = spi_bus->pdma_chanid_tx;
509 
510     if (pu8Buf == RT_NULL)
511     {
512         spi_bus->dummy = 0;
513         memctrl = eMemCtl_SrcFix_DstFix;
514         src_addr = (rt_uint8_t *)&spi_bus->dummy;
515     }
516     else
517     {
518         memctrl = eMemCtl_SrcInc_DstFix;
519         src_addr = (rt_uint8_t *)pu8Buf;
520     }
521 
522     /* Register Disable engine dma trigger callback function */
523     sChnCB.m_eCBType = eCBType_Trigger;
524     sChnCB.m_pfnCBHandler = nu_pdma_spi_tx_cb_trigger;
525     sChnCB.m_pvUserData = (void *)spi_base;
526     result = nu_pdma_callback_register(spi_pdma_tx_chid, &sChnCB);
527     if (result != RT_EOK)
528     {
529         goto exit_nu_pdma_spi_tx_config;
530     }
531 
532     result = nu_pdma_channel_memctrl_set(spi_pdma_tx_chid, memctrl);
533     if (result != RT_EOK)
534     {
535         goto exit_nu_pdma_spi_tx_config;
536     }
537 
538     result = nu_pdma_transfer(spi_pdma_tx_chid,
539                               bytes_per_word * 8,
540                               (uint32_t)src_addr,
541                               (uint32_t)&spi_base->TX,
542                               i32SndLen / bytes_per_word,
543                               0);
544 exit_nu_pdma_spi_tx_config:
545 
546     return result;
547 }
548 
549 
550 /**
551  * SPI PDMA transfer
552  */
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)553 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)
554 {
555     rt_err_t result = RT_EOK;
556 
557     result = nu_pdma_spi_rx_config(spi_bus, recv_addr, length, bytes_per_word);
558     RT_ASSERT(result == RT_EOK);
559 
560     result = nu_pdma_spi_tx_config(spi_bus, send_addr, length, bytes_per_word);
561     RT_ASSERT(result == RT_EOK);
562 
563     /* Wait RX-PDMA transfer done */
564     result = rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
565     RT_ASSERT(result == RT_EOK);
566 
567     return length;
568 }
569 
nu_hw_spi_pdma_allocate(struct nu_spi * spi_bus)570 rt_err_t nu_hw_spi_pdma_allocate(struct nu_spi *spi_bus)
571 {
572     /* Allocate SPI_TX nu_dma channel */
573     if ((spi_bus->pdma_chanid_tx = nu_pdma_channel_allocate(spi_bus->pdma_perp_tx)) < 0)
574     {
575         goto exit_nu_hw_spi_pdma_allocate;
576     }
577     /* Allocate SPI_RX nu_dma channel */
578     else if ((spi_bus->pdma_chanid_rx = nu_pdma_channel_allocate(spi_bus->pdma_perp_rx)) < 0)
579     {
580         nu_pdma_channel_free(spi_bus->pdma_chanid_tx);
581         goto exit_nu_hw_spi_pdma_allocate;
582     }
583 
584     spi_bus->m_psSemBus = rt_sem_create("spibus_sem", 0, RT_IPC_FLAG_FIFO);
585     RT_ASSERT(spi_bus->m_psSemBus != RT_NULL);
586 
587     return RT_EOK;
588 
589 exit_nu_hw_spi_pdma_allocate:
590 
591     return -(RT_ERROR);
592 }
593 #endif /* #if defined(BSP_USING_SPI_PDMA) */
594 
nu_spi_drain_rxfifo(SPI_T * spi_base)595 void nu_spi_drain_rxfifo(SPI_T *spi_base)
596 {
597     while (SPI_IS_BUSY(spi_base));
598 
599     // Drain SPI RX FIFO, make sure RX FIFO is empty
600     while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
601     {
602         SPI_ClearRxFIFO(spi_base);
603     }
604 }
605 
nu_spi_read(SPI_T * spi_base,uint8_t * recv_addr,uint8_t bytes_per_word)606 static int nu_spi_read(SPI_T *spi_base, uint8_t *recv_addr, uint8_t bytes_per_word)
607 {
608     int size = 0;
609 
610     // Read RX data
611     if (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
612     {
613         uint32_t val;
614         // Read data from SPI RX FIFO
615         switch (bytes_per_word)
616         {
617         case 4:
618             val = SPI_READ_RX(spi_base);
619             nu_set32_le(recv_addr, val);
620             break;
621         case 3:
622             val = SPI_READ_RX(spi_base);
623             nu_set24_le(recv_addr, val);
624             break;
625         case 2:
626             val = SPI_READ_RX(spi_base);
627             nu_set16_le(recv_addr, val);
628             break;
629         case 1:
630             *recv_addr = SPI_READ_RX(spi_base);
631             break;
632         default:
633             LOG_E("Data length is not supported.\n");
634             break;
635         }
636         size = bytes_per_word;
637     }
638     return size;
639 }
640 
nu_spi_write(SPI_T * spi_base,const uint8_t * send_addr,uint8_t bytes_per_word)641 static int nu_spi_write(SPI_T *spi_base, const uint8_t *send_addr, uint8_t bytes_per_word)
642 {
643     // Wait SPI TX send data
644     while (SPI_GET_TX_FIFO_FULL_FLAG(spi_base));
645 
646     // Input data to SPI TX
647     switch (bytes_per_word)
648     {
649     case 4:
650         SPI_WRITE_TX(spi_base, nu_get32_le(send_addr));
651         break;
652     case 3:
653         SPI_WRITE_TX(spi_base, nu_get24_le(send_addr));
654         break;
655     case 2:
656         SPI_WRITE_TX(spi_base, nu_get16_le(send_addr));
657         break;
658     case 1:
659         SPI_WRITE_TX(spi_base, *((uint8_t *)send_addr));
660         break;
661     default:
662         LOG_E("Data length is not supported.\n");
663         break;
664     }
665 
666     return bytes_per_word;
667 }
668 
669 /**
670  * @brief SPI bus polling
671  * @param dev : The pointer of the specified SPI module.
672  * @param send_addr : Source address
673  * @param recv_addr : Destination address
674  * @param length    : Data length
675  */
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)676 static void nu_spi_transmission_with_poll(struct nu_spi *spi_bus,
677         uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
678 {
679     SPI_T *spi_base = spi_bus->spi_base;
680 
681     // Write-only
682     if ((send_addr != RT_NULL) && (recv_addr == RT_NULL))
683     {
684         while (length > 0)
685         {
686             send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
687             length -= bytes_per_word;
688         }
689     } // if (send_addr != RT_NULL && recv_addr == RT_NULL)
690     // Read-only
691     else if ((send_addr == RT_NULL) && (recv_addr != RT_NULL))
692     {
693         spi_bus->dummy = 0;
694         while (length > 0)
695         {
696             /* Input data to SPI TX FIFO */
697             length -= nu_spi_write(spi_base, (const uint8_t *)&spi_bus->dummy, bytes_per_word);
698 
699             /* Read data from RX FIFO */
700             recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
701         }
702     } // else if (send_addr == RT_NULL && recv_addr != RT_NULL)
703     // Read&Write
704     else
705     {
706         while (length > 0)
707         {
708             /* Input data to SPI TX FIFO */
709             send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
710             length -= bytes_per_word;
711 
712             /* Read data from RX FIFO */
713             recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
714         }
715     } // else
716 
717     /* Wait RX or drain RX-FIFO */
718     if (recv_addr)
719     {
720         // Wait SPI transmission done
721         while (SPI_IS_BUSY(spi_base))
722         {
723             while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
724             {
725                 recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
726             }
727         }
728 
729         while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
730         {
731             recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
732         }
733     }
734     else
735     {
736         /* Clear SPI RX FIFO */
737         nu_spi_drain_rxfifo(spi_base);
738     }
739 }
740 
nu_spi_transfer(struct nu_spi * spi_bus,uint8_t * tx,uint8_t * rx,int length,uint8_t bytes_per_word)741 void nu_spi_transfer(struct nu_spi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
742 {
743     RT_ASSERT(spi_bus != RT_NULL);
744 
745 #if defined(BSP_USING_SPI_PDMA)
746     /* DMA transfer constrains */
747     if ((spi_bus->pdma_chanid_rx >= 0) &&
748             !((uint32_t)tx % bytes_per_word) &&
749             !((uint32_t)rx % bytes_per_word) &&
750             (bytes_per_word != 3) &&
751             (length >= NU_SPI_USE_PDMA_MIN_THRESHOLD))
752         nu_spi_pdma_transmit(spi_bus, tx, rx, length, bytes_per_word);
753     else
754         nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
755 #else
756     nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
757 #endif
758 }
759 
nu_spi_bus_xfer(struct rt_spi_device * device,struct rt_spi_message * message)760 static rt_ssize_t nu_spi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
761 {
762     struct nu_spi *spi_bus;
763     struct rt_spi_configuration *configuration;
764     uint8_t bytes_per_word;
765     void *pvUserData;
766 
767     RT_ASSERT(device != RT_NULL);
768     RT_ASSERT(device->bus != RT_NULL);
769     RT_ASSERT(message != RT_NULL);
770 
771     spi_bus = (struct nu_spi *) device->bus;
772     configuration = (struct rt_spi_configuration *)&spi_bus->configuration;
773     bytes_per_word = configuration->data_width / 8;
774     pvUserData = device->parent.user_data;
775 
776     if ((message->length % bytes_per_word) != 0)
777     {
778         /* Say bye. */
779         LOG_E("%s: error payload length(%d%%%d != 0).\n", spi_bus->name, message->length, bytes_per_word);
780         return 0;
781     }
782 
783     if (message->length > 0)
784     {
785         if (message->cs_take && !(configuration->mode & RT_SPI_NO_CS))
786         {
787             if (pvUserData != RT_NULL)
788             {
789                 if (configuration->mode & RT_SPI_CS_HIGH)
790                 {
791                     // set to HIGH */
792                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
793                 }
794                 else
795                 {
796                     // set to LOW */
797                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
798                 }
799             }
800             else
801             {
802                 if (configuration->mode & RT_SPI_CS_HIGH)
803                 {
804                     SPI_SET_SS_HIGH(spi_bus->spi_base);
805                 }
806                 else
807                 {
808                     SPI_SET_SS_LOW(spi_bus->spi_base);
809                 }
810             }
811         }
812 
813         nu_spi_transfer(spi_bus, (uint8_t *)message->send_buf, (uint8_t *)message->recv_buf, message->length, bytes_per_word);
814 
815         if (message->cs_release && !(configuration->mode & RT_SPI_NO_CS))
816         {
817             if (pvUserData != RT_NULL)
818             {
819                 if (configuration->mode & RT_SPI_CS_HIGH)
820                 {
821                     // set to LOW */
822                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
823                 }
824                 else
825                 {
826                     // set to HIGH */
827                     rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
828                 }
829             }
830             else
831             {
832                 if (configuration->mode & RT_SPI_CS_HIGH)
833                 {
834                     SPI_SET_SS_LOW(spi_bus->spi_base);
835                 }
836                 else
837                 {
838                     SPI_SET_SS_HIGH(spi_bus->spi_base);
839                 }
840             }
841         }
842 
843     }
844 
845     return message->length;
846 }
847 
nu_spi_register_bus(struct nu_spi * spi_bus,const char * name)848 static int nu_spi_register_bus(struct nu_spi *spi_bus, const char *name)
849 {
850     return rt_spi_bus_register(&spi_bus->dev, name, &nu_spi_poll_ops);
851 }
852 
853 /**
854  * Hardware SPI Initial
855  */
rt_hw_spi_init(void)856 static int rt_hw_spi_init(void)
857 {
858     int i;
859 
860     for (i = (SPI_START + 1); i < SPI_CNT; i++)
861     {
862         SYS_ResetModule(nu_spi_arr[i].rstidx);
863         nu_spi_register_bus(&nu_spi_arr[i], nu_spi_arr[i].name);
864 #if defined(BSP_USING_SPI_PDMA)
865         nu_spi_arr[i].pdma_chanid_tx = -1;
866         nu_spi_arr[i].pdma_chanid_rx = -1;
867         if ((nu_spi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_spi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
868         {
869             if (nu_hw_spi_pdma_allocate(&nu_spi_arr[i]) != RT_EOK)
870             {
871                 LOG_W("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_spi_arr[i].name);
872             }
873         }
874 #endif
875     }
876 
877     return 0;
878 }
879 
880 INIT_DEVICE_EXPORT(rt_hw_spi_init);
881 
882 #endif //#if defined(BSP_USING_SPI)
883