1 /*
2  * Copyright (c) 2017 comsuisse AG
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/drivers/i2s.h>
10 #include "i2s_api_test.h"
11 
12 K_MEM_SLAB_DEFINE(rx_mem_slab, BLOCK_SIZE, NUM_RX_BLOCKS, 32);
13 K_MEM_SLAB_DEFINE(tx_mem_slab, BLOCK_SIZE, NUM_TX_BLOCKS, 32);
14 
15 /* The data_l represent a sine wave */
16 ZTEST_DMEM int16_t data_l[SAMPLE_NO] = {
17 	  6392,  12539,  18204,  23169,  27244,  30272,  32137,  32767,  32137,
18 	 30272,  27244,  23169,  18204,  12539,   6392,      0,  -6393, -12540,
19 	-18205, -23170, -27245, -30273, -32138, -32767, -32138, -30273, -27245,
20 	-23170, -18205, -12540,  -6393,     -1,
21 };
22 
23 /* The data_r represent a sine wave with double the frequency of data_l */
24 ZTEST_DMEM int16_t data_r[SAMPLE_NO] = {
25 	 12539,  23169,  30272,  32767,  30272,  23169,  12539,      0, -12540,
26 	-23170, -30273, -32767, -30273, -23170, -12540,     -1,  12539,  23169,
27 	 30272,  32767,  30272,  23169,  12539,      0, -12540, -23170, -30273,
28 	-32767, -30273, -23170, -12540,     -1,
29 };
30 
fill_buf(int16_t * tx_block,int att)31 static void fill_buf(int16_t *tx_block, int att)
32 {
33 	for (int i = 0; i < SAMPLE_NO; i++) {
34 		tx_block[2 * i] = data_l[i] >> att;
35 		tx_block[2 * i + 1] = data_r[i] >> att;
36 	}
37 }
38 
verify_buf(int16_t * rx_block,int att)39 static int verify_buf(int16_t *rx_block, int att)
40 {
41 	int sample_no = SAMPLE_NO;
42 
43 #if (CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET > 0)
44 	static ZTEST_DMEM int offset = -1;
45 
46 	if (offset < 0) {
47 		do {
48 			++offset;
49 			if (offset > CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET) {
50 				TC_PRINT("Allowed data offset exceeded\n");
51 				return -TC_FAIL;
52 			}
53 		} while (rx_block[2 * offset] != data_l[0] >> att);
54 
55 		TC_PRINT("Using data offset: %d\n", offset);
56 	}
57 
58 	rx_block += 2 * offset;
59 	sample_no -= offset;
60 #endif
61 
62 	for (int i = 0; i < sample_no; i++) {
63 		if (rx_block[2 * i] != data_l[i] >> att) {
64 			TC_PRINT("Error: att %d: data_l mismatch at position "
65 				 "%d, expected %d, actual %d\n",
66 				 att, i, data_l[i] >> att, rx_block[2 * i]);
67 			return -TC_FAIL;
68 		}
69 		if (rx_block[2 * i + 1] != data_r[i] >> att) {
70 			TC_PRINT("Error: att %d: data_r mismatch at position "
71 				 "%d, expected %d, actual %d\n",
72 				 att, i, data_r[i] >> att, rx_block[2 * i + 1]);
73 			return -TC_FAIL;
74 		}
75 	}
76 
77 	return TC_PASS;
78 }
79 
fill_buf_const(int16_t * tx_block,int16_t val_l,int16_t val_r)80 void fill_buf_const(int16_t *tx_block, int16_t val_l, int16_t val_r)
81 {
82 	for (int i = 0; i < SAMPLE_NO; i++) {
83 		tx_block[2 * i] = val_l;
84 		tx_block[2 * i + 1] = val_r;
85 	}
86 }
87 
verify_buf_const(int16_t * rx_block,int16_t val_l,int16_t val_r)88 int verify_buf_const(int16_t *rx_block, int16_t val_l, int16_t val_r)
89 {
90 	for (int i = 0; i < SAMPLE_NO; i++) {
91 		if (rx_block[2 * i] != val_l) {
92 			TC_PRINT("Error: data_l mismatch at position "
93 				 "%d, expected %d, actual %d\n",
94 				 i, val_l, rx_block[2 * i]);
95 			return -TC_FAIL;
96 		}
97 		if (rx_block[2 * i + 1] != val_r) {
98 			TC_PRINT("Error: data_r mismatch at position "
99 				 "%d, expected %d, actual %d\n",
100 				 i, val_r, rx_block[2 * i + 1]);
101 			return -TC_FAIL;
102 		}
103 	}
104 
105 	return TC_PASS;
106 }
107 
tx_block_write_slab(const struct device * dev_i2s,int att,int err,struct k_mem_slab * slab)108 static int tx_block_write_slab(const struct device *dev_i2s, int att, int err,
109 			       struct k_mem_slab *slab)
110 {
111 	char tx_block[BLOCK_SIZE];
112 	int ret;
113 
114 	fill_buf((uint16_t *)tx_block, att);
115 	ret = i2s_buf_write(dev_i2s, tx_block, BLOCK_SIZE);
116 	if (ret != err) {
117 		TC_PRINT("Error: i2s_write failed expected %d, actual %d\n",
118 			 err, ret);
119 		return -TC_FAIL;
120 	}
121 
122 	return TC_PASS;
123 }
124 
tx_block_write(const struct device * dev_i2s,int att,int err)125 int tx_block_write(const struct device *dev_i2s, int att, int err)
126 {
127 	return tx_block_write_slab(dev_i2s, att, err, &tx_mem_slab);
128 }
129 
rx_block_read_slab(const struct device * dev_i2s,int att,struct k_mem_slab * slab)130 static int rx_block_read_slab(const struct device *dev_i2s, int att,
131 			      struct k_mem_slab *slab)
132 {
133 	char rx_block[BLOCK_SIZE];
134 	size_t rx_size;
135 	int ret;
136 
137 	ret = i2s_buf_read(dev_i2s, rx_block, &rx_size);
138 	if (ret < 0 || rx_size != BLOCK_SIZE) {
139 		TC_PRINT("Error: Read failed\n");
140 		return -TC_FAIL;
141 	}
142 	ret = verify_buf((uint16_t *)rx_block, att);
143 	if (ret < 0) {
144 		TC_PRINT("Error: Verify failed\n");
145 		return -TC_FAIL;
146 	}
147 
148 	return TC_PASS;
149 }
150 
rx_block_read(const struct device * dev_i2s,int att)151 int rx_block_read(const struct device *dev_i2s, int att)
152 {
153 	return rx_block_read_slab(dev_i2s, att, &rx_mem_slab);
154 }
155 
configure_stream(const struct device * dev_i2s,enum i2s_dir dir)156 int configure_stream(const struct device *dev_i2s, enum i2s_dir dir)
157 {
158 	int ret;
159 	struct i2s_config i2s_cfg;
160 
161 	i2s_cfg.word_size = 16U;
162 	i2s_cfg.channels = 2U;
163 	i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
164 	i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ;
165 	i2s_cfg.block_size = BLOCK_SIZE;
166 	i2s_cfg.timeout = TIMEOUT;
167 
168 	if (dir == I2S_DIR_TX) {
169 		/* Configure the Transmit port as Master */
170 		i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER
171 				| I2S_OPT_BIT_CLK_MASTER;
172 	} else if (dir == I2S_DIR_RX) {
173 		/* Configure the Receive port as Slave */
174 		i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE
175 				| I2S_OPT_BIT_CLK_SLAVE;
176 	} else { /* dir == I2S_DIR_BOTH */
177 		i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER
178 				| I2S_OPT_BIT_CLK_MASTER;
179 	}
180 
181 	if (!IS_ENABLED(CONFIG_I2S_TEST_USE_GPIO_LOOPBACK)) {
182 		i2s_cfg.options |= I2S_OPT_LOOPBACK;
183 	}
184 
185 	if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) {
186 		i2s_cfg.mem_slab = &tx_mem_slab;
187 		ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
188 		if (ret < 0) {
189 			TC_PRINT("Failed to configure I2S TX stream (%d)\n",
190 				 ret);
191 			return -TC_FAIL;
192 		}
193 	}
194 
195 	if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) {
196 		i2s_cfg.mem_slab = &rx_mem_slab;
197 		ret = i2s_configure(dev_i2s, I2S_DIR_RX, &i2s_cfg);
198 		if (ret < 0) {
199 			TC_PRINT("Failed to configure I2S RX stream (%d)\n",
200 				 ret);
201 			return -TC_FAIL;
202 		}
203 	}
204 
205 	return TC_PASS;
206 }
207