ASoC: Fixes for v6.19

A bunch more small fixes here, plus some more of the constant stream of
 quirks.   The most notable change here is Richard's change to the cs_dsp
 code for the KUnit tests which is relatively large, mostly due to
 boilerplate.  The tests were triggering large numbers of error messages
 as part of verifying that problems with input data are appropriately
 detected which in turn caused runtime issues for the framework due to
 the performance impact of pushing the logging out, while the logging is
 valuable in normal operation it's basically useless while doing tests
 designed to trigger it so rate limiting is an appropriate fix.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmmDa7YACgkQJNaLcl1U
 h9DImgf/adXRBuSZyBM0Te40IJfFI4x6sqQlwyaOOeOwe6OLBl6MswWCK8l2Z5MZ
 F6wWM/oSlwtwPuVzSL8pM4NA5mZxyxX+naccFZUVvbsOfPypc4cYLjG6P1XOv/ET
 On1UKDTkjSy12Ubq9apYguwmztj2AU4C4b3lZbuicX4S7ayAiCpR+c5sv2u/7Myl
 pssr1Q83dwi1LTK4+42KUdtPzXfL7VTBh5yVDF7yHuaT3e+yzNWus9/w/Xq2JS4d
 OMShgAyWsM2yUYNVEFAEV2wrWpACgJeQXNcidCDnP3ayaJoFU9dEDPJTjBLD0+k+
 fWVZmbK9+BviCqtT5fYkzyg/hDrKBA==
 =gzU5
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v6.19-rc8' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v6.19

A bunch more small fixes here, plus some more of the constant stream of
quirks.   The most notable change here is Richard's change to the cs_dsp
code for the KUnit tests which is relatively large, mostly due to
boilerplate.  The tests were triggering large numbers of error messages
as part of verifying that problems with input data are appropriately
detected which in turn caused runtime issues for the framework due to
the performance impact of pushing the logging out, while the logging is
valuable in normal operation it's basically useless while doing tests
designed to trigger it so rate limiting is an appropriate fix.
This commit is contained in:
Takashi Iwai 2026-02-04 17:03:08 +01:00
commit 523abd481c
15 changed files with 195 additions and 23 deletions

View File

@ -46,6 +46,7 @@ maintainers:
properties:
compatible:
enum:
- ti,tlv320aic23
- ti,tlv320aic3x
- ti,tlv320aic33
- ti,tlv320aic3007

View File

@ -9,6 +9,7 @@
* Cirrus Logic International Semiconductor Ltd.
*/
#include <kunit/visibility.h>
#include <linux/cleanup.h>
#include <linux/ctype.h>
#include <linux/debugfs.h>
@ -24,6 +25,41 @@
#include <linux/firmware/cirrus/cs_dsp.h>
#include <linux/firmware/cirrus/wmfw.h>
#include "cs_dsp.h"
/*
* When the KUnit test is running the error-case tests will cause a lot
* of messages. Rate-limit to prevent overflowing the kernel log buffer
* during KUnit test runs.
*/
#if IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST)
bool cs_dsp_suppress_err_messages;
EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_err_messages);
bool cs_dsp_suppress_warn_messages;
EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_warn_messages);
bool cs_dsp_suppress_info_messages;
EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_info_messages);
#define cs_dsp_err(_dsp, fmt, ...) \
do { \
if (!cs_dsp_suppress_err_messages) \
dev_err_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
#define cs_dsp_warn(_dsp, fmt, ...) \
do { \
if (!cs_dsp_suppress_warn_messages) \
dev_warn_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
#define cs_dsp_info(_dsp, fmt, ...) \
do { \
if (!cs_dsp_suppress_info_messages) \
dev_info_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
#define cs_dsp_dbg(_dsp, fmt, ...) \
dev_dbg_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#else
#define cs_dsp_err(_dsp, fmt, ...) \
dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#define cs_dsp_warn(_dsp, fmt, ...) \
@ -32,6 +68,7 @@
dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#define cs_dsp_dbg(_dsp, fmt, ...) \
dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#endif
#define ADSP1_CONTROL_1 0x00
#define ADSP1_CONTROL_2 0x02

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cs_dsp.h -- Private header for cs_dsp driver.
*
* Copyright (C) 2026 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*/
#ifndef FW_CS_DSP_H
#define FW_CS_DSP_H
#if IS_ENABLED(CONFIG_KUNIT)
extern bool cs_dsp_suppress_err_messages;
extern bool cs_dsp_suppress_warn_messages;
extern bool cs_dsp_suppress_info_messages;
#endif
#endif /* ifndef FW_CS_DSP_H */

View File

@ -17,6 +17,8 @@
#include <linux/random.h>
#include <linux/regmap.h>
#include "../cs_dsp.h"
/*
* Test method is:
*
@ -2224,7 +2226,22 @@ static int cs_dsp_bin_test_common_init(struct kunit *test, struct cs_dsp *dsp)
return ret;
/* Automatically call cs_dsp_remove() when test case ends */
return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
if (ret)
return ret;
/*
* The large number of test cases will cause an unusually large amount
* of dev_info() messages from cs_dsp, so suppress these.
*/
cs_dsp_suppress_info_messages = true;
return 0;
}
static void cs_dsp_bin_test_exit(struct kunit *test)
{
cs_dsp_suppress_info_messages = false;
}
static int cs_dsp_bin_test_halo_init(struct kunit *test)
@ -2536,18 +2553,21 @@ static struct kunit_case cs_dsp_bin_test_cases_adsp2[] = {
static struct kunit_suite cs_dsp_bin_test_halo = {
.name = "cs_dsp_bin_halo",
.init = cs_dsp_bin_test_halo_init,
.exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_halo,
};
static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = {
.name = "cs_dsp_bin_adsp2_32bit",
.init = cs_dsp_bin_test_adsp2_32bit_init,
.exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_adsp2,
};
static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = {
.name = "cs_dsp_bin_adsp2_16bit",
.init = cs_dsp_bin_test_adsp2_16bit_init,
.exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_adsp2,
};

View File

@ -18,6 +18,8 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include "../cs_dsp.h"
KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *);
KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *);
@ -380,11 +382,9 @@ static void bin_block_payload_len_garbage(struct kunit *test)
static void cs_dsp_bin_err_test_exit(struct kunit *test)
{
/*
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so rate limit the test cases.
*/
usleep_range(200, 500);
cs_dsp_suppress_err_messages = false;
cs_dsp_suppress_warn_messages = false;
cs_dsp_suppress_info_messages = false;
}
static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
@ -474,7 +474,19 @@ static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *ds
return ret;
/* Automatically call cs_dsp_remove() when test case ends */
return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
if (ret)
return ret;
/*
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so suppress messages.
*/
cs_dsp_suppress_err_messages = true;
cs_dsp_suppress_warn_messages = true;
cs_dsp_suppress_info_messages = true;
return 0;
}
static int cs_dsp_bin_err_test_halo_init(struct kunit *test)

