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