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