ASoC: cs35l56-shared: KUnit tests for onchip speaker ID gpios

Add KUnit testing of:
 cs35l56_check_and_save_onchip_spkid_gpios()
 cs35l56_configure_onchip_spkid_pads()
 cs35l56_read_onchip_spkid()

The test consists of:

- A mock regmap that simulates the pad and pin config registers.

- Parameterization of the pin list, pulls list, a simulated value for
  each pin and the speaker ID value that this should produce.

- A self-test of the simulated pin and GPIO registers.

- A test that the value returned by cs35l56_read_onchip_spkid() is
  correct.

- A test that the pin pull-up/down are set correctly by
  cs35l56_configure_onchip_spkid_pads()

- A test that cs35l56_configure_onchip_spkid_pads() and
  cs35l56_read_onchip_spkid(0 return the expected values if
  cs35l56_base->num_onchip_spkid_gpios == 0.

- A test that cs35l56_check_and_save_onchip_spkid_gpios() saves
  the configuration.

- A test that cs35l56_check_and_save_onchip_spkid_gpios() rejects
  illegal GPIO numbers.

- A test that cs35l56_check_and_save_onchip_spkid_gpios() rejects
  illegal pull types.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://patch.msgid.link/20260205164838.1611295-3-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Richard Fitzgerald
2026-02-05 16:48:37 +00:00
committed by Mark Brown
parent 4d1e3e2c40
commit 9bca0f05ce
4 changed files with 701 additions and 0 deletions

View File

@@ -936,6 +936,20 @@ config SND_SOC_CS35L56_TEST
help
This builds KUnit tests for the Cirrus Logic cs35l56
codec driver.
For more information on KUnit and unit tests in general,
please refer to the KUnit documentation in
Documentation/dev-tools/kunit/.
If in doubt, say "N".
config SND_SOC_CS35L56_SHARED_TEST
tristate "KUnit test for Cirrus Logic cs35l56-shared" if !KUNIT_ALL_TESTS
depends on SND_SOC_CS35L56_SHARED && KUNIT
default KUNIT_ALL_TESTS
help
This builds KUnit tests for the Cirrus Logic cs35l56-shared
module.
For more information on KUnit and unit tests in general,
please refer to the KUnit documentation in
Documentation/dev-tools/kunit/.

View File

@@ -77,6 +77,7 @@ snd-soc-cs35l45-spi-y := cs35l45-spi.o
snd-soc-cs35l45-i2c-y := cs35l45-i2c.o
snd-soc-cs35l56-y := cs35l56.o
snd-soc-cs35l56-shared-y := cs35l56-shared.o
snd-soc-cs35l56-shared-test-y := cs35l56-shared-test.o
snd-soc-cs35l56-i2c-y := cs35l56-i2c.o
snd-soc-cs35l56-spi-y := cs35l56-spi.o
snd-soc-cs35l56-sdw-y := cs35l56-sdw.o
@@ -512,6 +513,7 @@ obj-$(CONFIG_SND_SOC_CS35L45_SPI) += snd-soc-cs35l45-spi.o
obj-$(CONFIG_SND_SOC_CS35L45_I2C) += snd-soc-cs35l45-i2c.o
obj-$(CONFIG_SND_SOC_CS35L56) += snd-soc-cs35l56.o
obj-$(CONFIG_SND_SOC_CS35L56_SHARED) += snd-soc-cs35l56-shared.o
obj-$(CONFIG_SND_SOC_CS35L56_SHARED_TEST) += snd-soc-cs35l56-shared-test.o
obj-$(CONFIG_SND_SOC_CS35L56_I2C) += snd-soc-cs35l56-i2c.o
obj-$(CONFIG_SND_SOC_CS35L56_SPI) += snd-soc-cs35l56-spi.o
obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o

View File

@@ -0,0 +1,680 @@
// SPDX-License-Identifier: GPL-2.0-only
//
// KUnit test for the Cirrus Logic cs35l56-shared module.
//
// Copyright (C) 2026 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
#include <kunit/resource.h>
#include <kunit/test.h>
#include <kunit/static_stub.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/device/faux.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/regmap.h>
#include <linux/seq_buf.h>
#include <sound/cs35l56.h>
struct cs35l56_shared_test_priv {
struct kunit *test;
struct faux_device *amp_dev;
struct regmap *registers;
struct cs35l56_base *cs35l56_base;
u8 applied_pad_pull_state[CS35L56_MAX_GPIO];
};
struct cs35l56_shared_test_param {
int spkid_gpios[4];
int spkid_pulls[4];
unsigned long gpio_status;
int spkid;
};
KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
struct faux_device *)
KUNIT_DEFINE_ACTION_WRAPPER(regmap_exit_wrapper, regmap_exit, struct regmap *)
static const struct regmap_config cs35l56_shared_test_mock_registers_regmap = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = CS35L56_DSP1_PMEM_5114,
.cache_type = REGCACHE_MAPLE,
};
static const struct regmap_bus cs35l56_shared_test_mock_registers_regmap_bus = {
/* No handlers because it is always in cache-only */
};
static unsigned int cs35l56_shared_test_read_gpio_status(struct cs35l56_shared_test_priv *priv)
{
const struct cs35l56_shared_test_param *param = priv->test->param_value;
unsigned int reg_offs, pad_cfg, val;
unsigned int status = 0;
unsigned int mask = 1;
for (reg_offs = 0; reg_offs < CS35L56_MAX_GPIO * sizeof(u32); reg_offs += sizeof(u32)) {
regmap_read(priv->registers, CS35L56_SYNC_GPIO1_CFG + reg_offs, &pad_cfg);
regmap_read(priv->registers, CS35L56_GPIO1_CTRL1 + reg_offs, &val);
/* Only read a value if set as an input pin and as a GPIO */
val &= (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_MASK);
if ((pad_cfg & CS35L56_PAD_GPIO_IE) &&
(val == (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO)))
status |= (param->gpio_status & mask);
mask <<= 1;
}
return status;
}
static int cs35l56_shared_test_updt_gpio_pres(struct cs35l56_shared_test_priv *priv,
unsigned int reg, unsigned int val)
{
int i, ret;
ret = regmap_write(priv->registers, reg, val);
if (ret)
return ret;
if (val & CS35L56_UPDT_GPIO_PRES) {
/* Simulate transferring register state to internal latches */
for (i = 0; i < ARRAY_SIZE(priv->applied_pad_pull_state); i++) {
reg = CS35L56_SYNC_GPIO1_CFG + (i * sizeof(u32));
regmap_read(priv->registers, reg, &val);
val = FIELD_GET(CS35L56_PAD_GPIO_PULL_MASK, val);
priv->applied_pad_pull_state[i] = val;
}
}
return 0;
}
static int cs35l56_shared_test_reg_read(void *context, unsigned int reg, unsigned int *val)
{
struct cs35l56_shared_test_priv *priv = context;
switch (reg) {
case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG:
case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1:
return regmap_read(priv->registers, reg, val);
case CS35L56_UPDATE_REGS:
*val = 0;
return 0;
case CS35L56_GPIO_STATUS1:
*val = cs35l56_shared_test_read_gpio_status(priv);
return 0;
default:
kunit_fail_current_test("Bad regmap read address %#x\n", reg);
return -EINVAL;
}
}
static int cs35l56_shared_test_reg_write(void *context, unsigned int reg, unsigned int val)
{
struct cs35l56_shared_test_priv *priv = context;
switch (reg) {
case CS35L56_UPDATE_REGS:
return cs35l56_shared_test_updt_gpio_pres(priv, reg, val);
case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG:
case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1:
return regmap_write(priv->registers, reg, val);
default:
kunit_fail_current_test("Bad regmap write address %#x\n", reg);
return -EINVAL;
}
}
static const struct regmap_bus cs35l56_shared_test_regmap_bus = {
.reg_read = cs35l56_shared_test_reg_read,
.reg_write = cs35l56_shared_test_reg_write,
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
};
/*
* Self-test that the mock GPIO registers obey the configuration bits.
* Other tests rely on the mocked registers only returning a GPIO state
* if the pin is correctly set as a GPIO input.
*/
static void cs35l56_shared_test_mock_gpio_status_selftest(struct kunit *test)
{
const struct cs35l56_shared_test_param *param = test->param_value;
struct cs35l56_shared_test_priv *priv = test->priv;
struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
unsigned int reg, val;
KUNIT_ASSERT_NOT_NULL(test, param);
/* Set all pins non-GPIO and output. Mock GPIO_STATUS should read 0 */
for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0));
/* Set all pads as inputs */
for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_PAD_GPIO_IE));
KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val));
KUNIT_EXPECT_EQ(test, val, 0);
/* Set all pins as GPIO outputs. Mock GPIO_STATUS should read 0 */
for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO_FN_GPIO));
KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val));
KUNIT_EXPECT_EQ(test, val, 0);
/* Set all pins as non-GPIO inputs. Mock GPIO_STATUS should read 0 */
for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO_DIR_MASK));
KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val));
KUNIT_EXPECT_EQ(test, val, 0);
/* Set all pins as GPIO inputs. Mock GPIO_STATUS should match param->gpio_status */
for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0,
regmap_write(priv->registers, reg,
CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO));
KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val));
KUNIT_EXPECT_EQ(test, val, param->gpio_status);
/* Set all pads as outputs. Mock GPIO_STATUS should read 0 */
for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0));
KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val));
KUNIT_EXPECT_EQ(test, val, 0);
}
/* Test that the listed chip pins are assembled into a speaker ID integer. */
static void cs35l56_shared_test_get_onchip_speaker_id(struct kunit *test)
{
const struct cs35l56_shared_test_param *param = test->param_value;
struct cs35l56_shared_test_priv *priv = test->priv;
struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
unsigned int i, reg;
/* Set all pins non-GPIO and output */
for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0));
for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0));
/* Init GPIO array */
for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) {
if (param->spkid_gpios[i] < 0)
break;
cs35l56_base->onchip_spkid_gpios[i] = param->spkid_gpios[i] - 1;
cs35l56_base->num_onchip_spkid_gpios++;
}
cs35l56_base->num_onchip_spkid_pulls = 0;
KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0);
KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), param->spkid);
}
/* Test that the listed chip pins and the corresponding pads are configured correctly. */
static void cs35l56_shared_test_onchip_speaker_id_pad_config(struct kunit *test)
{
const struct cs35l56_shared_test_param *param = test->param_value;
struct cs35l56_shared_test_priv *priv = test->priv;
struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
unsigned int i, reg, val;
/* Init values in all pin registers */
for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0));
for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32))
KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0));
/* Init GPIO array */
for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) {
if (param->spkid_gpios[i] < 0)
break;
cs35l56_base->onchip_spkid_gpios[i] = param->spkid_gpios[i] - 1;
cs35l56_base->num_onchip_spkid_gpios++;
}
/* Init pulls array */
for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) {
if (param->spkid_pulls[i] < 0)
break;
cs35l56_base->onchip_spkid_pulls[i] = param->spkid_pulls[i];
cs35l56_base->num_onchip_spkid_pulls++;
}
KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0);
for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) {
if (param->spkid_gpios[i] < 0)
break;
/* Pad should be an input */
reg = CS35L56_SYNC_GPIO1_CFG + ((param->spkid_gpios[i] - 1) * sizeof(u32));
KUNIT_EXPECT_EQ(test, regmap_read(priv->registers, reg, &val), 0);
KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_IE, CS35L56_PAD_GPIO_IE);
/* Specified pulls should be set, others should be none */
if (i < cs35l56_base->num_onchip_spkid_pulls) {
KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK,
FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK,
param->spkid_pulls[i]));
} else {
KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK,
CS35L56_PAD_PULL_NONE);
}
/* Pulls for all specfied GPIOs should have been transferred to AO latch */
if (i < cs35l56_base->num_onchip_spkid_pulls) {
KUNIT_EXPECT_EQ(test,
priv->applied_pad_pull_state[param->spkid_gpios[i] - 1],
param->spkid_pulls[i]);
} else {
KUNIT_EXPECT_EQ(test,
priv->applied_pad_pull_state[param->spkid_gpios[i] - 1],
CS35L56_PAD_PULL_NONE);
}
}
}
/* Test that the listed chip pins are stashed correctly. */
static void cs35l56_shared_test_stash_onchip_spkid_pins(struct kunit *test)
{
const struct cs35l56_shared_test_param *param = test->param_value;
struct cs35l56_shared_test_priv *priv = test->priv;
struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
u32 gpios[5], pulls[5];
int i, num_gpios, num_pulls;
static_assert(ARRAY_SIZE(gpios) >= ARRAY_SIZE(param->spkid_gpios));
static_assert(ARRAY_SIZE(pulls) >= ARRAY_SIZE(param->spkid_pulls));
num_gpios = 0;
for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) {
if (param->spkid_gpios[i] < 0)
break;
gpios[i] = (u32)param->spkid_gpios[i];
num_gpios++;
}
num_pulls = 0;
for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) {
if (param->spkid_pulls[i] < 0)
break;
pulls[i] = (u32)param->spkid_pulls[i];
num_pulls++;
}
cs35l56_base->num_onchip_spkid_gpios = 0;
cs35l56_base->num_onchip_spkid_pulls = 0;
KUNIT_ASSERT_LE(test, num_gpios, ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios));
KUNIT_ASSERT_LE(test, num_pulls, ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls));
KUNIT_EXPECT_EQ(test,
cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base,
gpios, num_gpios,
pulls, num_pulls),
0);
KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_gpios, num_gpios);
KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_pulls, num_pulls);
/* GPIO numbers are adjusted from 1-based to 0-based */
for (i = 0; i < num_gpios; i++)
KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_gpios[i], gpios[i] - 1);
for (i = 0; i < num_pulls; i++)
KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_pulls[i], pulls[i]);
}
/* Test that illegal GPIO numbers are rejected. */
static void cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid(struct kunit *test)
{
struct cs35l56_shared_test_priv *priv = test->priv;
struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
u32 gpios[8] = { }, pulls[8] = { };
KUNIT_EXPECT_LE(test,
cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base,
gpios, 1,
pulls, 0),
0);
switch (cs35l56_base->type) {
case 0x54:
case 0x56:
case 0x57:
gpios[0] = CS35L56_MAX_GPIO + 1;
break;
case 0x63:
gpios[0] = CS35L63_MAX_GPIO + 1;
break;
default:
kunit_fail_current_test("Unsupported type:%#x\n", cs35l56_base->type);
return;
}
KUNIT_EXPECT_LE(test,
cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base,
gpios, 1,
pulls, 0),
0);
gpios[0] = 1;
pulls[0] = 3;
KUNIT_EXPECT_LE(test,
cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base,
gpios, 1,
pulls, 1),
0);
static_assert(ARRAY_SIZE(gpios) > ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios));
static_assert(ARRAY_SIZE(pulls) > ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls));
KUNIT_EXPECT_EQ(test,
cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base,
gpios, ARRAY_SIZE(gpios),
pulls, 0),
-EOVERFLOW);
KUNIT_EXPECT_EQ(test,
cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base,
gpios, 1,
pulls, ARRAY_SIZE(pulls)),
-EOVERFLOW);
}
static void cs35l56_shared_test_onchip_speaker_id_not_defined(struct kunit *test)
{
struct cs35l56_shared_test_priv *priv = test->priv;
struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
memset(cs35l56_base->onchip_spkid_gpios, 0, sizeof(cs35l56_base->onchip_spkid_gpios));
memset(cs35l56_base->onchip_spkid_pulls, 0, sizeof(cs35l56_base->onchip_spkid_pulls));
cs35l56_base->num_onchip_spkid_gpios = 0;
cs35l56_base->num_onchip_spkid_pulls = 0;
KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0);
KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), -ENOENT);
}
static int cs35l56_shared_test_case_regmap_init(struct kunit *test,
const struct regmap_config *regmap_config)
{
struct cs35l56_shared_test_priv *priv = test->priv;
struct cs35l56_base *cs35l56_base;
/*
* Create a dummy regmap to simulate a register map by holding the
* values of all simulated registers in the regmap cache.
*/
priv->registers = regmap_init(&priv->amp_dev->dev,
&cs35l56_shared_test_mock_registers_regmap_bus,
priv,
&cs35l56_shared_test_mock_registers_regmap);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->registers);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, regmap_exit_wrapper,
priv->registers));
regcache_cache_only(priv->registers, true);
/* Create dummy regmap for cs35l56 driver */
cs35l56_base = priv->cs35l56_base;
cs35l56_base->regmap = regmap_init(cs35l56_base->dev,
&cs35l56_shared_test_regmap_bus,
priv,
regmap_config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cs35l56_base->regmap);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, regmap_exit_wrapper,
cs35l56_base->regmap));
return 0;
}
static int cs35l56_shared_test_case_base_init(struct kunit *test, u8 type, u8 rev,
const struct regmap_config *regmap_config)
{
struct cs35l56_shared_test_priv *priv;
int ret;
KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks);
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
test->priv = priv;
priv->test = test;
/* Create dummy amp driver dev */
priv->amp_dev = faux_device_create("cs35l56_shared_test_drv", NULL, NULL);
KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test,
faux_device_destroy_wrapper,
priv->amp_dev));
priv->cs35l56_base = kunit_kzalloc(test, sizeof(*priv->cs35l56_base), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, priv->cs35l56_base);
priv->cs35l56_base->dev = &priv->amp_dev->dev;
priv->cs35l56_base->type = type;
priv->cs35l56_base->rev = rev;
if (regmap_config) {
ret = cs35l56_shared_test_case_regmap_init(test, regmap_config);
if (ret)
return ret;
}
return 0;
}
static int cs35l56_shared_test_case_regmap_init_L56_B0_sdw(struct kunit *test)
{
return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_sdw);
}
static int cs35l56_shared_test_case_regmap_init_L56_B0_spi(struct kunit *test)
{
return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_spi);
}
static int cs35l56_shared_test_case_regmap_init_L56_B0_i2c(struct kunit *test)
{
return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_i2c);
}
static int cs35l56_shared_test_case_regmap_init_L56_B2_sdw(struct kunit *test)
{
return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_sdw);
}
static int cs35l56_shared_test_case_regmap_init_L56_B2_spi(struct kunit *test)
{
return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_spi);
}
static int cs35l56_shared_test_case_regmap_init_L56_B2_i2c(struct kunit *test)
{
return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_i2c);
}
static int cs35l56_shared_test_case_regmap_init_L63_A1_sdw(struct kunit *test)
{
return cs35l56_shared_test_case_base_init(test, 0x63, 0xa1, &cs35l63_regmap_sdw);
}
static void cs35l56_shared_test_gpio_param_desc(const struct cs35l56_shared_test_param *param,
char *desc)
{
DECLARE_SEQ_BUF(gpios, 1 + (2 * ARRAY_SIZE(param->spkid_gpios)));
DECLARE_SEQ_BUF(pulls, 1 + (2 * ARRAY_SIZE(param->spkid_pulls)));
int i;
for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) {
if (param->spkid_gpios[i] < 0)
break;
seq_buf_printf(&gpios, "%s%d", (i == 0) ? "" : ",", param->spkid_gpios[i]);
}
for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) {
if (param->spkid_pulls[i] < 0)
break;
seq_buf_printf(&pulls, "%s%d", (i == 0) ? "" : ",", param->spkid_pulls[i]);
}
snprintf(desc, KUNIT_PARAM_DESC_SIZE, "gpios:{%s} pulls:{%s} status:%#lx spkid:%d",
seq_buf_str(&gpios), seq_buf_str(&pulls), param->gpio_status, param->spkid);
}
static const struct cs35l56_shared_test_param cs35l56_shared_test_gpios_selftest_cases[] = {
{ .spkid_gpios = { -1 }, .gpio_status = GENMASK(12, 0) },
};
KUNIT_ARRAY_PARAM(cs35l56_shared_test_gpios_selftest,
cs35l56_shared_test_gpios_selftest_cases,
cs35l56_shared_test_gpio_param_desc);
static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_spkid_cases[] = {
{ .spkid_gpios = { 1, -1 }, .gpio_status = 0, .spkid = 0 },
{ .spkid_gpios = { 1, -1 }, .gpio_status = ~BIT(0), .spkid = 0 },
{ .spkid_gpios = { 1, -1 }, .gpio_status = BIT(0), .spkid = 1 },
{ .spkid_gpios = { 7, -1 }, .gpio_status = 0, .spkid = 0 },
{ .spkid_gpios = { 7, -1 }, .gpio_status = ~BIT(6), .spkid = 0 },
{ .spkid_gpios = { 7, -1 }, .gpio_status = BIT(6), .spkid = 1 },
{ .spkid_gpios = { 1, 7, -1 }, .gpio_status = 0, .spkid = 0 },
{ .spkid_gpios = { 1, 7, -1 }, .gpio_status = ~(BIT(0) | BIT(6)), .spkid = 0 },
{ .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(6), .spkid = 1 },
{ .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(0), .spkid = 2 },
{ .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 },
{ .spkid_gpios = { 7, 1, -1 }, .gpio_status = 0, .spkid = 0 },
{ .spkid_gpios = { 7, 1, -1 }, .gpio_status = ~(BIT(6) | BIT(0)), .spkid = 0 },
{ .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(0), .spkid = 1 },
{ .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(6), .spkid = 2 },
{ .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = 0, .spkid = 0 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(0), .spkid = 1 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(6), .spkid = 2 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2), .spkid = 4 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(0), .spkid = 5 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(6), .spkid = 6 },
{ .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(6) | BIT(0), .spkid = 7 },
};
KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid, cs35l56_shared_test_onchip_spkid_cases,
cs35l56_shared_test_gpio_param_desc);
static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_spkid_pull_cases[] = {
{ .spkid_gpios = { 1, -1 }, .spkid_pulls = { 1, -1 }, },
{ .spkid_gpios = { 1, -1 }, .spkid_pulls = { 2, -1 }, },
{ .spkid_gpios = { 7, -1 }, .spkid_pulls = { 1, -1 }, },
{ .spkid_gpios = { 7, -1 }, .spkid_pulls = { 2, -1 }, },
{ .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 1, 1, -1 }, },
{ .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 2, 2, -1 }, },
{ .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 1, 1, -1 }, },
{ .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 2, 2, -1 }, },
{ .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 1, 1, 1, -1 }, },
{ .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 2, 2, 2, -1 }, },
};
KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid_pull,
cs35l56_shared_test_onchip_spkid_pull_cases,
cs35l56_shared_test_gpio_param_desc);
static struct kunit_case cs35l56_shared_test_cases[] = {
/* Tests for speaker id */
KUNIT_CASE_PARAM(cs35l56_shared_test_mock_gpio_status_selftest,
cs35l56_shared_test_gpios_selftest_gen_params),
KUNIT_CASE_PARAM(cs35l56_shared_test_get_onchip_speaker_id,
cs35l56_shared_test_onchip_spkid_gen_params),
KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config,
cs35l56_shared_test_onchip_spkid_gen_params),
KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config,
cs35l56_shared_test_onchip_spkid_pull_gen_params),
KUNIT_CASE_PARAM(cs35l56_shared_test_stash_onchip_spkid_pins,
cs35l56_shared_test_onchip_spkid_pull_gen_params),
KUNIT_CASE(cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid),
KUNIT_CASE(cs35l56_shared_test_onchip_speaker_id_not_defined),
{ }
};
static struct kunit_suite cs35l56_shared_test_suite_L56_B0_sdw = {
.name = "snd-soc-cs35l56-shared-test_L56_B0_sdw",
.init = cs35l56_shared_test_case_regmap_init_L56_B0_sdw,
.test_cases = cs35l56_shared_test_cases,
};
static struct kunit_suite cs35l56_shared_test_suite_L56_B2_sdw = {
.name = "snd-soc-cs35l56-shared-test_L56_B2_sdw",
.init = cs35l56_shared_test_case_regmap_init_L56_B2_sdw,
.test_cases = cs35l56_shared_test_cases,
};
static struct kunit_suite cs35l56_shared_test_suite_L63_A1_sdw = {
.name = "snd-soc-cs35l56-shared-test_L63_A1_sdw",
.init = cs35l56_shared_test_case_regmap_init_L63_A1_sdw,
.test_cases = cs35l56_shared_test_cases,
};
static struct kunit_suite cs35l56_shared_test_suite_L56_B0_spi = {
.name = "snd-soc-cs35l56-shared-test_L56_B0_spi",
.init = cs35l56_shared_test_case_regmap_init_L56_B0_spi,
.test_cases = cs35l56_shared_test_cases,
};
static struct kunit_suite cs35l56_shared_test_suite_L56_B2_spi = {
.name = "snd-soc-cs35l56-shared-test_L56_B2_spi",
.init = cs35l56_shared_test_case_regmap_init_L56_B2_spi,
.test_cases = cs35l56_shared_test_cases,
};
static struct kunit_suite cs35l56_shared_test_suite_L56_B0_i2c = {
.name = "snd-soc-cs35l56-shared-test_L56_B0_i2c",
.init = cs35l56_shared_test_case_regmap_init_L56_B0_i2c,
.test_cases = cs35l56_shared_test_cases,
};
static struct kunit_suite cs35l56_shared_test_suite_L56_B2_i2c = {
.name = "snd-soc-cs35l56-shared-test_L56_B2_i2c",
.init = cs35l56_shared_test_case_regmap_init_L56_B2_i2c,
.test_cases = cs35l56_shared_test_cases,
};
kunit_test_suites(
&cs35l56_shared_test_suite_L56_B0_sdw,
&cs35l56_shared_test_suite_L56_B2_sdw,
&cs35l56_shared_test_suite_L63_A1_sdw,
&cs35l56_shared_test_suite_L56_B0_spi,
&cs35l56_shared_test_suite_L56_B2_spi,
&cs35l56_shared_test_suite_L56_B0_i2c,
&cs35l56_shared_test_suite_L56_B2_i2c,
);
MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
MODULE_DESCRIPTION("KUnit test for cs35l56-shared module");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_LICENSE("GPL");

View File

@@ -5,6 +5,7 @@
// Copyright (C) 2023 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
#include <kunit/static_stub.h>
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/cleanup.h>
@@ -1630,6 +1631,8 @@ int cs35l56_configure_onchip_spkid_pads(struct cs35l56_base *cs35l56_base)
int num_gpios, num_pulls;
int i, ret;
KUNIT_STATIC_STUB_REDIRECT(cs35l56_configure_onchip_spkid_pads, cs35l56_base);
if (cs35l56_base->num_onchip_spkid_gpios == 0)
return 0;
@@ -1680,6 +1683,8 @@ int cs35l56_read_onchip_spkid(struct cs35l56_base *cs35l56_base)
int speaker_id = 0;
int i, ret;
KUNIT_STATIC_STUB_REDIRECT(cs35l56_read_onchip_spkid, cs35l56_base);
if (cs35l56_base->num_onchip_spkid_gpios == 0)
return -ENOENT;