xref: /openbmc/linux/sound/soc/soc-utils-test.c (revision e32e23a2)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2022 Cirrus Logic, Inc. and
3 //                    Cirrus Logic International Semiconductor Ltd.
4 
5 #include <kunit/test.h>
6 #include <linux/module.h>
7 #include <sound/pcm.h>
8 #include <sound/pcm_params.h>
9 #include <sound/soc.h>
10 #include <uapi/sound/asound.h>
11 
12 static const struct {
13 	u32 rate;
14 	snd_pcm_format_t fmt;
15 	u8 channels;
16 	u8 tdm_width;
17 	u8 tdm_slots;
18 	u8 slot_multiple;
19 	u32 bclk;
20 } tdm_params_to_bclk_cases[] = {
21 	/* rate		fmt	   channels tdm_width tdm_slots slot_multiple bclk */
22 
23 	/* From params only */
24 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	0,	  128000 },
25 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	0,	  256000 },
26 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	0,	  192000 },
27 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	0,	  384000 },
28 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	0,	  256000 },
29 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	0,	  512000 },
30 	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	0,	  705600 },
31 	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	0,	 1411200 },
32 	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	0,	 1058400 },
33 	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	0,	 2116800 },
34 	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	0,	 1411200 },
35 	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	0,	 2822400 },
36 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	0,	 6144000 },
37 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	0,	12288000 },
38 	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	0,	 9216000 },
39 	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	0,	18432000 },
40 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	0,	12288000 },
41 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	0,	24576000 },
42 
43 	/* I2S from params */
44 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	2,	  256000 },
45 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	2,	  256000 },
46 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	2,	  384000 },
47 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	2,	  384000 },
48 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	2,	  512000 },
49 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	2,	  512000 },
50 	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	2,	 1411200 },
51 	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	2,	 1411200 },
52 	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	2,	 2116800 },
53 	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	2,	 2116800 },
54 	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	2,	 2822400 },
55 	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	2,	 2822400 },
56 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	2,	12288000 },
57 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	2,	12288000 },
58 	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	2,	18432000 },
59 	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	2,	18432000 },
60 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	2,	24576000 },
61 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	2,	24576000 },
62 
63 	/* Fixed 8-slot TDM, other values from params */
64 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	8,	0,	 1024000 },
65 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	8,	0,	 1024000 },
66 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 3,	0,	8,	0,	 1024000 },
67 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 4,	0,	8,	0,	 1024000 },
68 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	8,	0,	 2048000 },
69 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	8,	0,	 2048000 },
70 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 3,	0,	8,	0,	 2048000 },
71 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 4,	0,	8,	0,	 2048000 },
72 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	8,	0,	49152000 },
73 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	8,	0,	49152000 },
74 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 3,	0,	8,	0,	49152000 },
75 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 4,	0,	8,	0,	49152000 },
76 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	8,	0,	98304000 },
77 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	8,	0,	98304000 },
78 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 3,	0,	8,	0,	98304000 },
79 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 4,	0,	8,	0,	98304000 },
80 
81 	/* Fixed 32-bit TDM, other values from params */
82 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	32,	0,	0,	  256000 },
83 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	32,	0,	0,	  512000 },
84 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 3,	32,	0,	0,	  768000 },
85 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 4,	32,	0,	0,	 1024000 },
86 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	32,	0,	0,	  256000 },
87 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	32,	0,	0,	  512000 },
88 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 3,	32,	0,	0,	  768000 },
89 	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 4,	32,	0,	0,	 1024000 },
90 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	32,	0,	0,	12288000 },
91 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	32,	0,	0,	24576000 },
92 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 3,	32,	0,	0,	36864000 },
93 	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 4,	32,	0,	0,	49152000 },
94 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	32,	0,	0,	12288000 },
95 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	32,	0,	0,	24576000 },
96 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 3,	32,	0,	0,	36864000 },
97 	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 4,	32,	0,	0,	49152000 },
98 
99 	/* Fixed 6-slot 24-bit TDM, other values from params */
100 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	24,	6,	0,	 1152000 },
101 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	24,	6,	0,	 1152000 },
102 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 3,	24,	6,	0,	 1152000 },
103 	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 4,	24,	6,	0,	 1152000 },
104 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 1,	24,	6,	0,	 1152000 },
105 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 2,	24,	6,	0,	 1152000 },
106 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 3,	24,	6,	0,	 1152000 },
107 	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 4,	24,	6,	0,	 1152000 },
108 	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 1,	24,	6,	0,	27648000 },
109 	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 2,	24,	6,	0,	27648000 },
110 	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 3,	24,	6,	0,	27648000 },
111 	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 4,	24,	6,	0,	27648000 },
112 	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 1,	24,	6,	0,	27648000 },
113 	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 2,	24,	6,	0,	27648000 },
114 	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 3,	24,	6,	0,	27648000 },
115 	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 4,	24,	6,	0,	27648000 },
116 };
117 
test_tdm_params_to_bclk_one(struct kunit * test,unsigned int rate,snd_pcm_format_t fmt,unsigned int channels,unsigned int tdm_width,unsigned int tdm_slots,unsigned int slot_multiple,unsigned int expected_bclk)118 static void test_tdm_params_to_bclk_one(struct kunit *test,
119 					unsigned int rate, snd_pcm_format_t fmt,
120 					unsigned int channels,
121 					unsigned int tdm_width, unsigned int tdm_slots,
122 					unsigned int slot_multiple,
123 					unsigned int expected_bclk)
124 {
125 	struct snd_pcm_hw_params params;
126 	int got_bclk;
127 
128 	_snd_pcm_hw_params_any(&params);
129 	snd_mask_none(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT));
130 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->min = rate;
131 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->max = rate;
132 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = channels;
133 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = channels;
134 	params_set_format(&params, fmt);
135 
136 	got_bclk = snd_soc_tdm_params_to_bclk(&params, tdm_width, tdm_slots, slot_multiple);
137 	pr_debug("%s: r=%u sb=%u ch=%u tw=%u ts=%u sm=%u expected=%u got=%d\n",
138 		 __func__,
139 		 rate, params_width(&params), channels, tdm_width, tdm_slots, slot_multiple,
140 		 expected_bclk, got_bclk);
141 	KUNIT_ASSERT_EQ(test, expected_bclk, (unsigned int)got_bclk);
142 }
143 
test_tdm_params_to_bclk(struct kunit * test)144 static void test_tdm_params_to_bclk(struct kunit *test)
145 {
146 	int i;
147 
148 	for (i = 0; i < ARRAY_SIZE(tdm_params_to_bclk_cases); ++i) {
149 		test_tdm_params_to_bclk_one(test,
150 					    tdm_params_to_bclk_cases[i].rate,
151 					    tdm_params_to_bclk_cases[i].fmt,
152 					    tdm_params_to_bclk_cases[i].channels,
153 					    tdm_params_to_bclk_cases[i].tdm_width,
154 					    tdm_params_to_bclk_cases[i].tdm_slots,
155 					    tdm_params_to_bclk_cases[i].slot_multiple,
156 					    tdm_params_to_bclk_cases[i].bclk);
157 
158 		if (tdm_params_to_bclk_cases[i].slot_multiple > 0)
159 			continue;
160 
161 		/* Slot multiple 1 should have the same effect as multiple 0 */
162 		test_tdm_params_to_bclk_one(test,
163 					    tdm_params_to_bclk_cases[i].rate,
164 					    tdm_params_to_bclk_cases[i].fmt,
165 					    tdm_params_to_bclk_cases[i].channels,
166 					    tdm_params_to_bclk_cases[i].tdm_width,
167 					    tdm_params_to_bclk_cases[i].tdm_slots,
168 					    1,
169 					    tdm_params_to_bclk_cases[i].bclk);
170 	}
171 }
172 
test_snd_soc_params_to_bclk_one(struct kunit * test,unsigned int rate,snd_pcm_format_t fmt,unsigned int channels,unsigned int expected_bclk)173 static void test_snd_soc_params_to_bclk_one(struct kunit *test,
174 					    unsigned int rate, snd_pcm_format_t fmt,
175 					    unsigned int channels,
176 					    unsigned int expected_bclk)
177 {
178 	struct snd_pcm_hw_params params;
179 	int got_bclk;
180 
181 	_snd_pcm_hw_params_any(&params);
182 	snd_mask_none(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT));
183 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->min = rate;
184 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->max = rate;
185 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = channels;
186 	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = channels;
187 	params_set_format(&params, fmt);
188 
189 	got_bclk = snd_soc_params_to_bclk(&params);
190 	pr_debug("%s: r=%u sb=%u ch=%u expected=%u got=%d\n",
191 		 __func__,
192 		 rate, params_width(&params), channels, expected_bclk, got_bclk);
193 	KUNIT_ASSERT_EQ(test, expected_bclk, (unsigned int)got_bclk);
194 }
195 
test_snd_soc_params_to_bclk(struct kunit * test)196 static void test_snd_soc_params_to_bclk(struct kunit *test)
197 {
198 	int i;
199 
200 	for (i = 0; i < ARRAY_SIZE(tdm_params_to_bclk_cases); ++i) {
201 		/*
202 		 * snd_soc_params_to_bclk() is all the test cases where
203 		 * snd_pcm_hw_params values are not overridden.
204 		 */
205 		if (tdm_params_to_bclk_cases[i].tdm_width |
206 		    tdm_params_to_bclk_cases[i].tdm_slots |
207 		    tdm_params_to_bclk_cases[i].slot_multiple)
208 			continue;
209 
210 		test_snd_soc_params_to_bclk_one(test,
211 						tdm_params_to_bclk_cases[i].rate,
212 						tdm_params_to_bclk_cases[i].fmt,
213 						tdm_params_to_bclk_cases[i].channels,
214 						tdm_params_to_bclk_cases[i].bclk);
215 	}
216 }
217 
218 static struct kunit_case soc_utils_test_cases[] = {
219 	KUNIT_CASE(test_tdm_params_to_bclk),
220 	KUNIT_CASE(test_snd_soc_params_to_bclk),
221 	{}
222 };
223 
224 static struct kunit_suite soc_utils_test_suite = {
225 	.name = "soc-utils",
226 	.test_cases = soc_utils_test_cases,
227 };
228 
229 kunit_test_suites(&soc_utils_test_suite);
230 
231 MODULE_DESCRIPTION("ASoC soc-utils kunit test");
232 MODULE_LICENSE("GPL");
233