1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2025 Cirrus Logic, Inc. and
3 //                    Cirrus Logic International Semiconductor Ltd.
4 
5 #include <kunit/device.h>
6 #include <kunit/test.h>
7 #include <linux/module.h>
8 #include <linux/regmap.h>
9 #include <linux/string.h>
10 #include <sound/asound.h>
11 #include <sound/control.h>
12 #include <sound/soc.h>
13 #include <sound/soc-component.h>
14 
15 enum soc_ops_test_control_layout {
16 	SOC_OPS_TEST_SINGLE,
17 	SOC_OPS_TEST_DOUBLE,
18 	SOC_OPS_TEST_DOUBLE_R,
19 };
20 
21 #define TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert) \
22 	.mc = { \
23 		.min = xmin, .max = xmax, .platform_max = xpmax, \
24 		.reg = 0, .shift = 0, .sign_bit = xsign, .invert = xinvert, \
25 		.rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? 1 : 0, \
26 		.rshift = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? 16 : 0, \
27 	}
28 
29 #define TEST_UINFO(clayout, ctype, cmin, cmax) \
30 	.uinfo = { \
31 		.type = SNDRV_CTL_ELEM_TYPE_##ctype, \
32 		.count = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_SINGLE ? 1 : 2, \
33 		.value.integer.min = cmin, \
34 		.value.integer.max = cmax, \
35 	}
36 
37 #define ITEST(cname, clayout, ctype, cfunc, cmin, cmax, \
38 	      xmin, xmax, xpmax, xsign, xinvert) \
39 	{ \
40 		.name = cname, \
41 		.func_name = #cfunc, \
42 		.layout = SOC_OPS_TEST_##clayout, \
43 		.info = snd_soc_info_##cfunc, \
44 		TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \
45 		TEST_UINFO(clayout, ctype, cmin, cmax), \
46 	}
47 
48 #define ATEST(clayout, cfunc, cctl, cret, cinit, \
49 	      xmask, xreg, xmin, xmax, xpmax, xsign, xinvert) \
50 	{ \
51 		.func_name = #cfunc, \
52 		.layout = SOC_OPS_TEST_##clayout, \
53 		.put = snd_soc_put_##cfunc, \
54 		.get = snd_soc_get_##cfunc, \
55 		TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \
56 		.lctl = cctl, .rctl = cctl, \
57 		.lmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \
58 				(xmask) | (xmask) << 16 : (xmask), \
59 		.rmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xmask) : 0, \
60 		.init = cinit ? 0xFFFFFFFF : 0x00000000, \
61 		.lreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \
62 				(xreg) | (xreg) << 16 : (xreg), \
63 		.rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xreg) : 0, \
64 		.ret = cret, \
65 	}
66 
67 struct soc_ops_test_priv {
68 	struct kunit *test;
69 
70 	struct snd_soc_component component;
71 };
72 
73 struct info_test_param {
74 	const char * const name;
75 	const char * const func_name;
76 	enum soc_ops_test_control_layout layout;
77 	struct soc_mixer_control mc;
78 	int (*info)(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info);
79 
80 	struct snd_ctl_elem_info uinfo;
81 };
82 
83 struct access_test_param {
84 	const char * const func_name;
85 	enum soc_ops_test_control_layout layout;
86 	struct soc_mixer_control mc;
87 	int (*put)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value);
88 	int (*get)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value);
89 
90 	unsigned int init;
91 	unsigned int lmask;
92 	unsigned int rmask;
93 	unsigned int lreg;
94 	unsigned int rreg;
95 	long lctl;
96 	long rctl;
97 	int ret;
98 };
99 
100 static const struct info_test_param all_info_test_params[] = {
101 	// Handling of volume control name for types
102 	ITEST("Test Control",        SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
103 	ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 0),
104 	ITEST("Test Volume Control", SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
105 	ITEST("Test Control",        DOUBLE_R, BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
106 	ITEST("Test Volume",         DOUBLE_R, INTEGER, volsw,    0,  1,   0,  1,  0, 0, 0),
107 	ITEST("Test Volume Control", DOUBLE_R, BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
108 	ITEST("Test Control",        DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
109 	ITEST("Test Volume",         DOUBLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 0),
110 	ITEST("Test Volume Control", DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
111 	ITEST("Test Control",        SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
112 	ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 1),
113 	ITEST("Test Volume Control", SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
114 	ITEST("Test Control",        DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
115 	ITEST("Test Volume",         DOUBLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 1),
116 	ITEST("Test Volume Control", DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
117 	ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0,  2,   0,  2,  0, 0, 0),
118 	ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  2,   0,  2,  0, 0, 0),
119 	ITEST("Test Volume Control", SINGLE,   INTEGER, volsw,    0,  2,   0,  2,  0, 0, 0),
120 	ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0,  1,   0,  2,  1, 0, 0),
121 	ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  1,   0,  2,  1, 0, 0),
122 	ITEST("Test Volume Control", SINGLE,   INTEGER, volsw,    0,  1,   0,  2,  1, 0, 0),
123 	// Negative minimums
124 	ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 20, -10, 10,  0, 4, 0),
125 	ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 15, -10, 10, 15, 4, 0),
126 	ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 20, -10, 10,  0, 4, 1),
127 	ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 15, -10, 10, 15, 4, 1),
128 	// SX control volume control naming
129 	ITEST("Test Control",        SINGLE,   BOOLEAN, volsw_sx, 0,  1, 0xF,  1,  0, 0, 0),
130 	ITEST("Test Volume",         SINGLE,   INTEGER, volsw_sx, 0,  1, 0xF,  1,  0, 0, 0),
131 	ITEST("Test Volume Control", SINGLE,   BOOLEAN, volsw_sx, 0,  1, 0xF,  1,  0, 0, 0),
132 	ITEST("Test Control",        SINGLE,   INTEGER, volsw_sx, 0,  4, 0xE,  4,  0, 0, 0),
133 	ITEST("Test Volume",         SINGLE,   INTEGER, volsw_sx, 0,  4, 0xE,  4,  0, 0, 0),
134 	ITEST("Test Volume Control", SINGLE,   INTEGER, volsw_sx, 0,  4, 0xE,  4,  0, 0, 0),
135 	ITEST("Test Control",        SINGLE,   INTEGER, volsw_sx, 0,  3, 0xE,  4,  3, 0, 0),
136 	ITEST("Test Volume",         SINGLE,   INTEGER, volsw_sx, 0,  3, 0xE,  4,  3, 0, 0),
137 	ITEST("Test Volume Control", SINGLE,   INTEGER, volsw_sx, 0,  3, 0xE,  4,  3, 0, 0),
138 };
139 
140 static const struct access_test_param all_access_test_params[] = {
141 	// Single positive value controls
142 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 0),
143 	ATEST(SINGLE,   volsw,      0,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 0),
144 	ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 0),
145 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 0),
146 	ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 0),
147 	ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x0F,    0,  20, 15, 0, 0),
148 	// Inverted single positive value controls
149 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 1),
150 	ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 1),
151 	ATEST(SINGLE,   volsw,     20,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 1),
152 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 1),
153 	ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 1),
154 	ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x05,    0,  20, 15, 0, 1),
155 	ATEST(SINGLE,   volsw,     10,   1, true,  0x1F, 0x0A,    0,  20,  0, 0, 0),
156 	ATEST(SINGLE,   volsw,      0,   1, true,  0x1F, 0x00,    0,  20,  0, 0, 0),
157 	ATEST(SINGLE,   volsw,     20,   1, true,  0x1F, 0x14,    0,  20,  0, 0, 0),
158 	ATEST(SINGLE,   volsw,     10,   1, true,  0x1F, 0x0A,    0,  20, 15, 0, 0),
159 	ATEST(SINGLE,   volsw,     25, -22, true,  0x1F, 0x00,    0,  20, 15, 0, 0),
160 	ATEST(SINGLE,   volsw,     15,   1, true,  0x1F, 0x0F,    0,  20, 15, 0, 0),
161 	// Single negative value controls
162 	ATEST(SINGLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 0),
163 	ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 0),
164 	ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 0),
165 	ATEST(SINGLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
166 	ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
167 	ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x05,  -10,  10, 15, 4, 0),
168 	// Single non-zero minimum positive value controls
169 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 0),
170 	ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 0),
171 	ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 0),
172 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 0),
173 	ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 0),
174 	ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x19,   10,  30, 15, 0, 0),
175 	// Inverted single non-zero minimum positive value controls
176 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 1),
177 	ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 1),
178 	ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 1),
179 	ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 1),
180 	ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 1),
181 	ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x0F,   10,  30, 15, 0, 1),
182 	// Double register positive value controls
183 	ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 0),
184 	ATEST(DOUBLE_R, volsw,      0,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 0),
185 	ATEST(DOUBLE_R, volsw,     20,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 0),
186 	ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 0),
187 	ATEST(DOUBLE_R, volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 0),
188 	ATEST(DOUBLE_R, volsw,     15,   1, false, 0x1F, 0x0F,    0,  20, 15, 0, 0),
189 	// Double register negative value controls
190 	ATEST(DOUBLE_R, volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 0),
191 	ATEST(DOUBLE_R, volsw,      0,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 0),
192 	ATEST(DOUBLE_R, volsw,     20,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 0),
193 	ATEST(DOUBLE_R, volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
194 	ATEST(DOUBLE_R, volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
195 	ATEST(DOUBLE_R, volsw,     15,   1, false, 0x1F, 0x05,  -10,  10, 15, 4, 0),
196 	ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10,  0, 4, 0),
197 	ATEST(DOUBLE_R, volsw,      0,   1, true,  0x1F, 0x16,  -10,  10,  0, 4, 0),
198 	ATEST(DOUBLE_R, volsw,     20,   1, true,  0x1F, 0x0A,  -10,  10,  0, 4, 0),
199 	ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10, 15, 4, 0),
200 	ATEST(DOUBLE_R, volsw,     25, -22, true,  0x1F, 0x00,  -10,  10, 15, 4, 0),
201 	ATEST(DOUBLE_R, volsw,     15,   1, true,  0x1F, 0x05,  -10,  10, 15, 4, 0),
202 	// Inverted double register negative value controls
203 	ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10,  0, 4, 1),
204 	ATEST(DOUBLE_R, volsw,      0,   1, true,  0x1F, 0x0A,  -10,  10,  0, 4, 1),
205 	ATEST(DOUBLE_R, volsw,     20,   1, true,  0x1F, 0x16,  -10,  10,  0, 4, 1),
206 	ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10, 15, 4, 1),
207 	ATEST(DOUBLE_R, volsw,     25, -22, true,  0x1F, 0x00,  -10,  10, 15, 4, 1),
208 	ATEST(DOUBLE_R, volsw,     15,   1, true,  0x1F, 0x1B,  -10,  10, 15, 4, 1),
209 	// Double register non-zero minimum positive value controls
210 	ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 0),
211 	ATEST(DOUBLE_R, volsw,      0,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 0),
212 	ATEST(DOUBLE_R, volsw,     20,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 0),
213 	ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 0),
214 	ATEST(DOUBLE_R, volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 0),
215 	ATEST(DOUBLE_R, volsw,     15,   1, false, 0x1F, 0x19,   10,  30, 15, 0, 0),
216 	// Double shift positive value controls
217 	ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 0),
218 	ATEST(DOUBLE,   volsw,      0,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 0),
219 	ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 0),
220 	ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 0),
221 	ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 0),
222 	ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x0F,    0,  20, 15, 0, 0),
223 	// Double shift negative value controls
224 	ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 0),
225 	ATEST(DOUBLE,   volsw,      0,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 0),
226 	ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 0),
227 	ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
228 	ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
229 	ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x05,  -10,  10, 15, 4, 0),
230 	// Inverted double shift negative value controls
231 	ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 1),
232 	ATEST(DOUBLE,   volsw,      0,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 1),
233 	ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 1),
234 	ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 1),
235 	ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 1),
236 	ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x1B,  -10,  10, 15, 4, 1),
237 	// Double shift non-zero minimum positive value controls
238 	ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 0),
239 	ATEST(DOUBLE,   volsw,      0,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 0),
240 	ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 0),
241 	ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 0),
242 	ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 0),
243 	ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x19,   10,  30, 15, 0, 0),
244 	ATEST(DOUBLE,   volsw,     10,   1, true,  0x1F, 0x14,   10,  30,  0, 0, 0),
245 	ATEST(DOUBLE,   volsw,      0,   1, true,  0x1F, 0x0A,   10,  30,  0, 0, 0),
246 	ATEST(DOUBLE,   volsw,     20,   1, true,  0x1F, 0x1E,   10,  30,  0, 0, 0),
247 	ATEST(DOUBLE,   volsw,     10,   1, true,  0x1F, 0x14,   10,  30, 15, 0, 0),
248 	ATEST(DOUBLE,   volsw,     25, -22, true,  0x1F, 0x00,   10,  30, 15, 0, 0),
249 	ATEST(DOUBLE,   volsw,     15,   1, true,  0x1F, 0x19,   10,  30, 15, 0, 0),
250 	// Single SX all values
251 	ATEST(SINGLE,   volsw_sx,   0,   1, false,  0xF, 0x0F, 0x0F,   4,  0, 0, 0),
252 	ATEST(SINGLE,   volsw_sx,   1,   0, false,  0xF, 0x00, 0x0F,   4,  0, 0, 0),
253 	ATEST(SINGLE,   volsw_sx,   2,   1, false,  0xF, 0x01, 0x0F,   4,  0, 0, 0),
254 	ATEST(SINGLE,   volsw_sx,   3,   1, false,  0xF, 0x02, 0x0F,   4,  0, 0, 0),
255 	ATEST(SINGLE,   volsw_sx,   4,   1, false,  0xF, 0x03, 0x0F,   4,  0, 0, 0),
256 	ATEST(SINGLE,   volsw_sx,   5, -22, false,  0xF, 0x00, 0x0F,   4,  0, 0, 0),
257 	ATEST(SINGLE,   volsw_sx,   0,   0, true,   0xF, 0x0F, 0x0F,   4,  0, 0, 0),
258 	ATEST(SINGLE,   volsw_sx,   1,   1, true,   0xF, 0x00, 0x0F,   4,  0, 0, 0),
259 	ATEST(SINGLE,   volsw_sx,   2,   1, true,   0xF, 0x01, 0x0F,   4,  0, 0, 0),
260 	ATEST(SINGLE,   volsw_sx,   3,   1, true,   0xF, 0x02, 0x0F,   4,  0, 0, 0),
261 	ATEST(SINGLE,   volsw_sx,   4,   1, true,   0xF, 0x03, 0x0F,   4,  0, 0, 0),
262 	ATEST(SINGLE,   volsw_sx,   5, -22, true,   0xF, 0x00, 0x0F,   4,  0, 0, 0),
263 	// Inverted single SX all values
264 	ATEST(SINGLE,   volsw_sx,   0,   1, false, 0x1F, 0x03, 0x0F,   4,  0, 0, 1),
265 	ATEST(SINGLE,   volsw_sx,   1,   1, false, 0x1F, 0x02, 0x0F,   4,  0, 0, 1),
266 	ATEST(SINGLE,   volsw_sx,   2,   1, false, 0x1F, 0x01, 0x0F,   4,  0, 0, 1),
267 	ATEST(SINGLE,   volsw_sx,   3,   0, false, 0x1F, 0x00, 0x0F,   4,  0, 0, 1),
268 	ATEST(SINGLE,   volsw_sx,   4,   1, false, 0x1F, 0x0F, 0x0F,   4,  0, 0, 1),
269 	ATEST(SINGLE,   volsw_sx,   5, -22, false, 0x1F, 0x00, 0x0F,   4,  0, 0, 1),
270 	// Single SX select values
271 	ATEST(SINGLE,   volsw_sx,   0,   1, false, 0xFF, 0x88, 0x88, 144,  0, 0, 0),
272 	ATEST(SINGLE,   volsw_sx,   1,   1, false, 0xFF, 0x89, 0x88, 144,  0, 0, 0),
273 	ATEST(SINGLE,   volsw_sx, 119,   1, false, 0xFF, 0xFF, 0x88, 144,  0, 0, 0),
274 	ATEST(SINGLE,   volsw_sx, 120,   0, false, 0xFF, 0x00, 0x88, 144,  0, 0, 0),
275 	ATEST(SINGLE,   volsw_sx, 121,   1, false, 0xFF, 0x01, 0x88, 144,  0, 0, 0),
276 	ATEST(SINGLE,   volsw_sx, 143,   1, false, 0xFF, 0x17, 0x88, 144,  0, 0, 0),
277 	ATEST(SINGLE,   volsw_sx, 144,   1, false, 0xFF, 0x18, 0x88, 144,  0, 0, 0),
278 	ATEST(SINGLE,   volsw_sx, 145, -22, false, 0xFF, 0x00, 0x88, 144,  0, 0, 0),
279 	ATEST(SINGLE,   volsw_sx,   0,   1, true,  0xFF, 0x88, 0x88, 144,  0, 0, 0),
280 	ATEST(SINGLE,   volsw_sx,   1,   1, true,  0xFF, 0x89, 0x88, 144,  0, 0, 0),
281 	ATEST(SINGLE,   volsw_sx, 119,   0, true,  0xFF, 0xFF, 0x88, 144,  0, 0, 0),
282 	ATEST(SINGLE,   volsw_sx, 120,   1, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
283 	ATEST(SINGLE,   volsw_sx, 121,   1, true,  0xFF, 0x01, 0x88, 144,  0, 0, 0),
284 	ATEST(SINGLE,   volsw_sx, 143,   1, true,  0xFF, 0x17, 0x88, 144,  0, 0, 0),
285 	ATEST(SINGLE,   volsw_sx, 144,   1, true,  0xFF, 0x18, 0x88, 144,  0, 0, 0),
286 	ATEST(SINGLE,   volsw_sx, 145, -22, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
287 	// Double shift SX select values
288 	ATEST(DOUBLE,   volsw_sx,   0,   1, true,  0xFF, 0x88, 0x88, 144,  0, 0, 0),
289 	ATEST(DOUBLE,   volsw_sx,   1,   1, true,  0xFF, 0x89, 0x88, 144,  0, 0, 0),
290 	ATEST(DOUBLE,   volsw_sx, 119,   0, true,  0xFF, 0xFF, 0x88, 144,  0, 0, 0),
291 	ATEST(DOUBLE,   volsw_sx, 120,   1, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
292 	ATEST(DOUBLE,   volsw_sx, 121,   1, true,  0xFF, 0x01, 0x88, 144,  0, 0, 0),
293 	ATEST(DOUBLE,   volsw_sx, 143,   1, true,  0xFF, 0x17, 0x88, 144,  0, 0, 0),
294 	ATEST(DOUBLE,   volsw_sx, 144,   1, true,  0xFF, 0x18, 0x88, 144,  0, 0, 0),
295 	ATEST(DOUBLE,   volsw_sx, 145, -22, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
296 	// Double register SX select values
297 	ATEST(DOUBLE_R, volsw_sx,   0,   1, true,  0xFF, 0x88, 0x88, 144,  0, 0, 0),
298 	ATEST(DOUBLE_R, volsw_sx,   1,   1, true,  0xFF, 0x89, 0x88, 144,  0, 0, 0),
299 	ATEST(DOUBLE_R, volsw_sx, 119,   0, true,  0xFF, 0xFF, 0x88, 144,  0, 0, 0),
300 	ATEST(DOUBLE_R, volsw_sx, 120,   1, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
301 	ATEST(DOUBLE_R, volsw_sx, 121,   1, true,  0xFF, 0x01, 0x88, 144,  0, 0, 0),
302 	ATEST(DOUBLE_R, volsw_sx, 143,   1, true,  0xFF, 0x17, 0x88, 144,  0, 0, 0),
303 	ATEST(DOUBLE_R, volsw_sx, 144,   1, true,  0xFF, 0x18, 0x88, 144,  0, 0, 0),
304 	ATEST(DOUBLE_R, volsw_sx, 145, -22, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
305 };
306 
307 static const char *control_type_str(const snd_ctl_elem_type_t type)
308 {
309 	switch (type) {
310 	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
311 		return "bool";
312 	case SNDRV_CTL_ELEM_TYPE_INTEGER:
313 		return "int";
314 	default:
315 		return "unknown";
316 	}
317 }
318 
319 static const char *control_layout_str(const enum soc_ops_test_control_layout layout)
320 {
321 	switch (layout) {
322 	case SOC_OPS_TEST_SINGLE:
323 		return "single";
324 	case SOC_OPS_TEST_DOUBLE:
325 		return "double";
326 	case SOC_OPS_TEST_DOUBLE_R:
327 		return "double_r";
328 	default:
329 		return "unknown";
330 	}
331 };
332 
333 static int mock_regmap_read(void *context, const void *reg_buf,
334 			    const size_t reg_size, void *val_buf,
335 			    size_t val_size)
336 {
337 	struct soc_ops_test_priv *priv = context;
338 
339 	KUNIT_FAIL(priv->test, "Unexpected bus read");
340 
341 	return -EIO;
342 }
343 
344 static int mock_regmap_gather_write(void *context,
345 				    const void *reg_buf, size_t reg_size,
346 				    const void *val_buf, size_t val_size)
347 {
348 	struct soc_ops_test_priv *priv = context;
349 
350 	KUNIT_FAIL(priv->test, "Unexpected bus gather_write");
351 
352 	return -EIO;
353 }
354 
355 static int mock_regmap_write(void *context, const void *val_buf,
356 			     size_t val_size)
357 {
358 	struct soc_ops_test_priv *priv = context;
359 
360 	KUNIT_FAIL(priv->test, "Unexpected bus write");
361 
362 	return -EIO;
363 }
364 
365 static const struct regmap_bus mock_regmap_bus = {
366 	.read = mock_regmap_read,
367 	.write = mock_regmap_write,
368 	.gather_write = mock_regmap_gather_write,
369 	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
370 	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
371 };
372 
373 static const struct regmap_config mock_regmap_config = {
374 	.reg_bits = 32,
375 	.val_bits = 32,
376 	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
377 	.val_format_endian = REGMAP_ENDIAN_NATIVE,
378 	.max_register = 0x1,
379 	.cache_type = REGCACHE_FLAT,
380 };
381 
382 static int soc_ops_test_init(struct kunit *test)
383 {
384 	struct soc_ops_test_priv *priv;
385 	struct regmap *regmap;
386 	struct device *dev;
387 
388 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
389 	if (!priv)
390 		return -ENOMEM;
391 
392 	priv->test = test;
393 
394 	dev = kunit_device_register(test, "soc_ops_test_drv");
395 	if (IS_ERR(dev))
396 		return PTR_ERR(dev);
397 
398 	regmap = devm_regmap_init(dev, &mock_regmap_bus, priv, &mock_regmap_config);
399 	if (IS_ERR(regmap))
400 		return PTR_ERR(regmap);
401 
402 	/* No actual hardware, we just use the cache */
403 	regcache_cache_only(regmap, true);
404 
405 	priv->component.dev = dev;
406 	priv->component.regmap = regmap;
407 	mutex_init(&priv->component.io_mutex);
408 
409 	test->priv = priv;
410 
411 	return 0;
412 }
413 
414 static void soc_ops_test_exit(struct kunit *test)
415 {
416 	struct soc_ops_test_priv *priv = test->priv;
417 
418 	kunit_device_unregister(test, priv->component.dev);
419 }
420 
421 static void info_test_desc(const struct info_test_param *param, char *desc)
422 {
423 	snprintf(desc, KUNIT_PARAM_DESC_SIZE,
424 		 "%s %s %s: ctl range: %ld->%ld, reg range: %d->%d(%d), sign: %d, inv: %d",
425 		 control_layout_str(param->layout), param->func_name,
426 		 control_type_str(param->uinfo.type),
427 		 param->uinfo.value.integer.min, param->uinfo.value.integer.max,
428 		 param->mc.min, param->mc.max, param->mc.platform_max,
429 		 param->mc.sign_bit, param->mc.invert);
430 }
431 
432 static void soc_ops_test_info(struct kunit *test)
433 {
434 	struct soc_ops_test_priv *priv = test->priv;
435 	const struct info_test_param *param = test->param_value;
436 	const struct snd_ctl_elem_info *target = &param->uinfo;
437 	struct snd_ctl_elem_info result;
438 	struct snd_kcontrol kctl = {
439 		.private_data = &priv->component,
440 		.private_value = (unsigned long)&param->mc,
441 	};
442 	int ret;
443 
444 	strscpy(kctl.id.name, param->name, sizeof(kctl.id.name));
445 
446 	ret = param->info(&kctl, &result);
447 	KUNIT_ASSERT_FALSE(test, ret);
448 
449 	KUNIT_EXPECT_EQ(test, result.count, target->count);
450 	KUNIT_EXPECT_EQ(test, result.type, target->type);
451 	KUNIT_EXPECT_EQ(test, result.value.integer.min, target->value.integer.min);
452 	KUNIT_EXPECT_EQ(test, result.value.integer.max, target->value.integer.max);
453 }
454 
455 static void access_test_desc(const struct access_test_param *param, char *desc)
456 {
457 	if (param->ret < 0) {
458 		snprintf(desc, KUNIT_PARAM_DESC_SIZE,
459 			 "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> err: %d",
460 			 control_layout_str(param->layout), param->func_name,
461 			 param->lctl, param->rctl,
462 			 param->mc.min, param->mc.max, param->mc.platform_max,
463 			 param->mc.sign_bit, param->mc.invert,
464 			 param->ret);
465 	} else {
466 		snprintf(desc, KUNIT_PARAM_DESC_SIZE,
467 			 "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> %#x,%#x",
468 			 control_layout_str(param->layout), param->func_name,
469 			 param->lctl, param->rctl,
470 			 param->mc.min, param->mc.max, param->mc.platform_max,
471 			 param->mc.sign_bit, param->mc.invert,
472 			 param->lreg, param->rreg);
473 	}
474 }
475 
476 static void soc_ops_test_access(struct kunit *test)
477 {
478 	struct soc_ops_test_priv *priv = test->priv;
479 	const struct access_test_param *param = test->param_value;
480 	struct snd_kcontrol kctl = {
481 		.private_data = &priv->component,
482 		.private_value = (unsigned long)&param->mc,
483 	};
484 	struct snd_ctl_elem_value result;
485 	unsigned int val;
486 	int ret;
487 
488 	ret = regmap_write(priv->component.regmap, 0x0, param->init);
489 	KUNIT_ASSERT_FALSE(test, ret);
490 	ret = regmap_write(priv->component.regmap, 0x1, param->init);
491 	KUNIT_ASSERT_FALSE(test, ret);
492 
493 	result.value.integer.value[0] = param->lctl;
494 	result.value.integer.value[1] = param->rctl;
495 
496 	ret = param->put(&kctl, &result);
497 	KUNIT_ASSERT_EQ(test, ret, param->ret);
498 	if (ret < 0)
499 		return;
500 
501 	ret = regmap_read(priv->component.regmap, 0x0, &val);
502 	KUNIT_ASSERT_FALSE(test, ret);
503 	KUNIT_EXPECT_EQ(test, val, (param->init & ~param->lmask) | param->lreg);
504 
505 	ret = regmap_read(priv->component.regmap, 0x1, &val);
506 	KUNIT_ASSERT_FALSE(test, ret);
507 	KUNIT_EXPECT_EQ(test, val, (param->init & ~param->rmask) | param->rreg);
508 
509 	result.value.integer.value[0] = 0;
510 	result.value.integer.value[1] = 0;
511 
512 	ret = param->get(&kctl, &result);
513 	KUNIT_ASSERT_GE(test, ret, 0);
514 
515 	KUNIT_EXPECT_EQ(test, result.value.integer.value[0], param->lctl);
516 	if (param->layout != SOC_OPS_TEST_SINGLE)
517 		KUNIT_EXPECT_EQ(test, result.value.integer.value[1], param->rctl);
518 	else
519 		KUNIT_EXPECT_EQ(test, result.value.integer.value[1], 0);
520 }
521 
522 KUNIT_ARRAY_PARAM(all_info_tests, all_info_test_params, info_test_desc);
523 KUNIT_ARRAY_PARAM(all_access_tests, all_access_test_params, access_test_desc);
524 
525 static struct kunit_case soc_ops_test_cases[] = {
526 	KUNIT_CASE_PARAM(soc_ops_test_info, all_info_tests_gen_params),
527 	KUNIT_CASE_PARAM(soc_ops_test_access, all_access_tests_gen_params),
528 	{}
529 };
530 
531 static struct kunit_suite soc_ops_test_suite = {
532 	.name = "soc-ops",
533 	.init = soc_ops_test_init,
534 	.exit = soc_ops_test_exit,
535 	.test_cases = soc_ops_test_cases,
536 };
537 
538 kunit_test_suites(&soc_ops_test_suite);
539 
540 MODULE_DESCRIPTION("ASoC soc-ops kunit test");
541 MODULE_LICENSE("GPL");
542