1 /*
2 * Copyright (c) 2017 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_REGISTER(spi_loopback);
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/printk.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <assert.h>
16 #include <zephyr/ztest.h>
17
18 #include <zephyr/drivers/spi.h>
19
20 #define SPI_FAST_DEV DT_COMPAT_GET_ANY_STATUS_OKAY(test_spi_loopback_fast)
21 #define SPI_SLOW_DEV DT_COMPAT_GET_ANY_STATUS_OKAY(test_spi_loopback_slow)
22
23 #if CONFIG_SPI_LOOPBACK_MODE_LOOP
24 #define MODE_LOOP SPI_MODE_LOOP
25 #else
26 #define MODE_LOOP 0
27 #endif
28
29 #ifdef CONFIG_SPI_LOOPBACK_16BITS_FRAMES
30 #define FRAME_SIZE (16)
31 #define FRAME_SIZE_STR ", frame size = 16"
32 #else
33 #define FRAME_SIZE (8)
34 #define FRAME_SIZE_STR ", frame size = 8"
35 #endif /* CONFIG_SPI_LOOPBACK_16BITS_FRAMES */
36
37 #ifdef CONFIG_DMA
38
39 #ifdef CONFIG_NOCACHE_MEMORY
40 #define DMA_ENABLED_STR ", DMA enabled"
41 #else /* CONFIG_NOCACHE_MEMORY */
42 #define DMA_ENABLED_STR ", DMA enabled (without CONFIG_NOCACHE_MEMORY)"
43 #endif
44
45 #else /* CONFIG_DMA */
46
47 #define DMA_ENABLED_STR
48 #endif /* CONFIG_DMA */
49
50 #define SPI_OP(frame_size) SPI_OP_MODE_MASTER | SPI_MODE_CPOL | MODE_LOOP | \
51 SPI_MODE_CPHA | SPI_WORD_SET(frame_size) | SPI_LINES_SINGLE
52
53 static struct spi_dt_spec spi_fast = SPI_DT_SPEC_GET(SPI_FAST_DEV, SPI_OP(FRAME_SIZE), 0);
54 static struct spi_dt_spec spi_slow = SPI_DT_SPEC_GET(SPI_SLOW_DEV, SPI_OP(FRAME_SIZE), 0);
55
56 /* to run this test, connect MOSI pin to the MISO of the SPI */
57
58 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
59 #define BUF_SIZE 18
60 #define BUF2_SIZE 36
61 #define BUF3_SIZE CONFIG_SPI_LARGE_BUFFER_SIZE
62
63
64 #if CONFIG_NOCACHE_MEMORY
65 #define __NOCACHE __attribute__((__section__(".nocache")))
66 #elif defined(CONFIG_DT_DEFINED_NOCACHE)
67 #define __NOCACHE __attribute__((__section__(CONFIG_DT_DEFINED_NOCACHE_NAME)))
68 #else /* CONFIG_NOCACHE_MEMORY */
69 #define __NOCACHE
70 #endif /* CONFIG_NOCACHE_MEMORY */
71
72 static const char tx_data[BUF_SIZE] = "0123456789abcdef-\0";
73 static __aligned(32) char buffer_tx[BUF_SIZE] __used __NOCACHE;
74 static __aligned(32) char buffer_rx[BUF_SIZE] __used __NOCACHE;
75 static const char tx2_data[BUF2_SIZE] = "Thequickbrownfoxjumpsoverthelazydog\0";
76 static __aligned(32) char buffer2_tx[BUF2_SIZE] __used __NOCACHE;
77 static __aligned(32) char buffer2_rx[BUF2_SIZE] __used __NOCACHE;
78 static const char large_tx_data[BUF3_SIZE] = "Thequickbrownfoxjumpsoverthelazydog\0";
79 static __aligned(32) char large_buffer_tx[BUF3_SIZE] __used __NOCACHE;
80 static __aligned(32) char large_buffer_rx[BUF3_SIZE] __used __NOCACHE;
81
82 /*
83 * We need 5x(buffer size) + 1 to print a comma-separated list of each
84 * byte in hex, plus a null.
85 */
86 static uint8_t buffer_print_tx[BUF_SIZE * 5 + 1];
87 static uint8_t buffer_print_rx[BUF_SIZE * 5 + 1];
88
89 static uint8_t buffer_print_tx2[BUF2_SIZE * 5 + 1];
90 static uint8_t buffer_print_rx2[BUF2_SIZE * 5 + 1];
91
to_display_format(const uint8_t * src,size_t size,char * dst)92 static void to_display_format(const uint8_t *src, size_t size, char *dst)
93 {
94 size_t i;
95
96 for (i = 0; i < size; i++) {
97 sprintf(dst + 5 * i, "0x%02x,", src[i]);
98 }
99 }
100
101 /* test transferring different buffers on the same dma channels */
spi_complete_multiple(struct spi_dt_spec * spec)102 static int spi_complete_multiple(struct spi_dt_spec *spec)
103 {
104 struct spi_buf tx_bufs[2];
105 const struct spi_buf_set tx = {
106 .buffers = tx_bufs,
107 .count = ARRAY_SIZE(tx_bufs)
108 };
109
110 tx_bufs[0].buf = buffer_tx;
111 tx_bufs[0].len = BUF_SIZE;
112
113 tx_bufs[1].buf = buffer2_tx;
114 tx_bufs[1].len = BUF2_SIZE;
115
116
117 struct spi_buf rx_bufs[2];
118 const struct spi_buf_set rx = {
119 .buffers = rx_bufs,
120 .count = ARRAY_SIZE(rx_bufs)
121 };
122
123 rx_bufs[0].buf = buffer_rx;
124 rx_bufs[0].len = BUF_SIZE;
125
126 rx_bufs[1].buf = buffer2_rx;
127 rx_bufs[1].len = BUF2_SIZE;
128
129 int ret;
130
131 LOG_INF("Start complete multiple");
132
133 ret = spi_transceive_dt(spec, &tx, &rx);
134 if (ret) {
135 LOG_ERR("Code %d", ret);
136 zassert_false(ret, "SPI transceive failed");
137 return ret;
138 }
139
140 if (memcmp(buffer_tx, buffer_rx, BUF_SIZE)) {
141 to_display_format(buffer_tx, BUF_SIZE, buffer_print_tx);
142 to_display_format(buffer_rx, BUF_SIZE, buffer_print_rx);
143 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
144 LOG_ERR(" vs: %s", buffer_print_rx);
145 zassert_false(1, "Buffer contents are different");
146 return -1;
147 }
148
149 if (memcmp(buffer2_tx, buffer2_rx, BUF2_SIZE)) {
150 to_display_format(buffer2_tx, BUF2_SIZE, buffer_print_tx2);
151 to_display_format(buffer2_rx, BUF2_SIZE, buffer_print_rx2);
152 LOG_ERR("Buffer 2 contents are different: %s", buffer_print_tx2);
153 LOG_ERR(" vs: %s", buffer_print_rx2);
154 zassert_false(1, "Buffer 2 contents are different");
155 return -1;
156 }
157
158 LOG_INF("Passed");
159
160 return 0;
161 }
162
spi_complete_loop(struct spi_dt_spec * spec)163 static int spi_complete_loop(struct spi_dt_spec *spec)
164 {
165 const struct spi_buf tx_bufs[] = {
166 {
167 .buf = buffer_tx,
168 .len = BUF_SIZE,
169 },
170 };
171 const struct spi_buf rx_bufs[] = {
172 {
173 .buf = buffer_rx,
174 .len = BUF_SIZE,
175 },
176 };
177 const struct spi_buf_set tx = {
178 .buffers = tx_bufs,
179 .count = ARRAY_SIZE(tx_bufs)
180 };
181 const struct spi_buf_set rx = {
182 .buffers = rx_bufs,
183 .count = ARRAY_SIZE(rx_bufs)
184 };
185
186 int ret;
187
188 LOG_INF("Start complete loop");
189
190 ret = spi_transceive_dt(spec, &tx, &rx);
191 if (ret) {
192 LOG_ERR("Code %d", ret);
193 zassert_false(ret, "SPI transceive failed");
194 return ret;
195 }
196
197 if (memcmp(buffer_tx, buffer_rx, BUF_SIZE)) {
198 to_display_format(buffer_tx, BUF_SIZE, buffer_print_tx);
199 to_display_format(buffer_rx, BUF_SIZE, buffer_print_rx);
200 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
201 LOG_ERR(" vs: %s", buffer_print_rx);
202 zassert_false(1, "Buffer contents are different");
203 return -1;
204 }
205
206 LOG_INF("Passed");
207
208 return 0;
209 }
210
spi_null_tx_buf(struct spi_dt_spec * spec)211 static int spi_null_tx_buf(struct spi_dt_spec *spec)
212 {
213 static const uint8_t EXPECTED_NOP_RETURN_BUF[BUF_SIZE] = { 0 };
214
215 (void)memset(buffer_rx, 0x77, BUF_SIZE);
216
217 const struct spi_buf tx_bufs[] = {
218 /* According to documentation, when sending NULL tx buf -
219 * NOP frames should be sent on MOSI line
220 */
221 {
222 .buf = NULL,
223 .len = BUF_SIZE,
224 },
225 };
226 const struct spi_buf rx_bufs[] = {
227 {
228 .buf = buffer_rx,
229 .len = BUF_SIZE,
230 },
231 };
232 const struct spi_buf_set tx = {
233 .buffers = tx_bufs,
234 .count = ARRAY_SIZE(tx_bufs)
235 };
236 const struct spi_buf_set rx = {
237 .buffers = rx_bufs,
238 .count = ARRAY_SIZE(rx_bufs)
239 };
240
241 int ret;
242
243 LOG_INF("Start null tx");
244
245 ret = spi_transceive_dt(spec, &tx, &rx);
246 if (ret) {
247 LOG_ERR("Code %d", ret);
248 zassert_false(ret, "SPI transceive failed");
249 return ret;
250 }
251
252
253 if (memcmp(buffer_rx, EXPECTED_NOP_RETURN_BUF, BUF_SIZE)) {
254 to_display_format(buffer_rx, BUF_SIZE, buffer_print_rx);
255 LOG_ERR("Rx Buffer should contain NOP frames but got: %s",
256 buffer_print_rx);
257 zassert_false(1, "Buffer not as expected");
258 return -1;
259 }
260
261 LOG_INF("Passed");
262
263 return 0;
264 }
265
spi_rx_half_start(struct spi_dt_spec * spec)266 static int spi_rx_half_start(struct spi_dt_spec *spec)
267 {
268 const struct spi_buf tx_bufs[] = {
269 {
270 .buf = buffer_tx,
271 .len = BUF_SIZE,
272 },
273 };
274 const struct spi_buf rx_bufs[] = {
275 {
276 .buf = buffer_rx,
277 .len = 8,
278 },
279 };
280 const struct spi_buf_set tx = {
281 .buffers = tx_bufs,
282 .count = ARRAY_SIZE(tx_bufs)
283 };
284 const struct spi_buf_set rx = {
285 .buffers = rx_bufs,
286 .count = ARRAY_SIZE(rx_bufs)
287 };
288 int ret;
289
290 LOG_INF("Start half start");
291
292 (void)memset(buffer_rx, 0, BUF_SIZE);
293
294 ret = spi_transceive_dt(spec, &tx, &rx);
295 if (ret) {
296 LOG_ERR("Code %d", ret);
297 zassert_false(ret, "SPI transceive failed");
298 return -1;
299 }
300
301 if (memcmp(buffer_tx, buffer_rx, 8)) {
302 to_display_format(buffer_tx, 8, buffer_print_tx);
303 to_display_format(buffer_rx, 8, buffer_print_rx);
304 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
305 LOG_ERR(" vs: %s", buffer_print_rx);
306 zassert_false(1, "Buffer contents are different");
307 return -1;
308 }
309
310 LOG_INF("Passed");
311
312 return 0;
313 }
314
spi_rx_half_end(struct spi_dt_spec * spec)315 static int spi_rx_half_end(struct spi_dt_spec *spec)
316 {
317 const struct spi_buf tx_bufs[] = {
318 {
319 .buf = buffer_tx,
320 .len = BUF_SIZE,
321 },
322 };
323 const struct spi_buf rx_bufs[] = {
324 {
325 .buf = NULL,
326 .len = 8,
327 },
328 {
329 .buf = buffer_rx,
330 .len = 8,
331 },
332 };
333 const struct spi_buf_set tx = {
334 .buffers = tx_bufs,
335 .count = ARRAY_SIZE(tx_bufs)
336 };
337 const struct spi_buf_set rx = {
338 .buffers = rx_bufs,
339 .count = ARRAY_SIZE(rx_bufs)
340 };
341 int ret;
342
343 if (IS_ENABLED(CONFIG_SPI_STM32_DMA)) {
344 LOG_INF("Skip half end");
345 return 0;
346 }
347
348 LOG_INF("Start half end");
349
350 (void)memset(buffer_rx, 0, BUF_SIZE);
351
352 ret = spi_transceive_dt(spec, &tx, &rx);
353 if (ret) {
354 LOG_ERR("Code %d", ret);
355 zassert_false(ret, "SPI transceive failed");
356 return -1;
357 }
358
359 if (memcmp(buffer_tx + 8, buffer_rx, 8)) {
360 to_display_format(buffer_tx + 8, 8, buffer_print_tx);
361 to_display_format(buffer_rx, 8, buffer_print_rx);
362 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
363 LOG_ERR(" vs: %s", buffer_print_rx);
364 zassert_false(1, "Buffer contents are different");
365 return -1;
366 }
367
368 LOG_INF("Passed");
369
370 return 0;
371 }
372
spi_rx_every_4(struct spi_dt_spec * spec)373 static int spi_rx_every_4(struct spi_dt_spec *spec)
374 {
375 const struct spi_buf tx_bufs[] = {
376 {
377 .buf = buffer_tx,
378 .len = BUF_SIZE,
379 },
380 };
381 const struct spi_buf rx_bufs[] = {
382 {
383 .buf = NULL,
384 .len = 4,
385 },
386 {
387 .buf = buffer_rx,
388 .len = 4,
389 },
390 {
391 .buf = NULL,
392 .len = 4,
393 },
394 {
395 .buf = buffer_rx + 4,
396 .len = 4,
397 },
398 };
399 const struct spi_buf_set tx = {
400 .buffers = tx_bufs,
401 .count = ARRAY_SIZE(tx_bufs)
402 };
403 const struct spi_buf_set rx = {
404 .buffers = rx_bufs,
405 .count = ARRAY_SIZE(rx_bufs)
406 };
407 int ret;
408
409 if (IS_ENABLED(CONFIG_SPI_STM32_DMA)) {
410 LOG_INF("Skip every 4");
411 return 0;
412 }
413
414 if (IS_ENABLED(CONFIG_DSPI_MCUX_EDMA)) {
415 LOG_INF("Skip every 4");
416 return 0;
417 }
418
419 LOG_INF("Start every 4");
420
421 (void)memset(buffer_rx, 0, BUF_SIZE);
422
423 ret = spi_transceive_dt(spec, &tx, &rx);
424 if (ret) {
425 LOG_ERR("Code %d", ret);
426 zassert_false(ret, "SPI transceive failed");
427 return -1;
428 }
429
430 if (memcmp(buffer_tx + 4, buffer_rx, 4)) {
431 to_display_format(buffer_tx + 4, 4, buffer_print_tx);
432 to_display_format(buffer_rx, 4, buffer_print_rx);
433 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
434 LOG_ERR(" vs: %s", buffer_print_rx);
435 zassert_false(1, "Buffer contents are different");
436 return -1;
437 } else if (memcmp(buffer_tx + 12, buffer_rx + 4, 4)) {
438 to_display_format(buffer_tx + 12, 4, buffer_print_tx);
439 to_display_format(buffer_rx + 4, 4, buffer_print_rx);
440 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
441 LOG_ERR(" vs: %s", buffer_print_rx);
442 zassert_false(1, "Buffer contents are different");
443 return -1;
444 }
445
446 LOG_INF("Passed");
447
448 return 0;
449 }
450
spi_rx_bigger_than_tx(struct spi_dt_spec * spec)451 static int spi_rx_bigger_than_tx(struct spi_dt_spec *spec)
452 {
453 const uint32_t tx_buf_size = 8;
454
455 BUILD_ASSERT(tx_buf_size < BUF_SIZE,
456 "Transmit buffer is expected to be smaller than the receive buffer");
457
458 const struct spi_buf tx_bufs[] = {
459 {
460 .buf = buffer_tx,
461 .len = tx_buf_size,
462 },
463 };
464 const struct spi_buf rx_bufs[] = {
465 {
466 .buf = buffer_rx,
467 .len = BUF_SIZE,
468 }
469 };
470 const struct spi_buf_set tx = {
471 .buffers = tx_bufs,
472 .count = ARRAY_SIZE(tx_bufs)
473 };
474 const struct spi_buf_set rx = {
475 .buffers = rx_bufs,
476 .count = ARRAY_SIZE(rx_bufs)
477 };
478 int ret;
479
480 if (IS_ENABLED(CONFIG_SPI_STM32_DMA)) {
481 LOG_INF("Skip rx bigger than tx");
482 return 0;
483 }
484
485 if (IS_ENABLED(CONFIG_DSPI_MCUX_EDMA)) {
486 LOG_INF("Skip rx bigger than tx");
487 return 0;
488 }
489
490 LOG_INF("Start rx bigger than tx");
491
492 (void)memset(buffer_rx, 0xff, BUF_SIZE);
493
494 ret = spi_transceive_dt(spec, &tx, &rx);
495 if (ret) {
496 LOG_ERR("Code %d", ret);
497 zassert_false(ret, "SPI transceive failed");
498 return -1;
499 }
500
501 if (memcmp(buffer_tx, buffer_rx, tx_buf_size)) {
502 to_display_format(buffer_tx, tx_buf_size, buffer_print_tx);
503 to_display_format(buffer_rx, tx_buf_size, buffer_print_rx);
504 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
505 LOG_ERR(" vs: %s", buffer_print_rx);
506 zassert_false(1, "Buffer contents are different");
507 return -1;
508 }
509
510 const uint8_t all_zeroes_buf[BUF_SIZE] = {0};
511
512 if (memcmp(all_zeroes_buf, buffer_rx + tx_buf_size, BUF_SIZE - tx_buf_size)) {
513 to_display_format(
514 buffer_rx + tx_buf_size, BUF_SIZE - tx_buf_size, buffer_print_tx);
515
516 to_display_format(
517 all_zeroes_buf, BUF_SIZE - tx_buf_size, buffer_print_rx);
518
519 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
520 LOG_ERR(" vs: %s", buffer_print_rx);
521 zassert_false(1, "Buffer contents are different");
522 return -1;
523 }
524
525 LOG_INF("Passed");
526
527 return 0;
528 }
529
530 /* test transferring different buffers on the same dma channels */
spi_complete_large_transfers(struct spi_dt_spec * spec)531 static int spi_complete_large_transfers(struct spi_dt_spec *spec)
532 {
533 struct spi_buf tx_bufs;
534 const struct spi_buf_set tx = {
535 .buffers = &tx_bufs,
536 .count = 1
537 };
538
539 tx_bufs.buf = large_buffer_tx;
540 tx_bufs.len = BUF3_SIZE;
541
542
543 struct spi_buf rx_bufs;
544 const struct spi_buf_set rx = {
545 .buffers = &rx_bufs,
546 .count = 1
547 };
548
549 rx_bufs.buf = large_buffer_rx;
550 rx_bufs.len = BUF3_SIZE;
551
552 int ret;
553
554 LOG_INF("Start complete large transfers");
555
556 ret = spi_transceive_dt(spec, &tx, &rx);
557 if (ret) {
558 LOG_ERR("Code %d", ret);
559 zassert_false(ret, "SPI transceive failed");
560 return ret;
561 }
562
563 if (memcmp(large_buffer_tx, large_buffer_rx, BUF3_SIZE)) {
564 zassert_false(1, "Large Buffer contents are different");
565 return -1;
566 }
567
568 LOG_INF("Passed");
569
570 return 0;
571 }
572 #if (CONFIG_SPI_ASYNC)
573 static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig);
574 static struct k_poll_event async_evt =
575 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
576 K_POLL_MODE_NOTIFY_ONLY,
577 &async_sig);
578 static K_SEM_DEFINE(caller, 0, 1);
579 K_THREAD_STACK_DEFINE(spi_async_stack, STACK_SIZE);
580 static int result = 1;
581
spi_async_call_cb(void * p1,void * p2,void * p3)582 static void spi_async_call_cb(void *p1,
583 void *p2,
584 void *p3)
585 {
586 ARG_UNUSED(p1);
587 ARG_UNUSED(p2);
588 ARG_UNUSED(p3);
589
590 struct k_poll_event *evt = p1;
591 struct k_sem *caller_sem = p2;
592 int ret;
593
594 LOG_DBG("Polling...");
595
596 while (1) {
597 ret = k_poll(evt, 1, K_MSEC(2000));
598 zassert_false(ret, "one or more events are not ready");
599
600 result = evt->signal->result;
601 k_sem_give(caller_sem);
602
603 /* Reinitializing for next call */
604 evt->signal->signaled = 0U;
605 evt->state = K_POLL_STATE_NOT_READY;
606 }
607 }
608
spi_async_call(struct spi_dt_spec * spec)609 static int spi_async_call(struct spi_dt_spec *spec)
610 {
611 const struct spi_buf tx_bufs[] = {
612 {
613 .buf = buffer_tx,
614 .len = BUF_SIZE,
615 },
616 {
617 .buf = buffer2_tx,
618 .len = BUF2_SIZE,
619 },
620 {
621 .buf = large_buffer_tx,
622 .len = BUF3_SIZE,
623 },
624 };
625 const struct spi_buf rx_bufs[] = {
626 {
627 .buf = buffer_rx,
628 .len = BUF_SIZE,
629 },
630 {
631 .buf = buffer2_rx,
632 .len = BUF2_SIZE,
633 },
634 {
635 .buf = large_buffer_rx,
636 .len = BUF3_SIZE,
637 },
638 };
639 const struct spi_buf_set tx = {
640 .buffers = tx_bufs,
641 .count = ARRAY_SIZE(tx_bufs)
642 };
643 const struct spi_buf_set rx = {
644 .buffers = rx_bufs,
645 .count = ARRAY_SIZE(rx_bufs)
646 };
647 int ret;
648
649 LOG_INF("Start async call");
650 memset(buffer_rx, 0, sizeof(buffer_rx));
651 memset(buffer2_rx, 0, sizeof(buffer2_rx));
652 memset(large_buffer_rx, 0, sizeof(large_buffer_rx));
653
654 ret = spi_transceive_signal(spec->bus, &spec->config, &tx, &rx, &async_sig);
655 if (ret == -ENOTSUP) {
656 LOG_DBG("Not supported");
657 return 0;
658 }
659
660 if (ret) {
661 LOG_ERR("Code %d", ret);
662 zassert_false(ret, "SPI transceive failed");
663 return -1;
664 }
665
666 k_sem_take(&caller, K_FOREVER);
667
668 if (result) {
669 LOG_ERR("Call code %d", ret);
670 zassert_false(result, "SPI transceive failed");
671 return -1;
672 }
673
674 if (memcmp(buffer_tx, buffer_rx, BUF_SIZE)) {
675 to_display_format(buffer_tx, BUF_SIZE, buffer_print_tx);
676 to_display_format(buffer_rx, BUF_SIZE, buffer_print_rx);
677 LOG_ERR("Buffer contents are different: %s", buffer_print_tx);
678 LOG_ERR(" vs: %s", buffer_print_rx);
679 zassert_false(1, "Buffer contents are different");
680 return -1;
681 }
682
683 if (memcmp(buffer2_tx, buffer2_rx, BUF2_SIZE)) {
684 to_display_format(buffer2_tx, BUF2_SIZE, buffer_print_tx2);
685 to_display_format(buffer2_rx, BUF2_SIZE, buffer_print_rx2);
686 LOG_ERR("Buffer 2 contents are different: %s", buffer_print_tx2);
687 LOG_ERR(" vs: %s", buffer_print_rx2);
688 zassert_false(1, "Buffer 2 contents are different");
689 return -1;
690 }
691
692 if (memcmp(large_buffer_tx, large_buffer_rx, BUF3_SIZE)) {
693 zassert_false(1, "Buffer 3 contents are different");
694 return -1;
695 }
696
697 LOG_INF("Passed");
698
699 return 0;
700 }
701 #endif
702
spi_resource_lock_test(struct spi_dt_spec * lock_spec,struct spi_dt_spec * try_spec)703 static int spi_resource_lock_test(struct spi_dt_spec *lock_spec,
704 struct spi_dt_spec *try_spec)
705 {
706 lock_spec->config.operation |= SPI_LOCK_ON;
707
708 if (spi_complete_loop(lock_spec)) {
709 return -1;
710 }
711
712 if (spi_release_dt(lock_spec)) {
713 LOG_ERR("Deadlock now?");
714 zassert_false(1, "SPI release failed");
715 return -1;
716 }
717
718 if (spi_complete_loop(try_spec)) {
719 return -1;
720 }
721
722 return 0;
723 }
724
ZTEST(spi_loopback,test_spi_loopback)725 ZTEST(spi_loopback, test_spi_loopback)
726 {
727 #if (CONFIG_SPI_ASYNC)
728 struct k_thread async_thread;
729 k_tid_t async_thread_id;
730 #endif
731
732 LOG_INF("SPI test on buffers TX/RX %p/%p" FRAME_SIZE_STR DMA_ENABLED_STR,
733 buffer_tx,
734 buffer_rx);
735
736 #if (CONFIG_SPI_ASYNC)
737 async_thread_id = k_thread_create(&async_thread,
738 spi_async_stack, STACK_SIZE,
739 spi_async_call_cb,
740 &async_evt, &caller, NULL,
741 K_PRIO_COOP(7), 0, K_NO_WAIT);
742 #endif
743 zassert_true(spi_is_ready_dt(&spi_slow), "Slow spi lookback device is not ready");
744
745 LOG_INF("SPI test slow config");
746
747 if (spi_complete_multiple(&spi_slow) ||
748 spi_complete_loop(&spi_slow) ||
749 spi_null_tx_buf(&spi_slow) ||
750 spi_rx_half_start(&spi_slow) ||
751 spi_rx_half_end(&spi_slow) ||
752 spi_rx_every_4(&spi_slow) ||
753 spi_rx_bigger_than_tx(&spi_slow) ||
754 spi_complete_large_transfers(&spi_slow)
755 #if (CONFIG_SPI_ASYNC)
756 || spi_async_call(&spi_slow)
757 #endif
758 ) {
759 goto end;
760 }
761
762 zassert_true(spi_is_ready_dt(&spi_fast), "Fast spi lookback device is not ready");
763
764 LOG_INF("SPI test fast config");
765
766 if (spi_complete_multiple(&spi_fast) ||
767 spi_complete_loop(&spi_fast) ||
768 spi_null_tx_buf(&spi_fast) ||
769 spi_rx_half_start(&spi_fast) ||
770 spi_rx_half_end(&spi_fast) ||
771 spi_rx_every_4(&spi_fast) ||
772 spi_rx_bigger_than_tx(&spi_fast) ||
773 spi_complete_large_transfers(&spi_fast)
774 #if (CONFIG_SPI_ASYNC)
775 || spi_async_call(&spi_fast)
776 #endif
777 ) {
778 goto end;
779 }
780
781 if (spi_resource_lock_test(&spi_slow, &spi_fast)) {
782 goto end;
783 }
784
785 LOG_INF("All tx/rx passed");
786 end:
787 #if (CONFIG_SPI_ASYNC)
788 k_thread_abort(async_thread_id);
789 #else
790 ;
791 #endif
792 }
793
spi_loopback_setup(void)794 static void *spi_loopback_setup(void)
795 {
796 memset(buffer_tx, 0, sizeof(buffer_tx));
797 memcpy(buffer_tx, tx_data, sizeof(tx_data));
798 memset(buffer2_tx, 0, sizeof(buffer2_tx));
799 memcpy(buffer2_tx, tx2_data, sizeof(tx2_data));
800 memset(large_buffer_tx, 0, sizeof(large_buffer_tx));
801 memcpy(large_buffer_tx, large_tx_data, sizeof(large_tx_data));
802 return NULL;
803 }
804
805 ZTEST_SUITE(spi_loopback, NULL, spi_loopback_setup, NULL, NULL, NULL);
806