View File

@ -18,6 +18,8 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include "../cs_dsp.h"
/*
* Test method is:
*
@ -1853,7 +1855,22 @@ static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp,
return ret;
/* Automatically call cs_dsp_remove() when test case ends */
return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
if (ret)
return ret;
/*
* The large number of test cases will cause an unusually large amount
* of dev_info() messages from cs_dsp, so suppress these.
*/
cs_dsp_suppress_info_messages = true;
return 0;
}
static void cs_dsp_wmfw_test_exit(struct kunit *test)
{
cs_dsp_suppress_info_messages = false;
}
static int cs_dsp_wmfw_test_halo_init(struct kunit *test)
@ -2163,42 +2180,49 @@ static struct kunit_case cs_dsp_wmfw_test_cases_adsp2[] = {
static struct kunit_suite cs_dsp_wmfw_test_halo = {
.name = "cs_dsp_wmfwV3_halo",
.init = cs_dsp_wmfw_test_halo_init,
.exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_halo,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init,
.exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init,
.exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init,
.exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init,
.exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init,
.exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init,
.exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
};

View File

@ -18,6 +18,8 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include "../cs_dsp.h"
KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *);
KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *);
@ -989,11 +991,9 @@ static void wmfw_v2_coeff_description_exceeds_block(struct kunit *test)
static void cs_dsp_wmfw_err_test_exit(struct kunit *test)
{
/*
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so rate limit the test cases.
*/
usleep_range(200, 500);
cs_dsp_suppress_err_messages = false;
cs_dsp_suppress_warn_messages = false;
cs_dsp_suppress_info_messages = false;
}
static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
@ -1072,7 +1072,19 @@ static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *d
return ret;
/* Automatically call cs_dsp_remove() when test case ends */
return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
if (ret)
return ret;
/*
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so suppress messages.
*/
cs_dsp_suppress_err_messages = true;
cs_dsp_suppress_warn_messages = true;
cs_dsp_suppress_info_messages = true;
return 0;
}
static int cs_dsp_wmfw_err_test_halo_init(struct kunit *test)

View File

@ -12,3 +12,4 @@ MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("FW_CS_DSP");
MODULE_IMPORT_NS("FW_CS_DSP_KUNIT_TEST_UTILS");
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");

View File

@ -301,9 +301,11 @@ static int acp_pdm_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
struct pdm_stream_instance *rtd = substream->runtime->private_data;
disable_pdm_interrupts(adata->acp_base);
adata->capture_stream = NULL;
kfree(rtd);
return 0;
}

