1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // KUnit test for the Cirrus Logic cs35l56-shared module. 4 // 5 // Copyright (C) 2026 Cirrus Logic, Inc. and 6 // Cirrus Logic International Semiconductor Ltd. 7 8 #include <kunit/resource.h> 9 #include <kunit/test.h> 10 #include <kunit/static_stub.h> 11 #include <linux/bitfield.h> 12 #include <linux/bitops.h> 13 #include <linux/device/faux.h> 14 #include <linux/gpio/driver.h> 15 #include <linux/module.h> 16 #include <linux/random.h> 17 #include <linux/regmap.h> 18 #include <linux/seq_buf.h> 19 #include <sound/cs35l56.h> 20 21 struct cs35l56_shared_test_mock_gpio { 22 unsigned int pin_state; 23 struct gpio_chip chip; 24 }; 25 26 struct cs35l56_shared_test_priv { 27 struct kunit *test; 28 struct faux_device *amp_dev; 29 struct faux_device *gpio_dev; 30 struct cs35l56_shared_test_mock_gpio *gpio_priv; 31 struct regmap *registers; 32 unsigned int reg_offset; 33 struct cs35l56_base *cs35l56_base; 34 u8 applied_pad_pull_state[CS35L56_MAX_GPIO]; 35 }; 36 37 struct cs35l56_shared_test_param { 38 int spkid_gpios[4]; 39 int spkid_pulls[4]; 40 unsigned long gpio_status; 41 int spkid; 42 }; 43 44 KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy, 45 struct faux_device *) 46 47 KUNIT_DEFINE_ACTION_WRAPPER(regmap_exit_wrapper, regmap_exit, struct regmap *) 48 49 KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper, 50 device_remove_software_node, 51 struct device *) 52 53 static int cs35l56_shared_test_mock_gpio_get_direction(struct gpio_chip *chip, 54 unsigned int offset) 55 { 56 return GPIO_LINE_DIRECTION_IN; 57 } 58 59 static int cs35l56_shared_test_mock_gpio_direction_in(struct gpio_chip *chip, 60 unsigned int offset) 61 { 62 return 0; 63 } 64 65 static int cs35l56_shared_test_mock_gpio_get(struct gpio_chip *chip, unsigned int offset) 66 { 67 struct cs35l56_shared_test_mock_gpio *gpio_priv = gpiochip_get_data(chip); 68 69 return !!(gpio_priv->pin_state & BIT(offset)); 70 } 71 72 static const struct gpio_chip cs35l56_shared_test_mock_gpio_chip = { 73 .label = "cs35l56_shared_test_mock_gpio", 74 .owner = THIS_MODULE, 75 .get_direction = cs35l56_shared_test_mock_gpio_get_direction, 76 .direction_input = cs35l56_shared_test_mock_gpio_direction_in, 77 .get = cs35l56_shared_test_mock_gpio_get, 78 .base = -1, 79 .ngpio = 32, 80 }; 81 82 /* software_node referencing the gpio driver */ 83 static const struct software_node cs35l56_shared_test_mock_gpio_swnode = { 84 .name = "cs35l56_shared_test_mock_gpio", 85 }; 86 87 static int cs35l56_shared_test_mock_gpio_probe(struct faux_device *fdev) 88 { 89 struct cs35l56_shared_test_mock_gpio *gpio_priv; 90 struct device *dev = &fdev->dev; 91 int ret; 92 93 gpio_priv = devm_kzalloc(dev, sizeof(*gpio_priv), GFP_KERNEL); 94 if (!gpio_priv) 95 return -ENOMEM; 96 97 ret = device_add_software_node(dev, &cs35l56_shared_test_mock_gpio_swnode); 98 if (ret) 99 return ret; 100 101 ret = devm_add_action_or_reset(dev, device_remove_software_node_wrapper, dev); 102 if (ret) 103 return ret; 104 105 /* GPIO core modifies our struct gpio_chip so use a copy */ 106 gpio_priv->chip = cs35l56_shared_test_mock_gpio_chip; 107 gpio_priv->chip.parent = dev; 108 ret = devm_gpiochip_add_data(dev, &gpio_priv->chip, gpio_priv); 109 if (ret) 110 return dev_err_probe(dev, ret, "Failed to add gpiochip\n"); 111 112 dev_set_drvdata(dev, gpio_priv); 113 114 return 0; 115 } 116 117 static struct faux_device_ops cs35l56_shared_test_mock_gpio_drv = { 118 .probe = cs35l56_shared_test_mock_gpio_probe, 119 }; 120 121 static void _cs35l56_shared_test_create_dummy_gpio(struct kunit *test) 122 { 123 struct cs35l56_shared_test_priv *priv = test->priv; 124 125 priv->gpio_dev = faux_device_create("cs35l56_shared_test_mock_gpio", NULL, 126 &cs35l56_shared_test_mock_gpio_drv); 127 KUNIT_ASSERT_NOT_NULL(test, priv->gpio_dev); 128 KUNIT_ASSERT_EQ(test, 0, 129 kunit_add_action_or_reset(test, 130 faux_device_destroy_wrapper, 131 priv->gpio_dev)); 132 133 priv->gpio_priv = dev_get_drvdata(&priv->gpio_dev->dev); 134 KUNIT_ASSERT_NOT_NULL(test, priv->gpio_priv); 135 } 136 137 static const struct regmap_config cs35l56_shared_test_mock_registers_regmap = { 138 .reg_bits = 32, 139 .val_bits = 32, 140 .reg_stride = 4, 141 .max_register = CS35L56_DSP1_PMEM_5114, 142 .cache_type = REGCACHE_MAPLE, 143 }; 144 145 static const struct regmap_bus cs35l56_shared_test_mock_registers_regmap_bus = { 146 /* No handlers because it is always in cache-only */ 147 }; 148 149 static unsigned int cs35l56_shared_test_read_gpio_status(struct cs35l56_shared_test_priv *priv) 150 { 151 const struct cs35l56_shared_test_param *param = priv->test->param_value; 152 unsigned int reg_offs, pad_cfg, val; 153 unsigned int status = 0; 154 unsigned int mask = 1; 155 156 for (reg_offs = 0; reg_offs < CS35L56_MAX_GPIO * sizeof(u32); reg_offs += sizeof(u32)) { 157 regmap_read(priv->registers, CS35L56_SYNC_GPIO1_CFG + reg_offs, &pad_cfg); 158 regmap_read(priv->registers, CS35L56_GPIO1_CTRL1 + reg_offs, &val); 159 160 /* Only read a value if set as an input pin and as a GPIO */ 161 val &= (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_MASK); 162 if ((pad_cfg & CS35L56_PAD_GPIO_IE) && 163 (val == (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO))) 164 status |= (param->gpio_status & mask); 165 166 mask <<= 1; 167 } 168 169 return status; 170 } 171 172 static int cs35l56_shared_test_updt_gpio_pres(struct cs35l56_shared_test_priv *priv, 173 unsigned int reg, unsigned int val) 174 { 175 int i, ret; 176 177 ret = regmap_write(priv->registers, reg, val); 178 if (ret) 179 return ret; 180 181 if (val & CS35L56_UPDT_GPIO_PRES) { 182 /* Simulate transferring register state to internal latches */ 183 for (i = 0; i < ARRAY_SIZE(priv->applied_pad_pull_state); i++) { 184 reg = CS35L56_SYNC_GPIO1_CFG + (i * sizeof(u32)); 185 regmap_read(priv->registers, reg, &val); 186 val = FIELD_GET(CS35L56_PAD_GPIO_PULL_MASK, val); 187 priv->applied_pad_pull_state[i] = val; 188 } 189 } 190 191 return 0; 192 } 193 194 static int cs35l56_shared_test_reg_read(void *context, unsigned int reg, unsigned int *val) 195 { 196 struct cs35l56_shared_test_priv *priv = context; 197 198 reg -= priv->reg_offset; 199 200 switch (reg) { 201 case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: 202 case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1: 203 return regmap_read(priv->registers, reg, val); 204 case CS35L56_UPDATE_REGS: 205 *val = 0; 206 return 0; 207 case CS35L56_GPIO_STATUS1: 208 *val = cs35l56_shared_test_read_gpio_status(priv); 209 return 0; 210 default: 211 kunit_fail_current_test("Bad regmap read address %#x\n", reg); 212 return -EINVAL; 213 } 214 } 215 216 static int cs35l56_shared_test_reg_write(void *context, unsigned int reg, unsigned int val) 217 { 218 struct cs35l56_shared_test_priv *priv = context; 219 220 reg -= priv->reg_offset; 221 222 switch (reg) { 223 case CS35L56_UPDATE_REGS: 224 return cs35l56_shared_test_updt_gpio_pres(priv, reg, val); 225 case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: 226 case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1: 227 return regmap_write(priv->registers, reg, val); 228 default: 229 kunit_fail_current_test("Bad regmap write address %#x\n", reg); 230 return -EINVAL; 231 } 232 } 233 234 static const struct regmap_bus cs35l56_shared_test_regmap_bus = { 235 .reg_read = cs35l56_shared_test_reg_read, 236 .reg_write = cs35l56_shared_test_reg_write, 237 .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, 238 .val_format_endian_default = REGMAP_ENDIAN_LITTLE, 239 }; 240 241 /* 242 * Self-test that the mock GPIO registers obey the configuration bits. 243 * Other tests rely on the mocked registers only returning a GPIO state 244 * if the pin is correctly set as a GPIO input. 245 */ 246 static void cs35l56_shared_test_mock_gpio_status_selftest(struct kunit *test) 247 { 248 const struct cs35l56_shared_test_param *param = test->param_value; 249 struct cs35l56_shared_test_priv *priv = test->priv; 250 struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 251 unsigned int reg, val; 252 253 KUNIT_ASSERT_NOT_NULL(test, param); 254 255 /* Set all pins non-GPIO and output. Mock GPIO_STATUS should read 0 */ 256 for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 257 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 258 259 /* Set all pads as inputs */ 260 for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 261 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_PAD_GPIO_IE)); 262 263 KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 264 KUNIT_EXPECT_EQ(test, val, 0); 265 266 /* Set all pins as GPIO outputs. Mock GPIO_STATUS should read 0 */ 267 for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 268 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO_FN_GPIO)); 269 270 KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 271 KUNIT_EXPECT_EQ(test, val, 0); 272 273 /* Set all pins as non-GPIO inputs. Mock GPIO_STATUS should read 0 */ 274 for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 275 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO_DIR_MASK)); 276 277 KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 278 KUNIT_EXPECT_EQ(test, val, 0); 279 280 /* Set all pins as GPIO inputs. Mock GPIO_STATUS should match param->gpio_status */ 281 for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 282 KUNIT_ASSERT_EQ(test, 0, 283 regmap_write(priv->registers, reg, 284 CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO)); 285 286 KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 287 KUNIT_EXPECT_EQ(test, val, param->gpio_status); 288 289 /* Set all pads as outputs. Mock GPIO_STATUS should read 0 */ 290 for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 291 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 292 293 KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 294 KUNIT_EXPECT_EQ(test, val, 0); 295 } 296 297 /* Test that the listed chip pins are assembled into a speaker ID integer. */ 298 static void cs35l56_shared_test_get_onchip_speaker_id(struct kunit *test) 299 { 300 const struct cs35l56_shared_test_param *param = test->param_value; 301 struct cs35l56_shared_test_priv *priv = test->priv; 302 struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 303 unsigned int i, reg; 304 305 /* Set all pins non-GPIO and output */ 306 for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 307 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 308 309 for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 310 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 311 312 /* Init GPIO array */ 313 for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 314 if (param->spkid_gpios[i] < 0) 315 break; 316 317 cs35l56_base->onchip_spkid_gpios[i] = param->spkid_gpios[i] - 1; 318 cs35l56_base->num_onchip_spkid_gpios++; 319 } 320 321 cs35l56_base->num_onchip_spkid_pulls = 0; 322 323 KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0); 324 KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), param->spkid); 325 } 326 327 /* Test that the listed chip pins and the corresponding pads are configured correctly. */ 328 static void cs35l56_shared_test_onchip_speaker_id_pad_config(struct kunit *test) 329 { 330 const struct cs35l56_shared_test_param *param = test->param_value; 331 struct cs35l56_shared_test_priv *priv = test->priv; 332 struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 333 unsigned int i, reg, val; 334 335 /* Init values in all pin registers */ 336 for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 337 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 338 339 for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 340 KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 341 342 /* Init GPIO array */ 343 for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 344 if (param->spkid_gpios[i] < 0) 345 break; 346 347 cs35l56_base->onchip_spkid_gpios[i] = param->spkid_gpios[i] - 1; 348 cs35l56_base->num_onchip_spkid_gpios++; 349 } 350 351 /* Init pulls array */ 352 for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 353 if (param->spkid_pulls[i] < 0) 354 break; 355 356 cs35l56_base->onchip_spkid_pulls[i] = param->spkid_pulls[i]; 357 cs35l56_base->num_onchip_spkid_pulls++; 358 } 359 360 KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0); 361 362 for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 363 if (param->spkid_gpios[i] < 0) 364 break; 365 366 /* Pad should be an input */ 367 reg = CS35L56_SYNC_GPIO1_CFG + ((param->spkid_gpios[i] - 1) * sizeof(u32)); 368 KUNIT_EXPECT_EQ(test, regmap_read(priv->registers, reg, &val), 0); 369 KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_IE, CS35L56_PAD_GPIO_IE); 370 371 /* Specified pulls should be set, others should be none */ 372 if (i < cs35l56_base->num_onchip_spkid_pulls) { 373 KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK, 374 FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK, 375 param->spkid_pulls[i])); 376 } else { 377 KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK, 378 CS35L56_PAD_PULL_NONE); 379 } 380 381 /* Pulls for all specfied GPIOs should have been transferred to AO latch */ 382 if (i < cs35l56_base->num_onchip_spkid_pulls) { 383 KUNIT_EXPECT_EQ(test, 384 priv->applied_pad_pull_state[param->spkid_gpios[i] - 1], 385 param->spkid_pulls[i]); 386 } else { 387 KUNIT_EXPECT_EQ(test, 388 priv->applied_pad_pull_state[param->spkid_gpios[i] - 1], 389 CS35L56_PAD_PULL_NONE); 390 } 391 } 392 } 393 394 /* Test that the listed chip pins are stashed correctly. */ 395 static void cs35l56_shared_test_stash_onchip_spkid_pins(struct kunit *test) 396 { 397 const struct cs35l56_shared_test_param *param = test->param_value; 398 struct cs35l56_shared_test_priv *priv = test->priv; 399 struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 400 u32 gpios[5], pulls[5]; 401 int i, num_gpios, num_pulls; 402 403 static_assert(ARRAY_SIZE(gpios) >= ARRAY_SIZE(param->spkid_gpios)); 404 static_assert(ARRAY_SIZE(pulls) >= ARRAY_SIZE(param->spkid_pulls)); 405 406 num_gpios = 0; 407 for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 408 if (param->spkid_gpios[i] < 0) 409 break; 410 411 gpios[i] = (u32)param->spkid_gpios[i]; 412 num_gpios++; 413 } 414 415 num_pulls = 0; 416 for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 417 if (param->spkid_pulls[i] < 0) 418 break; 419 420 pulls[i] = (u32)param->spkid_pulls[i]; 421 num_pulls++; 422 } 423 424 cs35l56_base->num_onchip_spkid_gpios = 0; 425 cs35l56_base->num_onchip_spkid_pulls = 0; 426 427 KUNIT_ASSERT_LE(test, num_gpios, ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); 428 KUNIT_ASSERT_LE(test, num_pulls, ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls)); 429 430 KUNIT_EXPECT_EQ(test, 431 cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 432 gpios, num_gpios, 433 pulls, num_pulls), 434 0); 435 436 KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_gpios, num_gpios); 437 KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_pulls, num_pulls); 438 439 /* GPIO numbers are adjusted from 1-based to 0-based */ 440 for (i = 0; i < num_gpios; i++) 441 KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_gpios[i], gpios[i] - 1); 442 443 for (i = 0; i < num_pulls; i++) 444 KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_pulls[i], pulls[i]); 445 } 446 447 /* Test that illegal GPIO numbers are rejected. */ 448 static void cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid(struct kunit *test) 449 { 450 struct cs35l56_shared_test_priv *priv = test->priv; 451 struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 452 u32 gpios[8] = { }, pulls[8] = { }; 453 454 KUNIT_EXPECT_LE(test, 455 cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 456 gpios, 1, 457 pulls, 0), 458 0); 459 460 switch (cs35l56_base->type) { 461 case 0x54: 462 case 0x56: 463 case 0x57: 464 gpios[0] = CS35L56_MAX_GPIO + 1; 465 break; 466 case 0x63: 467 gpios[0] = CS35L63_MAX_GPIO + 1; 468 break; 469 default: 470 kunit_fail_current_test("Unsupported type:%#x\n", cs35l56_base->type); 471 return; 472 } 473 KUNIT_EXPECT_LE(test, 474 cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 475 gpios, 1, 476 pulls, 0), 477 0); 478 479 gpios[0] = 1; 480 pulls[0] = 3; 481 KUNIT_EXPECT_LE(test, 482 cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 483 gpios, 1, 484 pulls, 1), 485 0); 486 487 static_assert(ARRAY_SIZE(gpios) > ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); 488 static_assert(ARRAY_SIZE(pulls) > ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls)); 489 KUNIT_EXPECT_EQ(test, 490 cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 491 gpios, ARRAY_SIZE(gpios), 492 pulls, 0), 493 -EOVERFLOW); 494 KUNIT_EXPECT_EQ(test, 495 cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 496 gpios, 1, 497 pulls, ARRAY_SIZE(pulls)), 498 -EOVERFLOW); 499 } 500 501 static void cs35l56_shared_test_onchip_speaker_id_not_defined(struct kunit *test) 502 { 503 struct cs35l56_shared_test_priv *priv = test->priv; 504 struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 505 506 memset(cs35l56_base->onchip_spkid_gpios, 0, sizeof(cs35l56_base->onchip_spkid_gpios)); 507 memset(cs35l56_base->onchip_spkid_pulls, 0, sizeof(cs35l56_base->onchip_spkid_pulls)); 508 cs35l56_base->num_onchip_spkid_gpios = 0; 509 cs35l56_base->num_onchip_spkid_pulls = 0; 510 KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0); 511 KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), -ENOENT); 512 } 513 514 /* simulate cs_amp_get_vendor_spkid() reading a vendor-specific ID of 1 */ 515 static int cs35l56_shared_test_get_vendor_spkid_1(struct device *dev) 516 { 517 return 1; 518 } 519 520 static void cs35l56_shared_test_get_speaker_id_vendor(struct kunit *test) 521 { 522 struct cs35l56_shared_test_priv *priv = test->priv; 523 524 /* Hook cs_amp_get_vendor_spkid() to return an ID of 1 */ 525 kunit_activate_static_stub(test, cs_amp_get_vendor_spkid, 526 cs35l56_shared_test_get_vendor_spkid_1); 527 528 KUNIT_EXPECT_EQ(test, cs35l56_get_speaker_id(priv->cs35l56_base), 1); 529 } 530 531 static void cs35l56_shared_test_get_speaker_id_property(struct kunit *test) 532 { 533 struct cs35l56_shared_test_priv *priv = test->priv; 534 const struct property_entry dev_props[] = { 535 PROPERTY_ENTRY_U32("cirrus,speaker-id", 2), 536 { } 537 }; 538 const struct software_node dev_node = SOFTWARE_NODE("SPK1", dev_props, NULL); 539 540 KUNIT_ASSERT_EQ(test, device_add_software_node(priv->cs35l56_base->dev, &dev_node), 0); 541 KUNIT_ASSERT_EQ(test, 0, 542 kunit_add_action_or_reset(test, 543 device_remove_software_node_wrapper, 544 priv->cs35l56_base->dev)); 545 546 KUNIT_EXPECT_EQ(test, cs35l56_get_speaker_id(priv->cs35l56_base), 2); 547 } 548 549 /* 550 * Create software nodes equivalent to ACPI structure 551 * 552 * Device(GSPK) { 553 * Name(_DSD, ...) { 554 * Package() { 555 * cs-gpios { 556 * GPIO, n, 0, 557 * ... 558 * } 559 * } 560 */ 561 static void _cs35l56_shared_test_create_spkid_swnode(struct kunit *test, 562 struct device *dev, 563 const struct software_node_ref_args *args, 564 int num_args) 565 { 566 struct cs35l56_shared_test_priv *priv = test->priv; 567 const struct property_entry props_template[] = { 568 PROPERTY_ENTRY_REF_ARRAY_LEN("spk-id-gpios", args, num_args), 569 { } 570 }; 571 struct property_entry *props; 572 struct software_node *node; 573 574 props = kunit_kzalloc(test, sizeof(props_template), GFP_KERNEL); 575 KUNIT_ASSERT_NOT_NULL(test, props); 576 memcpy(props, props_template, sizeof(props_template)); 577 578 node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL); 579 KUNIT_ASSERT_NOT_NULL(test, node); 580 *node = SOFTWARE_NODE("GSPK", props, NULL); 581 582 KUNIT_ASSERT_EQ(test, device_add_software_node(dev, node), 0); 583 KUNIT_ASSERT_EQ(test, 0, 584 kunit_add_action_or_reset(test, 585 device_remove_software_node_wrapper, 586 priv->cs35l56_base->dev)); 587 } 588 589 static void cs35l56_shared_test_get_speaker_id_from_host_gpio(struct kunit *test) 590 { 591 const struct cs35l56_shared_test_param *param = test->param_value; 592 struct cs35l56_shared_test_priv *priv = test->priv; 593 struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 594 struct software_node_ref_args *ref; 595 int i; 596 597 if (!IS_REACHABLE(CONFIG_GPIOLIB)) { 598 kunit_skip(test, "Requires CONFIG_GPIOLIB"); 599 return; 600 } 601 602 _cs35l56_shared_test_create_dummy_gpio(test); 603 604 ref = kunit_kcalloc(test, ARRAY_SIZE(param->spkid_gpios), sizeof(*ref), GFP_KERNEL); 605 KUNIT_ASSERT_NOT_NULL(test, ref); 606 607 for (i = 0; param->spkid_gpios[i] >= 0; i++) { 608 ref[i] = SOFTWARE_NODE_REFERENCE(&cs35l56_shared_test_mock_gpio_swnode, 609 param->spkid_gpios[i], 0); 610 } 611 _cs35l56_shared_test_create_spkid_swnode(test, cs35l56_base->dev, ref, i); 612 613 priv->gpio_priv->pin_state = param->gpio_status; 614 KUNIT_EXPECT_EQ(test, cs35l56_get_speaker_id(priv->cs35l56_base), param->spkid); 615 } 616 617 static int cs35l56_shared_test_case_regmap_init(struct kunit *test, 618 const struct regmap_config *regmap_config) 619 { 620 struct cs35l56_shared_test_priv *priv = test->priv; 621 struct cs35l56_base *cs35l56_base; 622 623 /* 624 * Create a dummy regmap to simulate a register map by holding the 625 * values of all simulated registers in the regmap cache. 626 */ 627 priv->registers = regmap_init(&priv->amp_dev->dev, 628 &cs35l56_shared_test_mock_registers_regmap_bus, 629 priv, 630 &cs35l56_shared_test_mock_registers_regmap); 631 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->registers); 632 KUNIT_ASSERT_EQ(test, 0, 633 kunit_add_action_or_reset(test, regmap_exit_wrapper, 634 priv->registers)); 635 regcache_cache_only(priv->registers, true); 636 637 /* Create dummy regmap for cs35l56 driver */ 638 cs35l56_base = priv->cs35l56_base; 639 cs35l56_base->regmap = regmap_init(cs35l56_base->dev, 640 &cs35l56_shared_test_regmap_bus, 641 priv, 642 regmap_config); 643 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cs35l56_base->regmap); 644 KUNIT_ASSERT_EQ(test, 0, 645 kunit_add_action_or_reset(test, regmap_exit_wrapper, 646 cs35l56_base->regmap)); 647 648 return 0; 649 } 650 651 static int cs35l56_shared_test_case_base_init(struct kunit *test, u8 type, u8 rev, 652 const struct regmap_config *regmap_config) 653 { 654 struct cs35l56_shared_test_priv *priv; 655 int ret; 656 657 KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks); 658 659 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 660 if (!priv) 661 return -ENOMEM; 662 663 test->priv = priv; 664 priv->test = test; 665 666 /* Create dummy amp driver dev */ 667 priv->amp_dev = faux_device_create("cs35l56_shared_test_drv", NULL, NULL); 668 KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev); 669 KUNIT_ASSERT_EQ(test, 0, 670 kunit_add_action_or_reset(test, 671 faux_device_destroy_wrapper, 672 priv->amp_dev)); 673 674 priv->cs35l56_base = kunit_kzalloc(test, sizeof(*priv->cs35l56_base), GFP_KERNEL); 675 KUNIT_ASSERT_NOT_NULL(test, priv->cs35l56_base); 676 priv->cs35l56_base->dev = &priv->amp_dev->dev; 677 priv->cs35l56_base->type = type; 678 priv->cs35l56_base->rev = rev; 679 680 if (regmap_config) { 681 priv->reg_offset = regmap_config->reg_base; 682 ret = cs35l56_shared_test_case_regmap_init(test, regmap_config); 683 if (ret) 684 return ret; 685 } 686 687 return 0; 688 } 689 690 static int cs35l56_shared_test_case_regmap_init_L56_B0_sdw(struct kunit *test) 691 { 692 return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_sdw); 693 } 694 695 static int cs35l56_shared_test_case_regmap_init_L56_B0_spi(struct kunit *test) 696 { 697 return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_spi); 698 } 699 700 static int cs35l56_shared_test_case_regmap_init_L56_B0_i2c(struct kunit *test) 701 { 702 return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_i2c); 703 } 704 705 static int cs35l56_shared_test_case_regmap_init_L56_B2_sdw(struct kunit *test) 706 { 707 return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_sdw); 708 } 709 710 static int cs35l56_shared_test_case_regmap_init_L56_B2_spi(struct kunit *test) 711 { 712 return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_spi); 713 } 714 715 static int cs35l56_shared_test_case_regmap_init_L56_B2_i2c(struct kunit *test) 716 { 717 return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_i2c); 718 } 719 720 static int cs35l56_shared_test_case_regmap_init_L63_A1_sdw(struct kunit *test) 721 { 722 return cs35l56_shared_test_case_base_init(test, 0x63, 0xa1, &cs35l63_regmap_sdw); 723 } 724 725 static void cs35l56_shared_test_gpio_param_desc(const struct cs35l56_shared_test_param *param, 726 char *desc) 727 { 728 DECLARE_SEQ_BUF(gpios, 1 + (2 * ARRAY_SIZE(param->spkid_gpios))); 729 DECLARE_SEQ_BUF(pulls, 1 + (2 * ARRAY_SIZE(param->spkid_pulls))); 730 int i; 731 732 for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 733 if (param->spkid_gpios[i] < 0) 734 break; 735 736 seq_buf_printf(&gpios, "%s%d", (i == 0) ? "" : ",", param->spkid_gpios[i]); 737 } 738 739 for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 740 if (param->spkid_pulls[i] < 0) 741 break; 742 743 seq_buf_printf(&pulls, "%s%d", (i == 0) ? "" : ",", param->spkid_pulls[i]); 744 } 745 746 snprintf(desc, KUNIT_PARAM_DESC_SIZE, "gpios:{%s} pulls:{%s} status:%#lx spkid:%d", 747 seq_buf_str(&gpios), seq_buf_str(&pulls), param->gpio_status, param->spkid); 748 } 749 750 static const struct cs35l56_shared_test_param cs35l56_shared_test_gpios_selftest_cases[] = { 751 { .spkid_gpios = { -1 }, .gpio_status = GENMASK(12, 0) }, 752 }; 753 KUNIT_ARRAY_PARAM(cs35l56_shared_test_gpios_selftest, 754 cs35l56_shared_test_gpios_selftest_cases, 755 cs35l56_shared_test_gpio_param_desc); 756 757 static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_spkid_cases[] = { 758 { .spkid_gpios = { 1, -1 }, .gpio_status = 0, .spkid = 0 }, 759 { .spkid_gpios = { 1, -1 }, .gpio_status = ~BIT(0), .spkid = 0 }, 760 { .spkid_gpios = { 1, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 761 762 { .spkid_gpios = { 7, -1 }, .gpio_status = 0, .spkid = 0 }, 763 { .spkid_gpios = { 7, -1 }, .gpio_status = ~BIT(6), .spkid = 0 }, 764 { .spkid_gpios = { 7, -1 }, .gpio_status = BIT(6), .spkid = 1 }, 765 766 { .spkid_gpios = { 1, 7, -1 }, .gpio_status = 0, .spkid = 0 }, 767 { .spkid_gpios = { 1, 7, -1 }, .gpio_status = ~(BIT(0) | BIT(6)), .spkid = 0 }, 768 { .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(6), .spkid = 1 }, 769 { .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(0), .spkid = 2 }, 770 { .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 771 772 { .spkid_gpios = { 7, 1, -1 }, .gpio_status = 0, .spkid = 0 }, 773 { .spkid_gpios = { 7, 1, -1 }, .gpio_status = ~(BIT(6) | BIT(0)), .spkid = 0 }, 774 { .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 775 { .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(6), .spkid = 2 }, 776 { .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 777 778 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = 0, .spkid = 0 }, 779 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 780 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(6), .spkid = 2 }, 781 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 782 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2), .spkid = 4 }, 783 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(0), .spkid = 5 }, 784 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(6), .spkid = 6 }, 785 { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(6) | BIT(0), .spkid = 7 }, 786 }; 787 KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid, cs35l56_shared_test_onchip_spkid_cases, 788 cs35l56_shared_test_gpio_param_desc); 789 790 static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_spkid_pull_cases[] = { 791 { .spkid_gpios = { 1, -1 }, .spkid_pulls = { 1, -1 }, }, 792 { .spkid_gpios = { 1, -1 }, .spkid_pulls = { 2, -1 }, }, 793 794 { .spkid_gpios = { 7, -1 }, .spkid_pulls = { 1, -1 }, }, 795 { .spkid_gpios = { 7, -1 }, .spkid_pulls = { 2, -1 }, }, 796 797 { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 1, 1, -1 }, }, 798 { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 2, 2, -1 }, }, 799 800 { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 1, 1, -1 }, }, 801 { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 2, 2, -1 }, }, 802 803 { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 1, 1, 1, -1 }, }, 804 { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 2, 2, 2, -1 }, }, 805 }; 806 KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid_pull, 807 cs35l56_shared_test_onchip_spkid_pull_cases, 808 cs35l56_shared_test_gpio_param_desc); 809 810 /* Note: spk-id-gpios property bit order is LSbit...MSbit */ 811 static const struct cs35l56_shared_test_param cs35l56_shared_test_host_gpio_spkid_cases[] = { 812 { .spkid_gpios = { 0, -1 }, .gpio_status = 0, .spkid = 0 }, 813 { .spkid_gpios = { 0, -1 }, .gpio_status = ~BIT(0), .spkid = 0 }, 814 { .spkid_gpios = { 0, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 815 816 { .spkid_gpios = { 6, -1 }, .gpio_status = 0, .spkid = 0 }, 817 { .spkid_gpios = { 6, -1 }, .gpio_status = ~BIT(6), .spkid = 0 }, 818 { .spkid_gpios = { 6, -1 }, .gpio_status = BIT(6), .spkid = 1 }, 819 820 { .spkid_gpios = { 6, 0, -1 }, .gpio_status = 0, .spkid = 0 }, 821 { .spkid_gpios = { 6, 0, -1 }, .gpio_status = ~(BIT(0) | BIT(6)), .spkid = 0 }, 822 { .spkid_gpios = { 6, 0, -1 }, .gpio_status = BIT(6), .spkid = 1 }, 823 { .spkid_gpios = { 6, 0, -1 }, .gpio_status = BIT(0), .spkid = 2 }, 824 { .spkid_gpios = { 6, 0, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 825 826 { .spkid_gpios = { 0, 6, -1 }, .gpio_status = 0, .spkid = 0 }, 827 { .spkid_gpios = { 0, 6, -1 }, .gpio_status = ~(BIT(6) | BIT(0)), .spkid = 0 }, 828 { .spkid_gpios = { 0, 6, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 829 { .spkid_gpios = { 0, 6, -1 }, .gpio_status = BIT(6), .spkid = 2 }, 830 { .spkid_gpios = { 0, 6, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 831 832 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = 0, .spkid = 0 }, 833 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 834 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(6), .spkid = 2 }, 835 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 836 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2), .spkid = 4 }, 837 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2) | BIT(0), .spkid = 5 }, 838 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2) | BIT(6), .spkid = 6 }, 839 { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2) | BIT(6) | BIT(0), .spkid = 7 }, 840 }; 841 KUNIT_ARRAY_PARAM(cs35l56_shared_test_host_gpio_spkid, cs35l56_shared_test_host_gpio_spkid_cases, 842 cs35l56_shared_test_gpio_param_desc); 843 844 static struct kunit_case cs35l56_shared_test_cases[] = { 845 /* Tests for speaker id */ 846 KUNIT_CASE_PARAM(cs35l56_shared_test_mock_gpio_status_selftest, 847 cs35l56_shared_test_gpios_selftest_gen_params), 848 KUNIT_CASE_PARAM(cs35l56_shared_test_get_onchip_speaker_id, 849 cs35l56_shared_test_onchip_spkid_gen_params), 850 KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config, 851 cs35l56_shared_test_onchip_spkid_gen_params), 852 KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config, 853 cs35l56_shared_test_onchip_spkid_pull_gen_params), 854 KUNIT_CASE_PARAM(cs35l56_shared_test_stash_onchip_spkid_pins, 855 cs35l56_shared_test_onchip_spkid_pull_gen_params), 856 KUNIT_CASE(cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid), 857 KUNIT_CASE(cs35l56_shared_test_onchip_speaker_id_not_defined), 858 859 KUNIT_CASE(cs35l56_shared_test_get_speaker_id_vendor), 860 KUNIT_CASE(cs35l56_shared_test_get_speaker_id_property), 861 KUNIT_CASE_PARAM_ATTR(cs35l56_shared_test_get_speaker_id_from_host_gpio, 862 cs35l56_shared_test_host_gpio_spkid_gen_params, 863 { KUNIT_SPEED_SLOW }), 864 865 { } 866 }; 867 868 static struct kunit_suite cs35l56_shared_test_suite_L56_B0_sdw = { 869 .name = "snd-soc-cs35l56-shared-test_L56_B0_sdw", 870 .init = cs35l56_shared_test_case_regmap_init_L56_B0_sdw, 871 .test_cases = cs35l56_shared_test_cases, 872 }; 873 874 static struct kunit_suite cs35l56_shared_test_suite_L56_B2_sdw = { 875 .name = "snd-soc-cs35l56-shared-test_L56_B2_sdw", 876 .init = cs35l56_shared_test_case_regmap_init_L56_B2_sdw, 877 .test_cases = cs35l56_shared_test_cases, 878 }; 879 880 static struct kunit_suite cs35l56_shared_test_suite_L63_A1_sdw = { 881 .name = "snd-soc-cs35l56-shared-test_L63_A1_sdw", 882 .init = cs35l56_shared_test_case_regmap_init_L63_A1_sdw, 883 .test_cases = cs35l56_shared_test_cases, 884 }; 885 886 static struct kunit_suite cs35l56_shared_test_suite_L56_B0_spi = { 887 .name = "snd-soc-cs35l56-shared-test_L56_B0_spi", 888 .init = cs35l56_shared_test_case_regmap_init_L56_B0_spi, 889 .test_cases = cs35l56_shared_test_cases, 890 }; 891 892 static struct kunit_suite cs35l56_shared_test_suite_L56_B2_spi = { 893 .name = "snd-soc-cs35l56-shared-test_L56_B2_spi", 894 .init = cs35l56_shared_test_case_regmap_init_L56_B2_spi, 895 .test_cases = cs35l56_shared_test_cases, 896 }; 897 898 static struct kunit_suite cs35l56_shared_test_suite_L56_B0_i2c = { 899 .name = "snd-soc-cs35l56-shared-test_L56_B0_i2c", 900 .init = cs35l56_shared_test_case_regmap_init_L56_B0_i2c, 901 .test_cases = cs35l56_shared_test_cases, 902 }; 903 904 static struct kunit_suite cs35l56_shared_test_suite_L56_B2_i2c = { 905 .name = "snd-soc-cs35l56-shared-test_L56_B2_i2c", 906 .init = cs35l56_shared_test_case_regmap_init_L56_B2_i2c, 907 .test_cases = cs35l56_shared_test_cases, 908 }; 909 910 kunit_test_suites( 911 &cs35l56_shared_test_suite_L56_B0_sdw, 912 &cs35l56_shared_test_suite_L56_B2_sdw, 913 &cs35l56_shared_test_suite_L63_A1_sdw, 914 915 &cs35l56_shared_test_suite_L56_B0_spi, 916 &cs35l56_shared_test_suite_L56_B2_spi, 917 918 &cs35l56_shared_test_suite_L56_B0_i2c, 919 &cs35l56_shared_test_suite_L56_B2_i2c, 920 ); 921 922 MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); 923 MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); 924 MODULE_DESCRIPTION("KUnit test for cs35l56-shared module"); 925 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); 926 MODULE_LICENSE("GPL"); 927