Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: cs35l56: More support for new Dell laptops

Merge series from Richard Fitzgerald <rf@opensource.cirrus.com>:

Some new Dell models use spare pins on the amp as a binary integer
value to indicate the speaker type. The driver must use this to
select the correct firmware files for the hardware.

Patch #1 is the new support.
The other patches are for KUnit testing.

+1317 -4
+37
include/sound/cs35l56.h
··· 9 9 #ifndef __CS35L56_H 10 10 #define __CS35L56_H 11 11 12 + #include <linux/bits.h> 12 13 #include <linux/debugfs.h> 13 14 #include <linux/firmware/cirrus/cs_dsp.h> 14 15 #include <linux/regulator/consumer.h> ··· 27 26 #define CS35L56_GLOBAL_ENABLES 0x0002014 28 27 #define CS35L56_BLOCK_ENABLES 0x0002018 29 28 #define CS35L56_BLOCK_ENABLES2 0x000201C 29 + #define CS35L56_SYNC_GPIO1_CFG 0x0002410 30 + #define CS35L56_ASP2_DIO_GPIO13_CFG 0x0002440 31 + #define CS35L56_UPDATE_REGS 0x0002A0C 30 32 #define CS35L56_REFCLK_INPUT 0x0002C04 31 33 #define CS35L56_GLOBAL_SAMPLE_RATE 0x0002C0C 32 34 #define CS35L56_OTP_MEM_53 0x00300D4 ··· 69 65 #define CS35L56_IRQ1_MASK_8 0x000E0AC 70 66 #define CS35L56_IRQ1_MASK_18 0x000E0D4 71 67 #define CS35L56_IRQ1_MASK_20 0x000E0DC 68 + #define CS35L56_GPIO_STATUS1 0x000F000 69 + #define CS35L56_GPIO1_CTRL1 0x000F008 70 + #define CS35L56_GPIO13_CTRL1 0x000F038 72 71 #define CS35L56_MIXER_NGATE_CH1_CFG 0x0010004 73 72 #define CS35L56_MIXER_NGATE_CH2_CFG 0x0010008 74 73 #define CS35L56_DSP_MBOX_1_RAW 0x0011000 ··· 137 130 #define CS35L56_MTLREVID_MASK 0x0000000F 138 131 #define CS35L56_REVID_B0 0x000000B0 139 132 133 + /* PAD_INTF */ 134 + #define CS35L56_PAD_GPIO_PULL_MASK GENMASK(3, 2) 135 + #define CS35L56_PAD_GPIO_IE BIT(0) 136 + 137 + #define CS35L56_PAD_PULL_NONE 0 138 + #define CS35L56_PAD_PULL_UP 1 139 + #define CS35L56_PAD_PULL_DOWN 2 140 + 141 + /* UPDATE_REGS */ 142 + #define CS35L56_UPDT_GPIO_PRES BIT(6) 143 + 140 144 /* ASP_ENABLES1 */ 141 145 #define CS35L56_ASP_RX2_EN_SHIFT 17 142 146 #define CS35L56_ASP_RX1_EN_SHIFT 16 ··· 202 184 203 185 /* MIXER_NGATE_CHn_CFG */ 204 186 #define CS35L56_AUX_NGATE_CHn_EN 0x00000001 187 + 188 + /* GPIOn_CTRL1 */ 189 + #define CS35L56_GPIO_DIR_MASK BIT(31) 190 + #define CS35L56_GPIO_FN_MASK GENMASK(2, 0) 191 + 192 + #define CS35L56_GPIO_FN_GPIO 0x00000001 205 193 206 194 /* Mixer input sources */ 207 195 #define CS35L56_INPUT_SRC_NONE 0x00 ··· 303 279 #define CS35L56_HALO_STATE_TIMEOUT_US 250000 304 280 #define CS35L56_RESET_PULSE_MIN_US 1100 305 281 #define CS35L56_WAKE_HOLD_TIME_US 1000 282 + #define CS35L56_PAD_PULL_SETTLE_US 10 306 283 307 284 #define CS35L56_CALIBRATION_POLL_US (100 * USEC_PER_MSEC) 308 285 #define CS35L56_CALIBRATION_TIMEOUT_US (5 * USEC_PER_SEC) ··· 313 288 314 289 #define CS35L56_NUM_BULK_SUPPLIES 3 315 290 #define CS35L56_NUM_DSP_REGIONS 5 291 + 292 + #define CS35L56_MAX_GPIO 13 293 + #define CS35L63_MAX_GPIO 9 316 294 317 295 /* Additional margin for SYSTEM_RESET to control port ready on SPI */ 318 296 #define CS35L56_SPI_RESET_TO_PORT_READY_US (CS35L56_CONTROL_PORT_READY_US + 2500) ··· 366 338 const struct cirrus_amp_cal_controls *calibration_controls; 367 339 struct dentry *debugfs; 368 340 u64 silicon_uid; 341 + u8 onchip_spkid_gpios[5]; 342 + u8 num_onchip_spkid_gpios; 343 + u8 onchip_spkid_pulls[5]; 344 + u8 num_onchip_spkid_pulls; 369 345 }; 370 346 371 347 static inline bool cs35l56_is_otp_register(unsigned int reg) ··· 445 413 void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp); 446 414 int cs35l56_hw_init(struct cs35l56_base *cs35l56_base); 447 415 int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base); 416 + int cs35l56_check_and_save_onchip_spkid_gpios(struct cs35l56_base *cs35l56_base, 417 + const u32 *gpios, int num_gpios, 418 + const u32 *pulls, int num_pulls); 419 + int cs35l56_configure_onchip_spkid_pads(struct cs35l56_base *cs35l56_base); 420 + int cs35l56_read_onchip_spkid(struct cs35l56_base *cs35l56_base); 448 421 int cs35l56_get_bclk_freq_id(unsigned int freq); 449 422 void cs35l56_fill_supply_names(struct regulator_bulk_data *data); 450 423
+14
sound/soc/codecs/Kconfig
··· 936 936 help 937 937 This builds KUnit tests for the Cirrus Logic cs35l56 938 938 codec driver. 939 + 940 + For more information on KUnit and unit tests in general, 941 + please refer to the KUnit documentation in 942 + Documentation/dev-tools/kunit/. 943 + If in doubt, say "N". 944 + 945 + config SND_SOC_CS35L56_SHARED_TEST 946 + tristate "KUnit test for Cirrus Logic cs35l56-shared" if !KUNIT_ALL_TESTS 947 + depends on SND_SOC_CS35L56_SHARED && KUNIT 948 + default KUNIT_ALL_TESTS 949 + help 950 + This builds KUnit tests for the Cirrus Logic cs35l56-shared 951 + module. 952 + 939 953 For more information on KUnit and unit tests in general, 940 954 please refer to the KUnit documentation in 941 955 Documentation/dev-tools/kunit/.
+2
sound/soc/codecs/Makefile
··· 77 77 snd-soc-cs35l45-i2c-y := cs35l45-i2c.o 78 78 snd-soc-cs35l56-y := cs35l56.o 79 79 snd-soc-cs35l56-shared-y := cs35l56-shared.o 80 + snd-soc-cs35l56-shared-test-y := cs35l56-shared-test.o 80 81 snd-soc-cs35l56-i2c-y := cs35l56-i2c.o 81 82 snd-soc-cs35l56-spi-y := cs35l56-spi.o 82 83 snd-soc-cs35l56-sdw-y := cs35l56-sdw.o ··· 513 512 obj-$(CONFIG_SND_SOC_CS35L45_I2C) += snd-soc-cs35l45-i2c.o 514 513 obj-$(CONFIG_SND_SOC_CS35L56) += snd-soc-cs35l56.o 515 514 obj-$(CONFIG_SND_SOC_CS35L56_SHARED) += snd-soc-cs35l56-shared.o 515 + obj-$(CONFIG_SND_SOC_CS35L56_SHARED_TEST) += snd-soc-cs35l56-shared-test.o 516 516 obj-$(CONFIG_SND_SOC_CS35L56_I2C) += snd-soc-cs35l56-i2c.o 517 517 obj-$(CONFIG_SND_SOC_CS35L56_SPI) += snd-soc-cs35l56-spi.o 518 518 obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o
+680
sound/soc/codecs/cs35l56-shared-test.c
··· 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/module.h> 15 + #include <linux/random.h> 16 + #include <linux/regmap.h> 17 + #include <linux/seq_buf.h> 18 + #include <sound/cs35l56.h> 19 + 20 + struct cs35l56_shared_test_priv { 21 + struct kunit *test; 22 + struct faux_device *amp_dev; 23 + struct regmap *registers; 24 + struct cs35l56_base *cs35l56_base; 25 + u8 applied_pad_pull_state[CS35L56_MAX_GPIO]; 26 + }; 27 + 28 + struct cs35l56_shared_test_param { 29 + int spkid_gpios[4]; 30 + int spkid_pulls[4]; 31 + unsigned long gpio_status; 32 + int spkid; 33 + }; 34 + 35 + KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy, 36 + struct faux_device *) 37 + 38 + KUNIT_DEFINE_ACTION_WRAPPER(regmap_exit_wrapper, regmap_exit, struct regmap *) 39 + 40 + static const struct regmap_config cs35l56_shared_test_mock_registers_regmap = { 41 + .reg_bits = 32, 42 + .val_bits = 32, 43 + .reg_stride = 4, 44 + .max_register = CS35L56_DSP1_PMEM_5114, 45 + .cache_type = REGCACHE_MAPLE, 46 + }; 47 + 48 + static const struct regmap_bus cs35l56_shared_test_mock_registers_regmap_bus = { 49 + /* No handlers because it is always in cache-only */ 50 + }; 51 + 52 + static unsigned int cs35l56_shared_test_read_gpio_status(struct cs35l56_shared_test_priv *priv) 53 + { 54 + const struct cs35l56_shared_test_param *param = priv->test->param_value; 55 + unsigned int reg_offs, pad_cfg, val; 56 + unsigned int status = 0; 57 + unsigned int mask = 1; 58 + 59 + for (reg_offs = 0; reg_offs < CS35L56_MAX_GPIO * sizeof(u32); reg_offs += sizeof(u32)) { 60 + regmap_read(priv->registers, CS35L56_SYNC_GPIO1_CFG + reg_offs, &pad_cfg); 61 + regmap_read(priv->registers, CS35L56_GPIO1_CTRL1 + reg_offs, &val); 62 + 63 + /* Only read a value if set as an input pin and as a GPIO */ 64 + val &= (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_MASK); 65 + if ((pad_cfg & CS35L56_PAD_GPIO_IE) && 66 + (val == (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO))) 67 + status |= (param->gpio_status & mask); 68 + 69 + mask <<= 1; 70 + } 71 + 72 + return status; 73 + } 74 + 75 + static int cs35l56_shared_test_updt_gpio_pres(struct cs35l56_shared_test_priv *priv, 76 + unsigned int reg, unsigned int val) 77 + { 78 + int i, ret; 79 + 80 + ret = regmap_write(priv->registers, reg, val); 81 + if (ret) 82 + return ret; 83 + 84 + if (val & CS35L56_UPDT_GPIO_PRES) { 85 + /* Simulate transferring register state to internal latches */ 86 + for (i = 0; i < ARRAY_SIZE(priv->applied_pad_pull_state); i++) { 87 + reg = CS35L56_SYNC_GPIO1_CFG + (i * sizeof(u32)); 88 + regmap_read(priv->registers, reg, &val); 89 + val = FIELD_GET(CS35L56_PAD_GPIO_PULL_MASK, val); 90 + priv->applied_pad_pull_state[i] = val; 91 + } 92 + } 93 + 94 + return 0; 95 + } 96 + 97 + static int cs35l56_shared_test_reg_read(void *context, unsigned int reg, unsigned int *val) 98 + { 99 + struct cs35l56_shared_test_priv *priv = context; 100 + 101 + switch (reg) { 102 + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: 103 + case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1: 104 + return regmap_read(priv->registers, reg, val); 105 + case CS35L56_UPDATE_REGS: 106 + *val = 0; 107 + return 0; 108 + case CS35L56_GPIO_STATUS1: 109 + *val = cs35l56_shared_test_read_gpio_status(priv); 110 + return 0; 111 + default: 112 + kunit_fail_current_test("Bad regmap read address %#x\n", reg); 113 + return -EINVAL; 114 + } 115 + } 116 + 117 + static int cs35l56_shared_test_reg_write(void *context, unsigned int reg, unsigned int val) 118 + { 119 + struct cs35l56_shared_test_priv *priv = context; 120 + 121 + switch (reg) { 122 + case CS35L56_UPDATE_REGS: 123 + return cs35l56_shared_test_updt_gpio_pres(priv, reg, val); 124 + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: 125 + case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1: 126 + return regmap_write(priv->registers, reg, val); 127 + default: 128 + kunit_fail_current_test("Bad regmap write address %#x\n", reg); 129 + return -EINVAL; 130 + } 131 + } 132 + 133 + static const struct regmap_bus cs35l56_shared_test_regmap_bus = { 134 + .reg_read = cs35l56_shared_test_reg_read, 135 + .reg_write = cs35l56_shared_test_reg_write, 136 + .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, 137 + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, 138 + }; 139 + 140 + /* 141 + * Self-test that the mock GPIO registers obey the configuration bits. 142 + * Other tests rely on the mocked registers only returning a GPIO state 143 + * if the pin is correctly set as a GPIO input. 144 + */ 145 + static void cs35l56_shared_test_mock_gpio_status_selftest(struct kunit *test) 146 + { 147 + const struct cs35l56_shared_test_param *param = test->param_value; 148 + struct cs35l56_shared_test_priv *priv = test->priv; 149 + struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 150 + unsigned int reg, val; 151 + 152 + KUNIT_ASSERT_NOT_NULL(test, param); 153 + 154 + /* Set all pins non-GPIO and output. Mock GPIO_STATUS should read 0 */ 155 + for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 156 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 157 + 158 + /* Set all pads as inputs */ 159 + for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 160 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_PAD_GPIO_IE)); 161 + 162 + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 163 + KUNIT_EXPECT_EQ(test, val, 0); 164 + 165 + /* Set all pins as GPIO outputs. Mock GPIO_STATUS should read 0 */ 166 + for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 167 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO_FN_GPIO)); 168 + 169 + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 170 + KUNIT_EXPECT_EQ(test, val, 0); 171 + 172 + /* Set all pins as non-GPIO inputs. Mock GPIO_STATUS should read 0 */ 173 + for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 174 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO_DIR_MASK)); 175 + 176 + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 177 + KUNIT_EXPECT_EQ(test, val, 0); 178 + 179 + /* Set all pins as GPIO inputs. Mock GPIO_STATUS should match param->gpio_status */ 180 + for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 181 + KUNIT_ASSERT_EQ(test, 0, 182 + regmap_write(priv->registers, reg, 183 + CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO)); 184 + 185 + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 186 + KUNIT_EXPECT_EQ(test, val, param->gpio_status); 187 + 188 + /* Set all pads as outputs. Mock GPIO_STATUS should read 0 */ 189 + for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 190 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 191 + 192 + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_STATUS1, &val)); 193 + KUNIT_EXPECT_EQ(test, val, 0); 194 + } 195 + 196 + /* Test that the listed chip pins are assembled into a speaker ID integer. */ 197 + static void cs35l56_shared_test_get_onchip_speaker_id(struct kunit *test) 198 + { 199 + const struct cs35l56_shared_test_param *param = test->param_value; 200 + struct cs35l56_shared_test_priv *priv = test->priv; 201 + struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 202 + unsigned int i, reg; 203 + 204 + /* Set all pins non-GPIO and output */ 205 + for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 206 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 207 + 208 + for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 209 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 210 + 211 + /* Init GPIO array */ 212 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 213 + if (param->spkid_gpios[i] < 0) 214 + break; 215 + 216 + cs35l56_base->onchip_spkid_gpios[i] = param->spkid_gpios[i] - 1; 217 + cs35l56_base->num_onchip_spkid_gpios++; 218 + } 219 + 220 + cs35l56_base->num_onchip_spkid_pulls = 0; 221 + 222 + KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0); 223 + KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), param->spkid); 224 + } 225 + 226 + /* Test that the listed chip pins and the corresponding pads are configured correctly. */ 227 + static void cs35l56_shared_test_onchip_speaker_id_pad_config(struct kunit *test) 228 + { 229 + const struct cs35l56_shared_test_param *param = test->param_value; 230 + struct cs35l56_shared_test_priv *priv = test->priv; 231 + struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 232 + unsigned int i, reg, val; 233 + 234 + /* Init values in all pin registers */ 235 + for (reg = CS35L56_GPIO1_CTRL1; reg <= CS35L56_GPIO13_CTRL1; reg += sizeof(u32)) 236 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 237 + 238 + for (reg = CS35L56_SYNC_GPIO1_CFG; reg <= CS35L56_ASP2_DIO_GPIO13_CFG; reg += sizeof(u32)) 239 + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); 240 + 241 + /* Init GPIO array */ 242 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 243 + if (param->spkid_gpios[i] < 0) 244 + break; 245 + 246 + cs35l56_base->onchip_spkid_gpios[i] = param->spkid_gpios[i] - 1; 247 + cs35l56_base->num_onchip_spkid_gpios++; 248 + } 249 + 250 + /* Init pulls array */ 251 + for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 252 + if (param->spkid_pulls[i] < 0) 253 + break; 254 + 255 + cs35l56_base->onchip_spkid_pulls[i] = param->spkid_pulls[i]; 256 + cs35l56_base->num_onchip_spkid_pulls++; 257 + } 258 + 259 + KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0); 260 + 261 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 262 + if (param->spkid_gpios[i] < 0) 263 + break; 264 + 265 + /* Pad should be an input */ 266 + reg = CS35L56_SYNC_GPIO1_CFG + ((param->spkid_gpios[i] - 1) * sizeof(u32)); 267 + KUNIT_EXPECT_EQ(test, regmap_read(priv->registers, reg, &val), 0); 268 + KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_IE, CS35L56_PAD_GPIO_IE); 269 + 270 + /* Specified pulls should be set, others should be none */ 271 + if (i < cs35l56_base->num_onchip_spkid_pulls) { 272 + KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK, 273 + FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK, 274 + param->spkid_pulls[i])); 275 + } else { 276 + KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK, 277 + CS35L56_PAD_PULL_NONE); 278 + } 279 + 280 + /* Pulls for all specfied GPIOs should have been transferred to AO latch */ 281 + if (i < cs35l56_base->num_onchip_spkid_pulls) { 282 + KUNIT_EXPECT_EQ(test, 283 + priv->applied_pad_pull_state[param->spkid_gpios[i] - 1], 284 + param->spkid_pulls[i]); 285 + } else { 286 + KUNIT_EXPECT_EQ(test, 287 + priv->applied_pad_pull_state[param->spkid_gpios[i] - 1], 288 + CS35L56_PAD_PULL_NONE); 289 + } 290 + } 291 + } 292 + 293 + /* Test that the listed chip pins are stashed correctly. */ 294 + static void cs35l56_shared_test_stash_onchip_spkid_pins(struct kunit *test) 295 + { 296 + const struct cs35l56_shared_test_param *param = test->param_value; 297 + struct cs35l56_shared_test_priv *priv = test->priv; 298 + struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 299 + u32 gpios[5], pulls[5]; 300 + int i, num_gpios, num_pulls; 301 + 302 + static_assert(ARRAY_SIZE(gpios) >= ARRAY_SIZE(param->spkid_gpios)); 303 + static_assert(ARRAY_SIZE(pulls) >= ARRAY_SIZE(param->spkid_pulls)); 304 + 305 + num_gpios = 0; 306 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 307 + if (param->spkid_gpios[i] < 0) 308 + break; 309 + 310 + gpios[i] = (u32)param->spkid_gpios[i]; 311 + num_gpios++; 312 + } 313 + 314 + num_pulls = 0; 315 + for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 316 + if (param->spkid_pulls[i] < 0) 317 + break; 318 + 319 + pulls[i] = (u32)param->spkid_pulls[i]; 320 + num_pulls++; 321 + } 322 + 323 + cs35l56_base->num_onchip_spkid_gpios = 0; 324 + cs35l56_base->num_onchip_spkid_pulls = 0; 325 + 326 + KUNIT_ASSERT_LE(test, num_gpios, ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); 327 + KUNIT_ASSERT_LE(test, num_pulls, ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls)); 328 + 329 + KUNIT_EXPECT_EQ(test, 330 + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 331 + gpios, num_gpios, 332 + pulls, num_pulls), 333 + 0); 334 + 335 + KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_gpios, num_gpios); 336 + KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_pulls, num_pulls); 337 + 338 + /* GPIO numbers are adjusted from 1-based to 0-based */ 339 + for (i = 0; i < num_gpios; i++) 340 + KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_gpios[i], gpios[i] - 1); 341 + 342 + for (i = 0; i < num_pulls; i++) 343 + KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_pulls[i], pulls[i]); 344 + } 345 + 346 + /* Test that illegal GPIO numbers are rejected. */ 347 + static void cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid(struct kunit *test) 348 + { 349 + struct cs35l56_shared_test_priv *priv = test->priv; 350 + struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 351 + u32 gpios[8] = { }, pulls[8] = { }; 352 + 353 + KUNIT_EXPECT_LE(test, 354 + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 355 + gpios, 1, 356 + pulls, 0), 357 + 0); 358 + 359 + switch (cs35l56_base->type) { 360 + case 0x54: 361 + case 0x56: 362 + case 0x57: 363 + gpios[0] = CS35L56_MAX_GPIO + 1; 364 + break; 365 + case 0x63: 366 + gpios[0] = CS35L63_MAX_GPIO + 1; 367 + break; 368 + default: 369 + kunit_fail_current_test("Unsupported type:%#x\n", cs35l56_base->type); 370 + return; 371 + } 372 + KUNIT_EXPECT_LE(test, 373 + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 374 + gpios, 1, 375 + pulls, 0), 376 + 0); 377 + 378 + gpios[0] = 1; 379 + pulls[0] = 3; 380 + KUNIT_EXPECT_LE(test, 381 + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 382 + gpios, 1, 383 + pulls, 1), 384 + 0); 385 + 386 + static_assert(ARRAY_SIZE(gpios) > ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); 387 + static_assert(ARRAY_SIZE(pulls) > ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls)); 388 + KUNIT_EXPECT_EQ(test, 389 + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 390 + gpios, ARRAY_SIZE(gpios), 391 + pulls, 0), 392 + -EOVERFLOW); 393 + KUNIT_EXPECT_EQ(test, 394 + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, 395 + gpios, 1, 396 + pulls, ARRAY_SIZE(pulls)), 397 + -EOVERFLOW); 398 + } 399 + 400 + static void cs35l56_shared_test_onchip_speaker_id_not_defined(struct kunit *test) 401 + { 402 + struct cs35l56_shared_test_priv *priv = test->priv; 403 + struct cs35l56_base *cs35l56_base = priv->cs35l56_base; 404 + 405 + memset(cs35l56_base->onchip_spkid_gpios, 0, sizeof(cs35l56_base->onchip_spkid_gpios)); 406 + memset(cs35l56_base->onchip_spkid_pulls, 0, sizeof(cs35l56_base->onchip_spkid_pulls)); 407 + cs35l56_base->num_onchip_spkid_gpios = 0; 408 + cs35l56_base->num_onchip_spkid_pulls = 0; 409 + KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), 0); 410 + KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), -ENOENT); 411 + } 412 + 413 + static int cs35l56_shared_test_case_regmap_init(struct kunit *test, 414 + const struct regmap_config *regmap_config) 415 + { 416 + struct cs35l56_shared_test_priv *priv = test->priv; 417 + struct cs35l56_base *cs35l56_base; 418 + 419 + /* 420 + * Create a dummy regmap to simulate a register map by holding the 421 + * values of all simulated registers in the regmap cache. 422 + */ 423 + priv->registers = regmap_init(&priv->amp_dev->dev, 424 + &cs35l56_shared_test_mock_registers_regmap_bus, 425 + priv, 426 + &cs35l56_shared_test_mock_registers_regmap); 427 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->registers); 428 + KUNIT_ASSERT_EQ(test, 0, 429 + kunit_add_action_or_reset(test, regmap_exit_wrapper, 430 + priv->registers)); 431 + regcache_cache_only(priv->registers, true); 432 + 433 + /* Create dummy regmap for cs35l56 driver */ 434 + cs35l56_base = priv->cs35l56_base; 435 + cs35l56_base->regmap = regmap_init(cs35l56_base->dev, 436 + &cs35l56_shared_test_regmap_bus, 437 + priv, 438 + regmap_config); 439 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cs35l56_base->regmap); 440 + KUNIT_ASSERT_EQ(test, 0, 441 + kunit_add_action_or_reset(test, regmap_exit_wrapper, 442 + cs35l56_base->regmap)); 443 + 444 + return 0; 445 + } 446 + 447 + static int cs35l56_shared_test_case_base_init(struct kunit *test, u8 type, u8 rev, 448 + const struct regmap_config *regmap_config) 449 + { 450 + struct cs35l56_shared_test_priv *priv; 451 + int ret; 452 + 453 + KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks); 454 + 455 + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 456 + if (!priv) 457 + return -ENOMEM; 458 + 459 + test->priv = priv; 460 + priv->test = test; 461 + 462 + /* Create dummy amp driver dev */ 463 + priv->amp_dev = faux_device_create("cs35l56_shared_test_drv", NULL, NULL); 464 + KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev); 465 + KUNIT_ASSERT_EQ(test, 0, 466 + kunit_add_action_or_reset(test, 467 + faux_device_destroy_wrapper, 468 + priv->amp_dev)); 469 + 470 + priv->cs35l56_base = kunit_kzalloc(test, sizeof(*priv->cs35l56_base), GFP_KERNEL); 471 + KUNIT_ASSERT_NOT_NULL(test, priv->cs35l56_base); 472 + priv->cs35l56_base->dev = &priv->amp_dev->dev; 473 + priv->cs35l56_base->type = type; 474 + priv->cs35l56_base->rev = rev; 475 + 476 + if (regmap_config) { 477 + ret = cs35l56_shared_test_case_regmap_init(test, regmap_config); 478 + if (ret) 479 + return ret; 480 + } 481 + 482 + return 0; 483 + } 484 + 485 + static int cs35l56_shared_test_case_regmap_init_L56_B0_sdw(struct kunit *test) 486 + { 487 + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_sdw); 488 + } 489 + 490 + static int cs35l56_shared_test_case_regmap_init_L56_B0_spi(struct kunit *test) 491 + { 492 + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_spi); 493 + } 494 + 495 + static int cs35l56_shared_test_case_regmap_init_L56_B0_i2c(struct kunit *test) 496 + { 497 + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regmap_i2c); 498 + } 499 + 500 + static int cs35l56_shared_test_case_regmap_init_L56_B2_sdw(struct kunit *test) 501 + { 502 + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_sdw); 503 + } 504 + 505 + static int cs35l56_shared_test_case_regmap_init_L56_B2_spi(struct kunit *test) 506 + { 507 + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_spi); 508 + } 509 + 510 + static int cs35l56_shared_test_case_regmap_init_L56_B2_i2c(struct kunit *test) 511 + { 512 + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regmap_i2c); 513 + } 514 + 515 + static int cs35l56_shared_test_case_regmap_init_L63_A1_sdw(struct kunit *test) 516 + { 517 + return cs35l56_shared_test_case_base_init(test, 0x63, 0xa1, &cs35l63_regmap_sdw); 518 + } 519 + 520 + static void cs35l56_shared_test_gpio_param_desc(const struct cs35l56_shared_test_param *param, 521 + char *desc) 522 + { 523 + DECLARE_SEQ_BUF(gpios, 1 + (2 * ARRAY_SIZE(param->spkid_gpios))); 524 + DECLARE_SEQ_BUF(pulls, 1 + (2 * ARRAY_SIZE(param->spkid_pulls))); 525 + int i; 526 + 527 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 528 + if (param->spkid_gpios[i] < 0) 529 + break; 530 + 531 + seq_buf_printf(&gpios, "%s%d", (i == 0) ? "" : ",", param->spkid_gpios[i]); 532 + } 533 + 534 + for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 535 + if (param->spkid_pulls[i] < 0) 536 + break; 537 + 538 + seq_buf_printf(&pulls, "%s%d", (i == 0) ? "" : ",", param->spkid_pulls[i]); 539 + } 540 + 541 + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "gpios:{%s} pulls:{%s} status:%#lx spkid:%d", 542 + seq_buf_str(&gpios), seq_buf_str(&pulls), param->gpio_status, param->spkid); 543 + } 544 + 545 + static const struct cs35l56_shared_test_param cs35l56_shared_test_gpios_selftest_cases[] = { 546 + { .spkid_gpios = { -1 }, .gpio_status = GENMASK(12, 0) }, 547 + }; 548 + KUNIT_ARRAY_PARAM(cs35l56_shared_test_gpios_selftest, 549 + cs35l56_shared_test_gpios_selftest_cases, 550 + cs35l56_shared_test_gpio_param_desc); 551 + 552 + static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_spkid_cases[] = { 553 + { .spkid_gpios = { 1, -1 }, .gpio_status = 0, .spkid = 0 }, 554 + { .spkid_gpios = { 1, -1 }, .gpio_status = ~BIT(0), .spkid = 0 }, 555 + { .spkid_gpios = { 1, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 556 + 557 + { .spkid_gpios = { 7, -1 }, .gpio_status = 0, .spkid = 0 }, 558 + { .spkid_gpios = { 7, -1 }, .gpio_status = ~BIT(6), .spkid = 0 }, 559 + { .spkid_gpios = { 7, -1 }, .gpio_status = BIT(6), .spkid = 1 }, 560 + 561 + { .spkid_gpios = { 1, 7, -1 }, .gpio_status = 0, .spkid = 0 }, 562 + { .spkid_gpios = { 1, 7, -1 }, .gpio_status = ~(BIT(0) | BIT(6)), .spkid = 0 }, 563 + { .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(6), .spkid = 1 }, 564 + { .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(0), .spkid = 2 }, 565 + { .spkid_gpios = { 1, 7, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 566 + 567 + { .spkid_gpios = { 7, 1, -1 }, .gpio_status = 0, .spkid = 0 }, 568 + { .spkid_gpios = { 7, 1, -1 }, .gpio_status = ~(BIT(6) | BIT(0)), .spkid = 0 }, 569 + { .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 570 + { .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(6), .spkid = 2 }, 571 + { .spkid_gpios = { 7, 1, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 572 + 573 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = 0, .spkid = 0 }, 574 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(0), .spkid = 1 }, 575 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(6), .spkid = 2 }, 576 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 }, 577 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2), .spkid = 4 }, 578 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(0), .spkid = 5 }, 579 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(6), .spkid = 6 }, 580 + { .spkid_gpios = { 3, 7, 1, -1 }, .gpio_status = BIT(2) | BIT(6) | BIT(0), .spkid = 7 }, 581 + }; 582 + KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid, cs35l56_shared_test_onchip_spkid_cases, 583 + cs35l56_shared_test_gpio_param_desc); 584 + 585 + static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_spkid_pull_cases[] = { 586 + { .spkid_gpios = { 1, -1 }, .spkid_pulls = { 1, -1 }, }, 587 + { .spkid_gpios = { 1, -1 }, .spkid_pulls = { 2, -1 }, }, 588 + 589 + { .spkid_gpios = { 7, -1 }, .spkid_pulls = { 1, -1 }, }, 590 + { .spkid_gpios = { 7, -1 }, .spkid_pulls = { 2, -1 }, }, 591 + 592 + { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 1, 1, -1 }, }, 593 + { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 2, 2, -1 }, }, 594 + 595 + { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 1, 1, -1 }, }, 596 + { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 2, 2, -1 }, }, 597 + 598 + { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 1, 1, 1, -1 }, }, 599 + { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 2, 2, 2, -1 }, }, 600 + }; 601 + KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid_pull, 602 + cs35l56_shared_test_onchip_spkid_pull_cases, 603 + cs35l56_shared_test_gpio_param_desc); 604 + 605 + static struct kunit_case cs35l56_shared_test_cases[] = { 606 + /* Tests for speaker id */ 607 + KUNIT_CASE_PARAM(cs35l56_shared_test_mock_gpio_status_selftest, 608 + cs35l56_shared_test_gpios_selftest_gen_params), 609 + KUNIT_CASE_PARAM(cs35l56_shared_test_get_onchip_speaker_id, 610 + cs35l56_shared_test_onchip_spkid_gen_params), 611 + KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config, 612 + cs35l56_shared_test_onchip_spkid_gen_params), 613 + KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config, 614 + cs35l56_shared_test_onchip_spkid_pull_gen_params), 615 + KUNIT_CASE_PARAM(cs35l56_shared_test_stash_onchip_spkid_pins, 616 + cs35l56_shared_test_onchip_spkid_pull_gen_params), 617 + KUNIT_CASE(cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid), 618 + KUNIT_CASE(cs35l56_shared_test_onchip_speaker_id_not_defined), 619 + { } 620 + }; 621 + 622 + static struct kunit_suite cs35l56_shared_test_suite_L56_B0_sdw = { 623 + .name = "snd-soc-cs35l56-shared-test_L56_B0_sdw", 624 + .init = cs35l56_shared_test_case_regmap_init_L56_B0_sdw, 625 + .test_cases = cs35l56_shared_test_cases, 626 + }; 627 + 628 + static struct kunit_suite cs35l56_shared_test_suite_L56_B2_sdw = { 629 + .name = "snd-soc-cs35l56-shared-test_L56_B2_sdw", 630 + .init = cs35l56_shared_test_case_regmap_init_L56_B2_sdw, 631 + .test_cases = cs35l56_shared_test_cases, 632 + }; 633 + 634 + static struct kunit_suite cs35l56_shared_test_suite_L63_A1_sdw = { 635 + .name = "snd-soc-cs35l56-shared-test_L63_A1_sdw", 636 + .init = cs35l56_shared_test_case_regmap_init_L63_A1_sdw, 637 + .test_cases = cs35l56_shared_test_cases, 638 + }; 639 + 640 + static struct kunit_suite cs35l56_shared_test_suite_L56_B0_spi = { 641 + .name = "snd-soc-cs35l56-shared-test_L56_B0_spi", 642 + .init = cs35l56_shared_test_case_regmap_init_L56_B0_spi, 643 + .test_cases = cs35l56_shared_test_cases, 644 + }; 645 + 646 + static struct kunit_suite cs35l56_shared_test_suite_L56_B2_spi = { 647 + .name = "snd-soc-cs35l56-shared-test_L56_B2_spi", 648 + .init = cs35l56_shared_test_case_regmap_init_L56_B2_spi, 649 + .test_cases = cs35l56_shared_test_cases, 650 + }; 651 + 652 + static struct kunit_suite cs35l56_shared_test_suite_L56_B0_i2c = { 653 + .name = "snd-soc-cs35l56-shared-test_L56_B0_i2c", 654 + .init = cs35l56_shared_test_case_regmap_init_L56_B0_i2c, 655 + .test_cases = cs35l56_shared_test_cases, 656 + }; 657 + 658 + static struct kunit_suite cs35l56_shared_test_suite_L56_B2_i2c = { 659 + .name = "snd-soc-cs35l56-shared-test_L56_B2_i2c", 660 + .init = cs35l56_shared_test_case_regmap_init_L56_B2_i2c, 661 + .test_cases = cs35l56_shared_test_cases, 662 + }; 663 + 664 + kunit_test_suites( 665 + &cs35l56_shared_test_suite_L56_B0_sdw, 666 + &cs35l56_shared_test_suite_L56_B2_sdw, 667 + &cs35l56_shared_test_suite_L63_A1_sdw, 668 + 669 + &cs35l56_shared_test_suite_L56_B0_spi, 670 + &cs35l56_shared_test_suite_L56_B2_spi, 671 + 672 + &cs35l56_shared_test_suite_L56_B0_i2c, 673 + &cs35l56_shared_test_suite_L56_B2_i2c, 674 + ); 675 + 676 + MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); 677 + MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); 678 + MODULE_DESCRIPTION("KUnit test for cs35l56-shared module"); 679 + MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); 680 + MODULE_LICENSE("GPL");
+172
sound/soc/codecs/cs35l56-shared.c
··· 5 5 // Copyright (C) 2023 Cirrus Logic, Inc. and 6 6 // Cirrus Logic International Semiconductor Ltd. 7 7 8 + #include <kunit/static_stub.h> 8 9 #include <linux/array_size.h> 10 + #include <linux/bitfield.h> 9 11 #include <linux/cleanup.h> 10 12 #include <linux/debugfs.h> 11 13 #include <linux/firmware/cirrus/wmfw.h> 12 14 #include <linux/fs.h> 13 15 #include <linux/gpio/consumer.h> 14 16 #include <linux/kstrtox.h> 17 + #include <linux/pm_runtime.h> 15 18 #include <linux/regmap.h> 16 19 #include <linux/regulator/consumer.h> 17 20 #include <linux/spi/spi.h> ··· 185 182 case CS35L56_OTP_MEM_53: 186 183 case CS35L56_OTP_MEM_54: 187 184 case CS35L56_OTP_MEM_55: 185 + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: 186 + case CS35L56_UPDATE_REGS: 188 187 case CS35L56_ASP1_ENABLES1: 189 188 case CS35L56_ASP1_CONTROL1: 190 189 case CS35L56_ASP1_CONTROL2: ··· 218 213 case CS35L56_IRQ1_MASK_8: 219 214 case CS35L56_IRQ1_MASK_18: 220 215 case CS35L56_IRQ1_MASK_20: 216 + case CS35L56_GPIO_STATUS1 ... CS35L56_GPIO13_CTRL1: 221 217 case CS35L56_MIXER_NGATE_CH1_CFG: 222 218 case CS35L56_MIXER_NGATE_CH2_CFG: 223 219 case CS35L56_DSP_VIRTUAL1_MBOX_1: ··· 268 262 case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ 269 263 case CS35L56_BLOCK_ENABLES: /* owned by firmware */ 270 264 case CS35L56_BLOCK_ENABLES2: /* owned by firmware */ 265 + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: 266 + case CS35L56_UPDATE_REGS: 271 267 case CS35L56_REFCLK_INPUT: /* owned by firmware */ 272 268 case CS35L56_GLOBAL_SAMPLE_RATE: /* owned by firmware */ 273 269 case CS35L56_DACPCM1_INPUT: /* owned by firmware */ ··· 280 272 case CS35L56_IRQ1_EINT_1 ... CS35L56_IRQ1_EINT_8: 281 273 case CS35L56_IRQ1_EINT_18: 282 274 case CS35L56_IRQ1_EINT_20: 275 + case CS35L56_GPIO_STATUS1 ... CS35L56_GPIO13_CTRL1: 283 276 case CS35L56_MIXER_NGATE_CH1_CFG: 284 277 case CS35L56_MIXER_NGATE_CH2_CFG: 285 278 case CS35L56_DSP_VIRTUAL1_MBOX_1: ··· 1560 1551 return ret; 1561 1552 } 1562 1553 EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, "SND_SOC_CS35L56_SHARED"); 1554 + 1555 + int cs35l56_check_and_save_onchip_spkid_gpios(struct cs35l56_base *cs35l56_base, 1556 + const u32 *gpios, int num_gpios, 1557 + const u32 *pulls, int num_pulls) 1558 + { 1559 + int max_gpio; 1560 + int ret = 0; 1561 + int i; 1562 + 1563 + if ((num_gpios > ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)) || 1564 + (num_pulls > ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls))) 1565 + return -EOVERFLOW; 1566 + 1567 + switch (cs35l56_base->type) { 1568 + case 0x54: 1569 + case 0x56: 1570 + case 0x57: 1571 + max_gpio = CS35L56_MAX_GPIO; 1572 + break; 1573 + default: 1574 + max_gpio = CS35L63_MAX_GPIO; 1575 + break; 1576 + } 1577 + 1578 + for (i = 0; i < num_gpios; i++) { 1579 + if (gpios[i] < 1 || gpios[i] > max_gpio) { 1580 + dev_err(cs35l56_base->dev, "Invalid spkid GPIO %d\n", gpios[i]); 1581 + /* Keep going so we log all bad values */ 1582 + ret = -EINVAL; 1583 + } 1584 + 1585 + /* Change to zero-based */ 1586 + cs35l56_base->onchip_spkid_gpios[i] = gpios[i] - 1; 1587 + } 1588 + 1589 + for (i = 0; i < num_pulls; i++) { 1590 + switch (pulls[i]) { 1591 + case 0: 1592 + cs35l56_base->onchip_spkid_pulls[i] = CS35L56_PAD_PULL_NONE; 1593 + break; 1594 + case 1: 1595 + cs35l56_base->onchip_spkid_pulls[i] = CS35L56_PAD_PULL_UP; 1596 + break; 1597 + case 2: 1598 + cs35l56_base->onchip_spkid_pulls[i] = CS35L56_PAD_PULL_DOWN; 1599 + break; 1600 + default: 1601 + dev_err(cs35l56_base->dev, "Invalid spkid pull %d\n", pulls[i]); 1602 + /* Keep going so we log all bad values */ 1603 + ret = -EINVAL; 1604 + break; 1605 + } 1606 + } 1607 + if (ret) 1608 + return ret; 1609 + 1610 + cs35l56_base->num_onchip_spkid_gpios = num_gpios; 1611 + cs35l56_base->num_onchip_spkid_pulls = num_pulls; 1612 + 1613 + return 0; 1614 + } 1615 + EXPORT_SYMBOL_NS_GPL(cs35l56_check_and_save_onchip_spkid_gpios, "SND_SOC_CS35L56_SHARED"); 1616 + 1617 + /* Caller must pm_runtime resume before calling this function */ 1618 + int cs35l56_configure_onchip_spkid_pads(struct cs35l56_base *cs35l56_base) 1619 + { 1620 + struct regmap *regmap = cs35l56_base->regmap; 1621 + unsigned int addr_offset, val; 1622 + int num_gpios, num_pulls; 1623 + int i, ret; 1624 + 1625 + KUNIT_STATIC_STUB_REDIRECT(cs35l56_configure_onchip_spkid_pads, cs35l56_base); 1626 + 1627 + if (cs35l56_base->num_onchip_spkid_gpios == 0) 1628 + return 0; 1629 + 1630 + num_gpios = min(cs35l56_base->num_onchip_spkid_gpios, 1631 + ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); 1632 + num_pulls = min(cs35l56_base->num_onchip_spkid_pulls, 1633 + ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls)); 1634 + 1635 + for (i = 0; i < num_gpios; i++) { 1636 + addr_offset = cs35l56_base->onchip_spkid_gpios[i] * sizeof(u32); 1637 + 1638 + /* Set unspecified pulls to NONE */ 1639 + if (i < num_pulls) { 1640 + val = FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK, 1641 + cs35l56_base->onchip_spkid_pulls[i]); 1642 + } else { 1643 + val = FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK, CS35L56_PAD_PULL_NONE); 1644 + } 1645 + 1646 + ret = regmap_update_bits(regmap, CS35L56_SYNC_GPIO1_CFG + addr_offset, 1647 + CS35L56_PAD_GPIO_PULL_MASK | CS35L56_PAD_GPIO_IE, 1648 + val | CS35L56_PAD_GPIO_IE); 1649 + if (ret) { 1650 + dev_err(cs35l56_base->dev, "GPIO%d set pad fail: %d\n", 1651 + cs35l56_base->onchip_spkid_gpios[i] + 1, ret); 1652 + return ret; 1653 + } 1654 + } 1655 + 1656 + ret = regmap_write(regmap, CS35L56_UPDATE_REGS, CS35L56_UPDT_GPIO_PRES); 1657 + if (ret) { 1658 + dev_err(cs35l56_base->dev, "UPDT_GPIO_PRES failed:%d\n", ret); 1659 + return ret; 1660 + } 1661 + 1662 + usleep_range(CS35L56_PAD_PULL_SETTLE_US, CS35L56_PAD_PULL_SETTLE_US * 2); 1663 + 1664 + return 0; 1665 + } 1666 + EXPORT_SYMBOL_NS_GPL(cs35l56_configure_onchip_spkid_pads, "SND_SOC_CS35L56_SHARED"); 1667 + 1668 + /* Caller must pm_runtime resume before calling this function */ 1669 + int cs35l56_read_onchip_spkid(struct cs35l56_base *cs35l56_base) 1670 + { 1671 + struct regmap *regmap = cs35l56_base->regmap; 1672 + unsigned int addr_offset, val; 1673 + int num_gpios; 1674 + int speaker_id = 0; 1675 + int i, ret; 1676 + 1677 + KUNIT_STATIC_STUB_REDIRECT(cs35l56_read_onchip_spkid, cs35l56_base); 1678 + 1679 + if (cs35l56_base->num_onchip_spkid_gpios == 0) 1680 + return -ENOENT; 1681 + 1682 + num_gpios = min(cs35l56_base->num_onchip_spkid_gpios, 1683 + ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); 1684 + 1685 + for (i = 0; i < num_gpios; i++) { 1686 + addr_offset = cs35l56_base->onchip_spkid_gpios[i] * sizeof(u32); 1687 + 1688 + ret = regmap_update_bits(regmap, CS35L56_GPIO1_CTRL1 + addr_offset, 1689 + CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_MASK, 1690 + CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO); 1691 + if (ret) { 1692 + dev_err(cs35l56_base->dev, "GPIO%u set func fail: %d\n", 1693 + cs35l56_base->onchip_spkid_gpios[i] + 1, ret); 1694 + return ret; 1695 + } 1696 + } 1697 + 1698 + ret = regmap_read(regmap, CS35L56_GPIO_STATUS1, &val); 1699 + if (ret) { 1700 + dev_err(cs35l56_base->dev, "GPIO%d status read failed: %d\n", 1701 + cs35l56_base->onchip_spkid_gpios[i] + 1, ret); 1702 + return ret; 1703 + } 1704 + 1705 + for (i = 0; i < num_gpios; i++) { 1706 + speaker_id <<= 1; 1707 + 1708 + if (val & BIT(cs35l56_base->onchip_spkid_gpios[i])) 1709 + speaker_id |= 1; 1710 + } 1711 + 1712 + dev_dbg(cs35l56_base->dev, "Onchip GPIO Speaker ID = %d\n", speaker_id); 1713 + 1714 + return speaker_id; 1715 + } 1716 + EXPORT_SYMBOL_NS_GPL(cs35l56_read_onchip_spkid, "SND_SOC_CS35L56_SHARED"); 1563 1717 1564 1718 static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = { 1565 1719 [0x0C] = 128000,
+273
sound/soc/codecs/cs35l56-test.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/overflow.h> 17 17 #include <linux/pci_ids.h> 18 + #include <linux/property.h> 19 + #include <linux/seq_buf.h> 18 20 #include <linux/soundwire/sdw.h> 19 21 #include <sound/cs35l56.h> 20 22 #include <sound/cs-amp-lib.h> ··· 25 23 KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy, 26 24 struct faux_device *) 27 25 26 + KUNIT_DEFINE_ACTION_WRAPPER(software_node_unregister_node_group_wrapper, 27 + software_node_unregister_node_group, 28 + const struct software_node * const *) 29 + 30 + KUNIT_DEFINE_ACTION_WRAPPER(software_node_unregister_wrapper, 31 + software_node_unregister, 32 + const struct software_node *) 33 + 34 + KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper, 35 + device_remove_software_node, 36 + struct device *) 37 + 28 38 struct cs35l56_test_priv { 29 39 struct faux_device *amp_dev; 30 40 struct cs35l56_private *cs35l56_priv; 31 41 32 42 const char *ssidexv2; 43 + 44 + bool read_onchip_spkid_called; 45 + bool configure_onchip_spkid_pads_called; 33 46 }; 34 47 35 48 struct cs35l56_test_param { 36 49 u8 type; 37 50 u8 rev; 51 + 52 + s32 spkid_gpios[4]; 53 + s32 spkid_pulls[4]; 54 + }; 55 + 56 + static const struct software_node cs35l56_test_dev_sw_node = 57 + SOFTWARE_NODE("SWD1", NULL, NULL); 58 + 59 + static const struct software_node cs35l56_test_af01_sw_node = 60 + SOFTWARE_NODE("AF01", NULL, &cs35l56_test_dev_sw_node); 61 + 62 + static const struct software_node *cs35l56_test_dev_and_af01_node_group[] = { 63 + &cs35l56_test_dev_sw_node, 64 + &cs35l56_test_af01_sw_node, 65 + NULL 38 66 }; 39 67 40 68 static const char *cs35l56_test_devm_get_vendor_specific_variant_id_none(struct device *dev, ··· 264 232 KUNIT_EXPECT_STREQ(test, cs35l56->fallback_fw_suffix, "l1u5"); 265 233 } 266 234 235 + /* 236 + * Test that cs35l56_process_xu_properties() correctly parses the GPIO and 237 + * pull values from properties into the arrays in struct cs35l56_base. 238 + * 239 + * This test creates the node tree: 240 + * 241 + * Node("SWD1") { // top-level device node 242 + * Node("AF01") { 243 + * Node("mipi-sdca-function-expansion-subproperties") { 244 + * property: "01fa-spk-id-gpios-onchip" 245 + * property: 01fa-spk-id-gpios-onchip-pull 246 + * } 247 + * } 248 + * } 249 + * 250 + * Note that in ACPI "mipi-sdca-function-expansion-subproperties" is 251 + * a special _DSD property that points to a Device(EXT0) node but behaves 252 + * as an alias of the EXT0 node. The equivalent in software nodes is to 253 + * create a Node named "mipi-sdca-function-expansion-subproperties" with 254 + * the properties. 255 + * 256 + */ 257 + static void cs35l56_test_parse_xu_onchip_spkid(struct kunit *test) 258 + { 259 + const struct cs35l56_test_param *param = test->param_value; 260 + struct cs35l56_test_priv *priv = test->priv; 261 + struct cs35l56_private *cs35l56 = priv->cs35l56_priv; 262 + struct software_node *ext0_node; 263 + int num_gpios = 0; 264 + int num_pulls = 0; 265 + int i; 266 + 267 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++, num_gpios++) { 268 + if (param->spkid_gpios[i] < 0) 269 + break; 270 + } 271 + KUNIT_ASSERT_LE(test, num_gpios, ARRAY_SIZE(cs35l56->base.onchip_spkid_gpios)); 272 + 273 + for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++, num_pulls++) { 274 + if (param->spkid_pulls[i] < 0) 275 + break; 276 + } 277 + KUNIT_ASSERT_LE(test, num_pulls, ARRAY_SIZE(cs35l56->base.onchip_spkid_pulls)); 278 + 279 + const struct property_entry ext0_props[] = { 280 + PROPERTY_ENTRY_U32_ARRAY_LEN("01fa-spk-id-gpios-onchip", 281 + param->spkid_gpios, num_gpios), 282 + PROPERTY_ENTRY_U32_ARRAY_LEN("01fa-spk-id-gpios-onchip-pull", 283 + param->spkid_pulls, num_pulls), 284 + { } 285 + }; 286 + 287 + KUNIT_ASSERT_EQ(test, 288 + software_node_register_node_group(cs35l56_test_dev_and_af01_node_group), 289 + 0); 290 + KUNIT_ASSERT_EQ(test, 291 + kunit_add_action_or_reset(test, 292 + software_node_unregister_node_group_wrapper, 293 + cs35l56_test_dev_and_af01_node_group), 294 + 0); 295 + 296 + ext0_node = kunit_kzalloc(test, sizeof(*ext0_node), GFP_KERNEL); 297 + KUNIT_ASSERT_NOT_NULL(test, ext0_node); 298 + *ext0_node = SOFTWARE_NODE("mipi-sdca-function-expansion-subproperties", 299 + ext0_props, &cs35l56_test_af01_sw_node); 300 + 301 + KUNIT_ASSERT_EQ(test, software_node_register(ext0_node), 0); 302 + KUNIT_ASSERT_EQ(test, 303 + kunit_add_action_or_reset(test, 304 + software_node_unregister_wrapper, 305 + ext0_node), 306 + 0); 307 + 308 + KUNIT_ASSERT_EQ(test, 309 + device_add_software_node(cs35l56->base.dev, &cs35l56_test_dev_sw_node), 0); 310 + KUNIT_ASSERT_EQ(test, 0, 311 + kunit_add_action_or_reset(test, 312 + device_remove_software_node_wrapper, 313 + cs35l56->base.dev)); 314 + 315 + KUNIT_EXPECT_EQ(test, cs35l56_process_xu_properties(cs35l56), 0); 316 + 317 + KUNIT_EXPECT_EQ(test, cs35l56->base.num_onchip_spkid_gpios, num_gpios); 318 + KUNIT_EXPECT_EQ(test, cs35l56->base.num_onchip_spkid_pulls, num_pulls); 319 + 320 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 321 + if (param->spkid_gpios[i] < 0) 322 + break; 323 + 324 + /* 325 + * cs35l56_process_xu_properties() stores the GPIO numbers 326 + * zero-based, which is one less than the value in the property. 327 + */ 328 + KUNIT_EXPECT_EQ_MSG(test, cs35l56->base.onchip_spkid_gpios[i], 329 + param->spkid_gpios[i] - 1, 330 + "i=%d", i); 331 + } 332 + 333 + for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 334 + if (param->spkid_pulls[i] < 0) 335 + break; 336 + 337 + KUNIT_EXPECT_EQ_MSG(test, cs35l56->base.onchip_spkid_pulls[i], 338 + param->spkid_pulls[i], "i=%d", i); 339 + } 340 + } 341 + 342 + static int cs35l56_test_dummy_read_onchip_spkid(struct cs35l56_base *cs35l56_base) 343 + { 344 + struct kunit *test = kunit_get_current_test(); 345 + struct cs35l56_test_priv *priv = test->priv; 346 + 347 + priv->read_onchip_spkid_called = true; 348 + 349 + return 4; 350 + } 351 + 352 + static int cs35l56_test_dummy_configure_onchip_spkid_pads(struct cs35l56_base *cs35l56_base) 353 + { 354 + struct kunit *test = kunit_get_current_test(); 355 + struct cs35l56_test_priv *priv = test->priv; 356 + 357 + priv->configure_onchip_spkid_pads_called = true; 358 + 359 + return 0; 360 + } 361 + 362 + static void cs35l56_test_set_fw_name_reads_onchip_spkid(struct kunit *test) 363 + { 364 + struct cs35l56_test_priv *priv = test->priv; 365 + struct cs35l56_private *cs35l56 = priv->cs35l56_priv; 366 + 367 + /* Provide some on-chip GPIOs for spkid */ 368 + cs35l56->base.onchip_spkid_gpios[0] = 1; 369 + cs35l56->base.num_onchip_spkid_gpios = 1; 370 + 371 + cs35l56->speaker_id = -ENOENT; 372 + 373 + kunit_activate_static_stub(test, 374 + cs35l56_configure_onchip_spkid_pads, 375 + cs35l56_test_dummy_configure_onchip_spkid_pads); 376 + kunit_activate_static_stub(test, 377 + cs35l56_read_onchip_spkid, 378 + cs35l56_test_dummy_read_onchip_spkid); 379 + 380 + priv->configure_onchip_spkid_pads_called = false; 381 + priv->read_onchip_spkid_called = false; 382 + KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0); 383 + KUNIT_EXPECT_TRUE(test, priv->configure_onchip_spkid_pads_called); 384 + KUNIT_EXPECT_TRUE(test, priv->read_onchip_spkid_called); 385 + KUNIT_EXPECT_EQ(test, cs35l56->speaker_id, 386 + cs35l56_test_dummy_read_onchip_spkid(&cs35l56->base)); 387 + } 388 + 389 + static void cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios(struct kunit *test) 390 + { 391 + struct cs35l56_test_priv *priv = test->priv; 392 + struct cs35l56_private *cs35l56 = priv->cs35l56_priv; 393 + 394 + /* Provide some on-chip GPIOs for spkid */ 395 + cs35l56->base.onchip_spkid_gpios[0] = 1; 396 + cs35l56->base.num_onchip_spkid_gpios = 1; 397 + 398 + /* Simulate that the driver already got a spkid from somewhere */ 399 + cs35l56->speaker_id = 15; 400 + 401 + KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0); 402 + KUNIT_EXPECT_EQ(test, cs35l56->speaker_id, 15); 403 + } 404 + 405 + static void cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios(struct kunit *test) 406 + { 407 + struct cs35l56_test_priv *priv = test->priv; 408 + struct cs35l56_private *cs35l56 = priv->cs35l56_priv; 409 + 410 + cs35l56->base.num_onchip_spkid_gpios = 0; 411 + 412 + /* Simulate that the driver already got a spkid from somewhere */ 413 + cs35l56->speaker_id = 15; 414 + 415 + KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0); 416 + KUNIT_EXPECT_EQ(test, cs35l56->speaker_id, 15); 417 + } 418 + 267 419 static int cs35l56_test_case_init_common(struct kunit *test) 268 420 { 269 421 struct cs35l56_test_priv *priv; ··· 479 263 cs35l56->component = kunit_kzalloc(test, sizeof(*cs35l56->component), GFP_KERNEL); 480 264 KUNIT_ASSERT_NOT_NULL(test, cs35l56->component); 481 265 cs35l56->component->dev = cs35l56->base.dev; 266 + snd_soc_component_set_drvdata(cs35l56->component, cs35l56); 482 267 483 268 cs35l56->component->card = kunit_kzalloc(test, sizeof(*cs35l56->component->card), 484 269 GFP_KERNEL); ··· 516 299 return 0; 517 300 } 518 301 302 + static void cs35l56_test_gpio_param_desc(const struct cs35l56_test_param *param, char *desc) 303 + { 304 + DECLARE_SEQ_BUF(gpios, 1 + (2 * ARRAY_SIZE(param->spkid_gpios))); 305 + DECLARE_SEQ_BUF(pulls, 1 + (2 * ARRAY_SIZE(param->spkid_pulls))); 306 + int i; 307 + 308 + for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { 309 + if (param->spkid_gpios[i] < 0) 310 + break; 311 + 312 + seq_buf_printf(&gpios, "%s%d", (i == 0) ? "" : ",", param->spkid_gpios[i]); 313 + } 314 + 315 + for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { 316 + if (param->spkid_pulls[i] < 0) 317 + break; 318 + 319 + seq_buf_printf(&pulls, "%s%d", (i == 0) ? "" : ",", param->spkid_pulls[i]); 320 + } 321 + 322 + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "gpios:{%s} pulls:{%s}", 323 + seq_buf_str(&gpios), seq_buf_str(&pulls)); 324 + } 325 + 326 + static const struct cs35l56_test_param cs35l56_test_onchip_spkid_cases[] = { 327 + { .spkid_gpios = { 1, -1 }, .spkid_pulls = { 1, -1 }, }, 328 + { .spkid_gpios = { 1, -1 }, .spkid_pulls = { 2, -1 }, }, 329 + 330 + { .spkid_gpios = { 7, -1 }, .spkid_pulls = { 1, -1 }, }, 331 + { .spkid_gpios = { 7, -1 }, .spkid_pulls = { 2, -1 }, }, 332 + 333 + { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 1, 1, -1 }, }, 334 + { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 2, 2, -1 }, }, 335 + 336 + { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 1, 1, -1 }, }, 337 + { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 2, 2, -1 }, }, 338 + 339 + { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 1, 1, 1, -1 }, }, 340 + { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 2, 2, 2, -1 }, }, 341 + }; 342 + KUNIT_ARRAY_PARAM(cs35l56_test_onchip_spkid, 343 + cs35l56_test_onchip_spkid_cases, 344 + cs35l56_test_gpio_param_desc); 345 + 519 346 static void cs35l56_test_type_rev_param_desc(const struct cs35l56_test_param *param, 520 347 char *desc) 521 348 { ··· 592 331 cs35l56_test_type_rev_ex_b0_gen_params), 593 332 KUNIT_CASE(cs35l56_test_l56_b0_ssidexv2_ignored_suffix_sdw), 594 333 334 + KUNIT_CASE_PARAM(cs35l56_test_parse_xu_onchip_spkid, 335 + cs35l56_test_onchip_spkid_gen_params), 336 + 337 + KUNIT_CASE(cs35l56_test_set_fw_name_reads_onchip_spkid), 338 + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios), 339 + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios), 340 + 595 341 { } /* terminator */ 596 342 }; 597 343 ··· 606 338 KUNIT_CASE_PARAM(cs35l56_test_suffix_i2cspi, cs35l56_test_type_rev_all_gen_params), 607 339 KUNIT_CASE_PARAM(cs35l56_test_ssidexv2_suffix_i2cspi, 608 340 cs35l56_test_type_rev_all_gen_params), 341 + 342 + KUNIT_CASE(cs35l56_test_set_fw_name_reads_onchip_spkid), 343 + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios), 344 + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios), 609 345 610 346 { } /* terminator */ 611 347 }; ··· 632 360 ); 633 361 634 362 MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); 363 + MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); 635 364 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 636 365 MODULE_DESCRIPTION("KUnit test for Cirrus Logic cs35l56 codec driver"); 637 366 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+137 -4
sound/soc/codecs/cs35l56.c
··· 1179 1179 } 1180 1180 EXPORT_SYMBOL_IF_KUNIT(cs35l56_set_fw_suffix); 1181 1181 1182 - static int cs35l56_component_probe(struct snd_soc_component *component) 1182 + VISIBLE_IF_KUNIT int cs35l56_set_fw_name(struct snd_soc_component *component) 1183 1183 { 1184 - struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); 1185 1184 struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); 1186 - struct dentry *debugfs_root = component->debugfs_root; 1187 1185 unsigned short vendor, device; 1188 1186 int ret; 1189 1187 1190 - BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) != ARRAY_SIZE(cs35l56_tx_input_values)); 1188 + if ((cs35l56->speaker_id < 0) && cs35l56->base.num_onchip_spkid_gpios) { 1189 + PM_RUNTIME_ACQUIRE(cs35l56->base.dev, pm); 1190 + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); 1191 + if (ret) 1192 + return ret; 1193 + 1194 + ret = cs35l56_configure_onchip_spkid_pads(&cs35l56->base); 1195 + if (ret) 1196 + return ret; 1197 + 1198 + ret = cs35l56_read_onchip_spkid(&cs35l56->base); 1199 + if (ret < 0) 1200 + return ret; 1201 + 1202 + cs35l56->speaker_id = ret; 1203 + } 1191 1204 1192 1205 if (!cs35l56->dsp.system_name && 1193 1206 (snd_soc_card_get_pci_ssid(component->card, &vendor, &device) == 0)) { ··· 1221 1208 return -ENOMEM; 1222 1209 } 1223 1210 1211 + return 0; 1212 + } 1213 + EXPORT_SYMBOL_IF_KUNIT(cs35l56_set_fw_name); 1214 + 1215 + static int cs35l56_component_probe(struct snd_soc_component *component) 1216 + { 1217 + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); 1218 + struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); 1219 + struct dentry *debugfs_root = component->debugfs_root; 1220 + int ret; 1221 + 1222 + BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) != ARRAY_SIZE(cs35l56_tx_input_values)); 1223 + 1224 1224 if (!wait_for_completion_timeout(&cs35l56->init_completion, 1225 1225 msecs_to_jiffies(5000))) { 1226 1226 dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__); ··· 1245 1219 return -ENOMEM; 1246 1220 1247 1221 cs35l56->component = component; 1222 + ret = cs35l56_set_fw_name(component); 1223 + if (ret) 1224 + return ret; 1225 + 1248 1226 ret = cs35l56_set_fw_suffix(cs35l56); 1249 1227 if (ret) 1250 1228 return ret; ··· 1562 1532 return 0; 1563 1533 } 1564 1534 1535 + static int cs35l56_read_fwnode_u32_array(struct device *dev, 1536 + struct fwnode_handle *parent_node, 1537 + const char *prop_name, 1538 + int max_count, 1539 + u32 *dest) 1540 + { 1541 + int count, ret; 1542 + 1543 + count = fwnode_property_count_u32(parent_node, prop_name); 1544 + if ((count == 0) || (count == -EINVAL) || (count == -ENODATA)) { 1545 + dev_dbg(dev, "%s not found in %s\n", prop_name, fwnode_get_name(parent_node)); 1546 + return 0; 1547 + } 1548 + 1549 + if (count < 0) { 1550 + dev_err(dev, "Get %s error:%d\n", prop_name, count); 1551 + return count; 1552 + } 1553 + 1554 + if (count > max_count) { 1555 + dev_err(dev, "%s too many entries (%d)\n", prop_name, count); 1556 + return -EOVERFLOW; 1557 + } 1558 + 1559 + ret = fwnode_property_read_u32_array(parent_node, prop_name, dest, count); 1560 + if (ret) { 1561 + dev_err(dev, "Error reading %s: %d\n", prop_name, ret); 1562 + return ret; 1563 + } 1564 + 1565 + return count; 1566 + } 1567 + 1568 + static int cs35l56_process_xu_onchip_speaker_id(struct cs35l56_private *cs35l56, 1569 + struct fwnode_handle *ext_node) 1570 + { 1571 + static const char * const gpio_name = "01fa-spk-id-gpios-onchip"; 1572 + static const char * const pull_name = "01fa-spk-id-gpios-onchip-pull"; 1573 + u32 gpios[5], pulls[5]; 1574 + int num_gpios, num_pulls; 1575 + int ret; 1576 + 1577 + static_assert(ARRAY_SIZE(gpios) == ARRAY_SIZE(cs35l56->base.onchip_spkid_gpios)); 1578 + static_assert(ARRAY_SIZE(pulls) == ARRAY_SIZE(cs35l56->base.onchip_spkid_pulls)); 1579 + 1580 + num_gpios = cs35l56_read_fwnode_u32_array(cs35l56->base.dev, ext_node, gpio_name, 1581 + ARRAY_SIZE(gpios), gpios); 1582 + if (num_gpios < 1) 1583 + return num_gpios; 1584 + 1585 + num_pulls = cs35l56_read_fwnode_u32_array(cs35l56->base.dev, ext_node, pull_name, 1586 + ARRAY_SIZE(pulls), pulls); 1587 + if (num_pulls < 0) 1588 + return num_pulls; 1589 + 1590 + if (num_pulls != num_gpios) { 1591 + dev_warn(cs35l56->base.dev, "%s count(%d) != %s count(%d)\n", 1592 + pull_name, num_pulls, gpio_name, num_gpios); 1593 + } 1594 + 1595 + ret = cs35l56_check_and_save_onchip_spkid_gpios(&cs35l56->base, 1596 + gpios, num_gpios, 1597 + pulls, num_pulls); 1598 + if (ret) { 1599 + return dev_err_probe(cs35l56->base.dev, ret, "Error in %s/%s\n", 1600 + gpio_name, pull_name); 1601 + } 1602 + 1603 + return 0; 1604 + } 1605 + 1606 + VISIBLE_IF_KUNIT int cs35l56_process_xu_properties(struct cs35l56_private *cs35l56) 1607 + { 1608 + struct fwnode_handle *ext_node = NULL; 1609 + struct fwnode_handle *link; 1610 + int ret; 1611 + 1612 + if (!cs35l56->sdw_peripheral) 1613 + return 0; 1614 + 1615 + fwnode_for_each_child_node(dev_fwnode(cs35l56->base.dev), link) { 1616 + ext_node = fwnode_get_named_child_node(link, 1617 + "mipi-sdca-function-expansion-subproperties"); 1618 + if (ext_node) { 1619 + fwnode_handle_put(link); 1620 + break; 1621 + } 1622 + } 1623 + 1624 + if (!ext_node) 1625 + return 0; 1626 + 1627 + ret = cs35l56_process_xu_onchip_speaker_id(cs35l56, ext_node); 1628 + fwnode_handle_put(ext_node); 1629 + 1630 + return ret; 1631 + } 1632 + EXPORT_SYMBOL_IF_KUNIT(cs35l56_process_xu_properties); 1633 + 1565 1634 static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56) 1566 1635 { 1567 1636 struct device *dev = cs35l56->base.dev; ··· 1839 1710 1840 1711 ret = cs35l56_get_firmware_uid(cs35l56); 1841 1712 if (ret != 0) 1713 + goto err; 1714 + 1715 + ret = cs35l56_process_xu_properties(cs35l56); 1716 + if (ret) 1842 1717 goto err; 1843 1718 1844 1719 ret = cs35l56_dsp_init(cs35l56);
+2
sound/soc/codecs/cs35l56.h
··· 76 76 77 77 #if IS_ENABLED(CONFIG_KUNIT) 78 78 int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56); 79 + int cs35l56_set_fw_name(struct snd_soc_component *component); 80 + int cs35l56_process_xu_properties(struct cs35l56_private *cs35l56); 79 81 #endif 80 82 81 83 #endif /* ifndef CS35L56_H */