View File

@ -640,6 +640,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "8BD6"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_BOARD_NAME, "8EE4"),
}
},
{
.driver_data = &acp6x_card,
.matches = {

View File

@ -496,7 +496,23 @@ void cs42l43_bias_sense_timeout(struct work_struct *work)
pm_runtime_put_autosuspend(priv->dev);
}
static void cs42l43_start_load_detect(struct cs42l43_codec *priv)
static const struct reg_sequence cs42l43_3pole_patch[] = {
{ 0x4000, 0x00000055 },
{ 0x4000, 0x000000AA },
{ 0x17420, 0x8500F300 },
{ 0x17424, 0x36003E00 },
{ 0x4000, 0x00000000 },
};
static const struct reg_sequence cs42l43_4pole_patch[] = {
{ 0x4000, 0x00000055 },
{ 0x4000, 0x000000AA },
{ 0x17420, 0x7800E600 },
{ 0x17424, 0x36003800 },
{ 0x4000, 0x00000000 },
};
static void cs42l43_start_load_detect(struct cs42l43_codec *priv, bool mic)
{
struct cs42l43 *cs42l43 = priv->core;
@ -520,6 +536,15 @@ static void cs42l43_start_load_detect(struct cs42l43_codec *priv)
dev_err(priv->dev, "Load detect HP power down timed out\n");
}
if (mic)
regmap_multi_reg_write_bypassed(cs42l43->regmap,
cs42l43_4pole_patch,
ARRAY_SIZE(cs42l43_4pole_patch));
else
regmap_multi_reg_write_bypassed(cs42l43->regmap,
cs42l43_3pole_patch,
ARRAY_SIZE(cs42l43_3pole_patch));
regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0);
regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, CS42L43_HP_HPF_EN_MASK, 0);
@ -598,7 +623,7 @@ static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic)
reinit_completion(&priv->load_detect);
cs42l43_start_load_detect(priv);
cs42l43_start_load_detect(priv, mic);
time_left = wait_for_completion_timeout(&priv->load_detect,
msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS));
cs42l43_stop_load_detect(priv);
@ -622,11 +647,11 @@ static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic)
}
switch (val & CS42L43_AMP3_RES_DET_MASK) {
case 0x0: // low impedance
case 0x1: // high impedance
case 0x0: // < 22 Ohm impedance
case 0x1: // < 150 Ohm impedance
case 0x2: // < 1000 Ohm impedance
return CS42L43_JACK_HEADPHONE;
case 0x2: // lineout
case 0x3: // Open circuit
case 0x3: // > 1000 Ohm impedance
return CS42L43_JACK_LINEOUT;
default:
return -EINVAL;

View File

@ -203,6 +203,7 @@ static const struct reg_sequence rt1320_vc_blind_write[] = {
{ 0x3fc2bfc2, 0x00 },
{ 0x3fc2bfc1, 0x00 },
{ 0x3fc2bfc0, 0x07 },
{ 0x1000cc46, 0x00 },
{ 0x0000d486, 0x43 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 },
{ 0x1000db00, 0x07 },
@ -354,6 +355,7 @@ static const struct reg_sequence rt1321_blind_write[] = {
{ 0x0000d73d, 0xd7 },
{ 0x0000d73e, 0x00 },
{ 0x0000d73f, 0x10 },
{ 0x1000cd56, 0x00 },
{ 0x3fc2dfc3, 0x00 },
{ 0x3fc2dfc2, 0x00 },
{ 0x3fc2dfc1, 0x00 },

View File

@ -223,10 +223,13 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_EARC));
up_read(&card->snd_card->controls_rwsem);
/* Allow playback for SPDIF only */
rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =

View File

@ -334,6 +334,15 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id)
* if the topology file is modified as well.
*/
static const struct dmi_system_id sof_es8336_quirk_table[] = {
{
.callback = sof_es8336_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
DMI_MATCH(DMI_PRODUCT_NAME, "BOD-WXX9"),
},
.driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO |
SOF_ES8336_ENABLE_DMIC)
},
{
.callback = sof_es8336_quirk_cb,
.matches = {

View File

@ -1304,9 +1304,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
int i;
hdev = pdata->hw_pdata;
link_mask = hdev->info.link_mask;
if (!link_mask) {
if (!hdev->info.link_mask) {
dev_info(sdev->dev, "SoundWire links not enabled\n");
return NULL;
}
@ -1337,7 +1336,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
* link_mask supported by hw and then go on searching
* link_adr
*/
if (~link_mask & mach->link_mask)
if (~hdev->info.link_mask & mach->link_mask)
continue;
/* No need to match adr if there is no links defined */