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
control_type_str(const snd_ctl_elem_type_t type)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
control_layout_str(const enum soc_ops_test_control_layout layout)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
mock_regmap_read(void * context,const void * reg_buf,const size_t reg_size,void * val_buf,size_t val_size)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
mock_regmap_gather_write(void * context,const void * reg_buf,size_t reg_size,const void * val_buf,size_t val_size)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
mock_regmap_write(void * context,const void * val_buf,size_t val_size)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
soc_ops_test_init(struct kunit * test)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
soc_ops_test_exit(struct kunit * test)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
info_test_desc(const struct info_test_param * param,char * desc)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
soc_ops_test_info(struct kunit * test)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 = ¶m->uinfo;
437 struct snd_ctl_elem_info result;
438 struct snd_kcontrol kctl = {
439 .private_data = &priv->component,
440 .private_value = (unsigned long)¶m->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
access_test_desc(const struct access_test_param * param,char * desc)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
soc_ops_test_access(struct kunit * test)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)¶m->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