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 = ¶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 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)¶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