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