Pull sound fixes from Takashi Iwai: "A collection of small fixes. It became a bit larger than wished, but all of them are device-specific small fixes, and it should be still fairly safe to take at the last minute. Included are a few quirks and fixes for Intel, AMD, HD-audio, and USB-audio, as well as a race fix in aloop driver and corrections of Cirrus firmware kunit test" * tag 'sound-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: ALSA: hda/realtek: Enable headset mic for Acer Nitro 5 ASoC: fsl_xcvr: fix missing lock in fsl_xcvr_mode_put() ASoC: dt-bindings: ti,tlv320aic3x: Add compatible string ti,tlv320aic23 ASoC: amd: fix memory leak in acp3x pdm dma ops ALSA: usb-audio: fix broken logic in snd_audigy2nx_led_update() ALSA: aloop: Fix racy access at PCM trigger ASoC: rt1320: fix intermittent no-sound issue ASoC: SOF: Intel: use hdev->info.link_mask directly firmware: cs_dsp: rate-limit log messages in KUnit builds ASoC: amd: yc: Add quirk for HP 200 G2a 16 ASoC: cs42l43: Correct handling of 3-pole jack load detection ASoC: Intel: sof_es8336: Add DMI quirk for Huawei BOD-WXX9 ASoC: sof_sdw: Add a quirk for Lenovo laptop using sidecar amps with cs42l43
Unified · Split
| @@ -46,6 +46,7 @@ maintainers: · 45 unmodified lines | ||
| 46 | 46 | properties: |
| 47 | 47 | compatible: |
| 48 | 48 | enum: |
| 49 | + - ti,tlv320aic23 | |
| 49 | 50 | - ti,tlv320aic3x |
| 50 | 51 | - ti,tlv320aic33 |
| 51 | 52 | - ti,tlv320aic3007 |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | * Cirrus Logic International Semiconductor Ltd. |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | +#include <kunit/visibility.h> | |
| 12 | 13 | #include <linux/cleanup.h> |
| 13 | 14 | #include <linux/ctype.h> |
| 14 | 15 | #include <linux/debugfs.h> |
| @@ -24,6 +25,41 @@ · 9 unmodified lines | ||
| 24 | 25 | #include <linux/firmware/cirrus/cs_dsp.h> |
| 25 | 26 | #include <linux/firmware/cirrus/wmfw.h> |
| 26 | 27 | |
| 28 | +#include "cs_dsp.h" | |
| 29 | + | |
| 30 | +/* | |
| 31 | + * When the KUnit test is running the error-case tests will cause a lot | |
| 32 | + * of messages. Rate-limit to prevent overflowing the kernel log buffer | |
| 33 | + * during KUnit test runs. | |
| 34 | + */ | |
| 35 | +#if IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST) | |
| 36 | +bool cs_dsp_suppress_err_messages; | |
| 37 | +EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_err_messages); | |
| 38 | + | |
| 39 | +bool cs_dsp_suppress_warn_messages; | |
| 40 | +EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_warn_messages); | |
| 41 | + | |
| 42 | +bool cs_dsp_suppress_info_messages; | |
| 43 | +EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_info_messages); | |
| 44 | + | |
| 45 | +#define cs_dsp_err(_dsp, fmt, ...) \ | |
| 46 | + do { \ | |
| 47 | + if (!cs_dsp_suppress_err_messages) \ | |
| 48 | + dev_err_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \ | |
| 49 | + } while (false) | |
| 50 | +#define cs_dsp_warn(_dsp, fmt, ...) \ | |
| 51 | + do { \ | |
| 52 | + if (!cs_dsp_suppress_warn_messages) \ | |
| 53 | + dev_warn_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \ | |
| 54 | + } while (false) | |
| 55 | +#define cs_dsp_info(_dsp, fmt, ...) \ | |
| 56 | + do { \ | |
| 57 | + if (!cs_dsp_suppress_info_messages) \ | |
| 58 | + dev_info_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \ | |
| 59 | + } while (false) | |
| 60 | +#define cs_dsp_dbg(_dsp, fmt, ...) \ | |
| 61 | + dev_dbg_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) | |
| 62 | +#else | |
| 27 | 63 | #define cs_dsp_err(_dsp, fmt, ...) \ |
| 28 | 64 | dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
| 29 | 65 | #define cs_dsp_warn(_dsp, fmt, ...) \ |
| @@ -32,6 +68,7 @@ · 2 unmodified lines | ||
| 32 | 68 | dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
| 33 | 69 | #define cs_dsp_dbg(_dsp, fmt, ...) \ |
| 34 | 70 | dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
| 71 | +#endif | |
| 35 | 72 | |
| 36 | 73 | #define ADSP1_CONTROL_1 0x00 |
| 37 | 74 | #define ADSP1_CONTROL_2 0x02 |
| @@ -0,0 +1,18 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * cs_dsp.h -- Private header for cs_dsp driver. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2026 Cirrus Logic, Inc. and | |
| 6 | + * Cirrus Logic International Semiconductor Ltd. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#ifndef FW_CS_DSP_H | |
| 10 | +#define FW_CS_DSP_H | |
| 11 | + | |
| 12 | +#if IS_ENABLED(CONFIG_KUNIT) | |
| 13 | +extern bool cs_dsp_suppress_err_messages; | |
| 14 | +extern bool cs_dsp_suppress_warn_messages; | |
| 15 | +extern bool cs_dsp_suppress_info_messages; | |
| 16 | +#endif | |
| 17 | + | |
| 18 | +#endif /* ifndef FW_CS_DSP_H */ | |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/random.h> |
| 18 | 18 | #include <linux/regmap.h> |
| 19 | 19 | |
| 20 | +#include "../cs_dsp.h" | |
| 21 | + | |
| 20 | 22 | /* |
| 21 | 23 | * Test method is: |
| 22 | 24 | * |
| @@ -2224,7 +2226,22 @@ static int cs_dsp_bin_test_common_init(struct kunit *test, struct cs_dsp *dsp) · 2201 unmodified lines | ||
| 2224 | 2226 | return ret; |
| 2225 | 2227 | |
| 2226 | 2228 | /* Automatically call cs_dsp_remove() when test case ends */ |
| 2227 | − return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 2229 | + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 2230 | + if (ret) | |
| 2231 | + return ret; | |
| 2232 | + | |
| 2233 | + /* | |
| 2234 | + * The large number of test cases will cause an unusually large amount | |
| 2235 | + * of dev_info() messages from cs_dsp, so suppress these. | |
| 2236 | + */ | |
| 2237 | + cs_dsp_suppress_info_messages = true; | |
| 2238 | + | |
| 2239 | + return 0; | |
| 2240 | +} | |
| 2241 | + | |
| 2242 | +static void cs_dsp_bin_test_exit(struct kunit *test) | |
| 2243 | +{ | |
| 2244 | + cs_dsp_suppress_info_messages = false; | |
| 2228 | 2245 | } |
| 2229 | 2246 | |
| 2230 | 2247 | 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[] = { · 305 unmodified lines | ||
| 2536 | 2553 | static struct kunit_suite cs_dsp_bin_test_halo = { |
| 2537 | 2554 | .name = "cs_dsp_bin_halo", |
| 2538 | 2555 | .init = cs_dsp_bin_test_halo_init, |
| 2556 | + .exit = cs_dsp_bin_test_exit, | |
| 2539 | 2557 | .test_cases = cs_dsp_bin_test_cases_halo, |
| 2540 | 2558 | }; |
| 2541 | 2559 | |
| 2542 | 2560 | static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = { |
| 2543 | 2561 | .name = "cs_dsp_bin_adsp2_32bit", |
| 2544 | 2562 | .init = cs_dsp_bin_test_adsp2_32bit_init, |
| 2563 | + .exit = cs_dsp_bin_test_exit, | |
| 2545 | 2564 | .test_cases = cs_dsp_bin_test_cases_adsp2, |
| 2546 | 2565 | }; |
| 2547 | 2566 | |
| 2548 | 2567 | static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = { |
| 2549 | 2568 | .name = "cs_dsp_bin_adsp2_16bit", |
| 2550 | 2569 | .init = cs_dsp_bin_test_adsp2_16bit_init, |
| 2570 | + .exit = cs_dsp_bin_test_exit, | |
| 2551 | 2571 | .test_cases = cs_dsp_bin_test_cases_adsp2, |
| 2552 | 2572 | }; |
| 2553 | 2573 | |
| @@ -18,6 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/string.h> |
| 19 | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | |
| 21 | +#include "../cs_dsp.h" | |
| 22 | + | |
| 21 | 23 | KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); |
| 22 | 24 | KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *); |
| 23 | 25 | |
| @@ -380,11 +382,9 @@ static void bin_block_payload_len_garbage(struct kunit *test) · 356 unmodified lines | ||
| 380 | 382 | |
| 381 | 383 | static void cs_dsp_bin_err_test_exit(struct kunit *test) |
| 382 | 384 | { |
| 383 | − /* | |
| 384 | − * Testing error conditions can produce a lot of log output | |
| 385 | − * from cs_dsp error messages, so rate limit the test cases. | |
| 386 | − */ | |
| 387 | − usleep_range(200, 500); | |
| 385 | + cs_dsp_suppress_err_messages = false; | |
| 386 | + cs_dsp_suppress_warn_messages = false; | |
| 387 | + cs_dsp_suppress_info_messages = false; | |
| 388 | 388 | } |
| 389 | 389 | |
| 390 | 390 | 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 · 83 unmodified lines | ||
| 474 | 474 | return ret; |
| 475 | 475 | |
| 476 | 476 | /* Automatically call cs_dsp_remove() when test case ends */ |
| 477 | − return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 477 | + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 478 | + if (ret) | |
| 479 | + return ret; | |
| 480 | + | |
| 481 | + /* | |
| 482 | + * Testing error conditions can produce a lot of log output | |
| 483 | + * from cs_dsp error messages, so suppress messages. | |
| 484 | + */ | |
| 485 | + cs_dsp_suppress_err_messages = true; | |
| 486 | + cs_dsp_suppress_warn_messages = true; | |
| 487 | + cs_dsp_suppress_info_messages = true; | |
| 488 | + | |
| 489 | + return 0; | |
| 478 | 490 | } |
| 479 | 491 | |
| 480 | 492 | static int cs_dsp_bin_err_test_halo_init(struct kunit *test) |
| @@ -18,6 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/string.h> |
| 19 | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | |
| 21 | +#include "../cs_dsp.h" | |
| 22 | + | |
| 21 | 23 | /* |
| 22 | 24 | * Test method is: |
| 23 | 25 | * |
| @@ -1853,7 +1855,22 @@ static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp, · 1829 unmodified lines | ||
| 1853 | 1855 | return ret; |
| 1854 | 1856 | |
| 1855 | 1857 | /* Automatically call cs_dsp_remove() when test case ends */ |
| 1856 | − return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 1858 | + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 1859 | + if (ret) | |
| 1860 | + return ret; | |
| 1861 | + | |
| 1862 | + /* | |
| 1863 | + * The large number of test cases will cause an unusually large amount | |
| 1864 | + * of dev_info() messages from cs_dsp, so suppress these. | |
| 1865 | + */ | |
| 1866 | + cs_dsp_suppress_info_messages = true; | |
| 1867 | + | |
| 1868 | + return 0; | |
| 1869 | +} | |
| 1870 | + | |
| 1871 | +static void cs_dsp_wmfw_test_exit(struct kunit *test) | |
| 1872 | +{ | |
| 1873 | + cs_dsp_suppress_info_messages = false; | |
| 1857 | 1874 | } |
| 1858 | 1875 | |
| 1859 | 1876 | 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[] = { · 303 unmodified lines | ||
| 2163 | 2180 | static struct kunit_suite cs_dsp_wmfw_test_halo = { |
| 2164 | 2181 | .name = "cs_dsp_wmfwV3_halo", |
| 2165 | 2182 | .init = cs_dsp_wmfw_test_halo_init, |
| 2183 | + .exit = cs_dsp_wmfw_test_exit, | |
| 2166 | 2184 | .test_cases = cs_dsp_wmfw_test_cases_halo, |
| 2167 | 2185 | }; |
| 2168 | 2186 | |
| 2169 | 2187 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = { |
| 2170 | 2188 | .name = "cs_dsp_wmfwV0_adsp2_32bit", |
| 2171 | 2189 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init, |
| 2190 | + .exit = cs_dsp_wmfw_test_exit, | |
| 2172 | 2191 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2173 | 2192 | }; |
| 2174 | 2193 | |
| 2175 | 2194 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = { |
| 2176 | 2195 | .name = "cs_dsp_wmfwV1_adsp2_32bit", |
| 2177 | 2196 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init, |
| 2197 | + .exit = cs_dsp_wmfw_test_exit, | |
| 2178 | 2198 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2179 | 2199 | }; |
| 2180 | 2200 | |
| 2181 | 2201 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = { |
| 2182 | 2202 | .name = "cs_dsp_wmfwV2_adsp2_32bit", |
| 2183 | 2203 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init, |
| 2204 | + .exit = cs_dsp_wmfw_test_exit, | |
| 2184 | 2205 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2185 | 2206 | }; |
| 2186 | 2207 | |
| 2187 | 2208 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = { |
| 2188 | 2209 | .name = "cs_dsp_wmfwV0_adsp2_16bit", |
| 2189 | 2210 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init, |
| 2211 | + .exit = cs_dsp_wmfw_test_exit, | |
| 2190 | 2212 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2191 | 2213 | }; |
| 2192 | 2214 | |
| 2193 | 2215 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = { |
| 2194 | 2216 | .name = "cs_dsp_wmfwV1_adsp2_16bit", |
| 2195 | 2217 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init, |
| 2218 | + .exit = cs_dsp_wmfw_test_exit, | |
| 2196 | 2219 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2197 | 2220 | }; |
| 2198 | 2221 | |
| 2199 | 2222 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = { |
| 2200 | 2223 | .name = "cs_dsp_wmfwV2_adsp2_16bit", |
| 2201 | 2224 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init, |
| 2225 | + .exit = cs_dsp_wmfw_test_exit, | |
| 2202 | 2226 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2203 | 2227 | }; |
| 2204 | 2228 | |
| @@ -18,6 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/string.h> |
| 19 | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | |
| 21 | +#include "../cs_dsp.h" | |
| 22 | + | |
| 21 | 23 | KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); |
| 22 | 24 | KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *); |
| 23 | 25 | |
| @@ -989,11 +991,9 @@ static void wmfw_v2_coeff_description_exceeds_block(struct kunit *test) · 965 unmodified lines | ||
| 989 | 991 | |
| 990 | 992 | static void cs_dsp_wmfw_err_test_exit(struct kunit *test) |
| 991 | 993 | { |
| 992 | − /* | |
| 993 | − * Testing error conditions can produce a lot of log output | |
| 994 | − * from cs_dsp error messages, so rate limit the test cases. | |
| 995 | − */ | |
| 996 | − usleep_range(200, 500); | |
| 994 | + cs_dsp_suppress_err_messages = false; | |
| 995 | + cs_dsp_suppress_warn_messages = false; | |
| 996 | + cs_dsp_suppress_info_messages = false; | |
| 997 | 997 | } |
| 998 | 998 | |
| 999 | 999 | 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 · 72 unmodified lines | ||
| 1072 | 1072 | return ret; |
| 1073 | 1073 | |
| 1074 | 1074 | /* Automatically call cs_dsp_remove() when test case ends */ |
| 1075 | − return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 1075 | + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); | |
| 1076 | + if (ret) | |
| 1077 | + return ret; | |
| 1078 | + | |
| 1079 | + /* | |
| 1080 | + * Testing error conditions can produce a lot of log output | |
| 1081 | + * from cs_dsp error messages, so suppress messages. | |
| 1082 | + */ | |
| 1083 | + cs_dsp_suppress_err_messages = true; | |
| 1084 | + cs_dsp_suppress_warn_messages = true; | |
| 1085 | + cs_dsp_suppress_info_messages = true; | |
| 1086 | + | |
| 1087 | + return 0; | |
| 1076 | 1088 | } |
| 1077 | 1089 | |
| 1078 | 1090 | static int cs_dsp_wmfw_err_test_halo_init(struct kunit *test) |
| @@ -12,3 +12,4 @@ MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); · 11 unmodified lines | ||
| 12 | 12 | MODULE_LICENSE("GPL"); |
| 13 | 13 | MODULE_IMPORT_NS("FW_CS_DSP"); |
| 14 | 14 | MODULE_IMPORT_NS("FW_CS_DSP_KUNIT_TEST_UTILS"); |
| 15 | +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); | |
| @@ -336,37 +336,43 @@ static bool is_access_interleaved(snd_pcm_access_t access) · 335 unmodified lines | ||
| 336 | 336 | |
| 337 | 337 | static int loopback_check_format(struct loopback_cable *cable, int stream) |
| 338 | 338 | { |
| 339 | + struct loopback_pcm *dpcm_play, *dpcm_capt; | |
| 339 | 340 | struct snd_pcm_runtime *runtime, *cruntime; |
| 340 | 341 | struct loopback_setup *setup; |
| 341 | 342 | struct snd_card *card; |
| 343 | + bool stop_capture = false; | |
| 342 | 344 | int check; |
| 343 | 345 | |
| 344 | − if (cable->valid != CABLE_VALID_BOTH) { | |
| 345 | − if (stream == SNDRV_PCM_STREAM_PLAYBACK) | |
| 346 | − goto __notify; | |
| 347 | − return 0; | |
| 348 | − } | |
| 349 | − runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | |
| 350 | − substream->runtime; | |
| 351 | − cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | |
| 352 | − substream->runtime; | |
| 353 | − check = runtime->format != cruntime->format || | |
| 354 | − runtime->rate != cruntime->rate || | |
| 355 | − runtime->channels != cruntime->channels || | |
| 356 | − is_access_interleaved(runtime->access) != | |
| 357 | − is_access_interleaved(cruntime->access); | |
| 358 | − if (!check) | |
| 359 | − return 0; | |
| 360 | − if (stream == SNDRV_PCM_STREAM_CAPTURE) { | |
| 361 | − return -EIO; | |
| 362 | − } else { | |
| 363 | − snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | |
| 364 | − substream, SNDRV_PCM_STATE_DRAINING); | |
| 365 | − __notify: | |
| 366 | − runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | |
| 367 | − substream->runtime; | |
| 368 | − setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); | |
| 369 | − card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; | |
| 346 | + scoped_guard(spinlock_irqsave, &cable->lock) { | |
| 347 | + dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; | |
| 348 | + dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; | |
| 349 | + | |
| 350 | + if (cable->valid != CABLE_VALID_BOTH) { | |
| 351 | + if (stream == SNDRV_PCM_STREAM_CAPTURE || !dpcm_play) | |
| 352 | + return 0; | |
| 353 | + } else { | |
| 354 | + if (!dpcm_play || !dpcm_capt) | |
| 355 | + return -EIO; | |
| 356 | + runtime = dpcm_play->substream->runtime; | |
| 357 | + cruntime = dpcm_capt->substream->runtime; | |
| 358 | + if (!runtime || !cruntime) | |
| 359 | + return -EIO; | |
| 360 | + check = runtime->format != cruntime->format || | |
| 361 | + runtime->rate != cruntime->rate || | |
| 362 | + runtime->channels != cruntime->channels || | |
| 363 | + is_access_interleaved(runtime->access) != | |
| 364 | + is_access_interleaved(cruntime->access); | |
| 365 | + if (!check) | |
| 366 | + return 0; | |
| 367 | + if (stream == SNDRV_PCM_STREAM_CAPTURE) | |
| 368 | + return -EIO; | |
| 369 | + else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) | |
| 370 | + stop_capture = true; | |
| 371 | + } | |
| 372 | + | |
| 373 | + setup = get_setup(dpcm_play); | |
| 374 | + card = dpcm_play->loopback->card; | |
| 375 | + runtime = dpcm_play->substream->runtime; | |
| 370 | 376 | if (setup->format != runtime->format) { |
| 371 | 377 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, |
| 372 | 378 | &setup->format_id); |
| @@ -389,6 +395,10 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) · 16 unmodified lines | ||
| 389 | 395 | setup->access = runtime->access; |
| 390 | 396 | } |
| 391 | 397 | } |
| 398 | + | |
| 399 | + if (stop_capture) | |
| 400 | + snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING); | |
| 401 | + | |
| 392 | 402 | return 0; |
| 393 | 403 | } |
| 394 | 404 | |
| @@ -6353,6 +6353,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { · 6352 unmodified lines | ||
| 6353 | 6353 | SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), |
| 6354 | 6354 | SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), |
| 6355 | 6355 | SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), |
| 6356 | + SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC), | |
| 6356 | 6357 | SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), |
| 6357 | 6358 | SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), |
| 6358 | 6359 | SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), |
| @@ -301,9 +301,11 @@ static int acp_pdm_dma_close(struct snd_soc_component *component, · 300 unmodified lines | ||
| 301 | 301 | struct snd_pcm_substream *substream) |
| 302 | 302 | { |
| 303 | 303 | struct pdm_dev_data *adata = dev_get_drvdata(component->dev); |
| 304 | + struct pdm_stream_instance *rtd = substream->runtime->private_data; | |
| 304 | 305 | |
| 305 | 306 | disable_pdm_interrupts(adata->acp_base); |
| 306 | 307 | adata->capture_stream = NULL; |
| 308 | + kfree(rtd); | |
| 307 | 309 | return 0; |
| 308 | 310 | } |
| 309 | 311 | |
| @@ -640,6 +640,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { · 639 unmodified lines | ||
| 640 | 640 | DMI_MATCH(DMI_BOARD_NAME, "8BD6"), |
| 641 | 641 | } |
| 642 | 642 | }, |
| 643 | + { | |
| 644 | + .driver_data = &acp6x_card, | |
| 645 | + .matches = { | |
| 646 | + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), | |
| 647 | + DMI_MATCH(DMI_BOARD_NAME, "8EE4"), | |
| 648 | + } | |
| 649 | + }, | |
| 643 | 650 | { |
| 644 | 651 | .driver_data = &acp6x_card, |
| 645 | 652 | .matches = { |
| @@ -496,7 +496,23 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) · 495 unmodified lines | ||
| 496 | 496 | pm_runtime_put_autosuspend(priv->dev); |
| 497 | 497 | } |
| 498 | 498 | |
| 499 | −static void cs42l43_start_load_detect(struct cs42l43_codec *priv) | |
| 499 | +static const struct reg_sequence cs42l43_3pole_patch[] = { | |
| 500 | + { 0x4000, 0x00000055 }, | |
| 501 | + { 0x4000, 0x000000AA }, | |
| 502 | + { 0x17420, 0x8500F300 }, | |
| 503 | + { 0x17424, 0x36003E00 }, | |
| 504 | + { 0x4000, 0x00000000 }, | |
| 505 | +}; | |
| 506 | + | |
| 507 | +static const struct reg_sequence cs42l43_4pole_patch[] = { | |
| 508 | + { 0x4000, 0x00000055 }, | |
| 509 | + { 0x4000, 0x000000AA }, | |
| 510 | + { 0x17420, 0x7800E600 }, | |
| 511 | + { 0x17424, 0x36003800 }, | |
| 512 | + { 0x4000, 0x00000000 }, | |
| 513 | +}; | |
| 514 | + | |
| 515 | +static void cs42l43_start_load_detect(struct cs42l43_codec *priv, bool mic) | |
| 500 | 516 | { |
| 501 | 517 | struct cs42l43 *cs42l43 = priv->core; |
| 502 | 518 | |
| @@ -520,6 +536,15 @@ static void cs42l43_start_load_detect(struct cs42l43_codec *priv) · 17 unmodified lines | ||
| 520 | 536 | dev_err(priv->dev, "Load detect HP power down timed out\n"); |
| 521 | 537 | } |
| 522 | 538 | |
| 539 | + if (mic) | |
| 540 | + regmap_multi_reg_write_bypassed(cs42l43->regmap, | |
| 541 | + cs42l43_4pole_patch, | |
| 542 | + ARRAY_SIZE(cs42l43_4pole_patch)); | |
| 543 | + else | |
| 544 | + regmap_multi_reg_write_bypassed(cs42l43->regmap, | |
| 545 | + cs42l43_3pole_patch, | |
| 546 | + ARRAY_SIZE(cs42l43_3pole_patch)); | |
| 547 | + | |
| 523 | 548 | regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, |
| 524 | 549 | CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0); |
| 525 | 550 | 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) · 72 unmodified lines | ||
| 598 | 623 | |
| 599 | 624 | reinit_completion(&priv->load_detect); |
| 600 | 625 | |
| 601 | − cs42l43_start_load_detect(priv); | |
| 626 | + cs42l43_start_load_detect(priv, mic); | |
| 602 | 627 | time_left = wait_for_completion_timeout(&priv->load_detect, |
| 603 | 628 | msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS)); |
| 604 | 629 | cs42l43_stop_load_detect(priv); |
| @@ -622,11 +647,11 @@ static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic) · 17 unmodified lines | ||
| 622 | 647 | } |
| 623 | 648 | |
| 624 | 649 | switch (val & CS42L43_AMP3_RES_DET_MASK) { |
| 625 | − case 0x0: // low impedance | |
| 626 | − case 0x1: // high impedance | |
| 650 | + case 0x0: // < 22 Ohm impedance | |
| 651 | + case 0x1: // < 150 Ohm impedance | |
| 652 | + case 0x2: // < 1000 Ohm impedance | |
| 627 | 653 | return CS42L43_JACK_HEADPHONE; |
| 628 | − case 0x2: // lineout | |
| 629 | − case 0x3: // Open circuit | |
| 654 | + case 0x3: // > 1000 Ohm impedance | |
| 630 | 655 | return CS42L43_JACK_LINEOUT; |
| 631 | 656 | default: |
| 632 | 657 | return -EINVAL; |
| @@ -203,6 +203,7 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { · 202 unmodified lines | ||
| 203 | 203 | { 0x3fc2bfc2, 0x00 }, |
| 204 | 204 | { 0x3fc2bfc1, 0x00 }, |
| 205 | 205 | { 0x3fc2bfc0, 0x07 }, |
| 206 | + { 0x1000cc46, 0x00 }, | |
| 206 | 207 | { 0x0000d486, 0x43 }, |
| 207 | 208 | { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 }, |
| 208 | 209 | { 0x1000db00, 0x07 }, |
| @@ -354,6 +355,7 @@ static const struct reg_sequence rt1321_blind_write[] = { · 145 unmodified lines | ||
| 354 | 355 | { 0x0000d73d, 0xd7 }, |
| 355 | 356 | { 0x0000d73e, 0x00 }, |
| 356 | 357 | { 0x0000d73f, 0x10 }, |
| 358 | + { 0x1000cd56, 0x00 }, | |
| 357 | 359 | { 0x3fc2dfc3, 0x00 }, |
| 358 | 360 | { 0x3fc2dfc2, 0x00 }, |
| 359 | 361 | { 0x3fc2dfc1, 0x00 }, |
| @@ -223,10 +223,13 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, · 222 unmodified lines | ||
| 223 | 223 | |
| 224 | 224 | xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); |
| 225 | 225 | |
| 226 | + down_read(&card->snd_card->controls_rwsem); | |
| 226 | 227 | fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, |
| 227 | 228 | (xcvr->mode == FSL_XCVR_MODE_ARC)); |
| 228 | 229 | fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, |
| 229 | 230 | (xcvr->mode == FSL_XCVR_MODE_EARC)); |
| 231 | + up_read(&card->snd_card->controls_rwsem); | |
| 232 | + | |
| 230 | 233 | /* Allow playback for SPDIF only */ |
| 231 | 234 | rtd = snd_soc_get_pcm_runtime(card, card->dai_link); |
| 232 | 235 | rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = |
| @@ -334,6 +334,15 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id) · 333 unmodified lines | ||
| 334 | 334 | * if the topology file is modified as well. |
| 335 | 335 | */ |
| 336 | 336 | static const struct dmi_system_id sof_es8336_quirk_table[] = { |
| 337 | + { | |
| 338 | + .callback = sof_es8336_quirk_cb, | |
| 339 | + .matches = { | |
| 340 | + DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), | |
| 341 | + DMI_MATCH(DMI_PRODUCT_NAME, "BOD-WXX9"), | |
| 342 | + }, | |
| 343 | + .driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO | | |
| 344 | + SOF_ES8336_ENABLE_DMIC) | |
| 345 | + }, | |
| 337 | 346 | { |
| 338 | 347 | .callback = sof_es8336_quirk_cb, |
| 339 | 348 | .matches = { |
| @@ -1304,9 +1304,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev · 1303 unmodified lines | ||
| 1304 | 1304 | int i; |
| 1305 | 1305 | |
| 1306 | 1306 | hdev = pdata->hw_pdata; |
| 1307 | − link_mask = hdev->info.link_mask; | |
| 1308 | 1307 | |
| 1309 | − if (!link_mask) { | |
| 1308 | + if (!hdev->info.link_mask) { | |
| 1310 | 1309 | dev_info(sdev->dev, "SoundWire links not enabled\n"); |
| 1311 | 1310 | return NULL; |
| 1312 | 1311 | } |
| @@ -1337,7 +1336,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev · 24 unmodified lines | ||
| 1337 | 1336 | * link_mask supported by hw and then go on searching |
| 1338 | 1337 | * link_adr |
| 1339 | 1338 | */ |
| 1340 | − if (~link_mask & mach->link_mask) | |
| 1339 | + if (~hdev->info.link_mask & mach->link_mask) | |
| 1341 | 1340 | continue; |
| 1342 | 1341 | |
| 1343 | 1342 | /* No need to match adr if there is no links defined */ |
| @@ -311,13 +311,8 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, · 310 unmodified lines | ||
| 311 | 311 | if (pm.err < 0) |
| 312 | 312 | return pm.err; |
| 313 | 313 | |
| 314 | − if (chip->usb_id == USB_ID(0x041e, 0x3042)) | |
| 315 | − err = snd_usb_ctl_msg(chip->dev, | |
| 316 | − usb_sndctrlpipe(chip->dev, 0), 0x24, | |
| 317 | − USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | |
| 318 | − !value, 0, NULL, 0); | |
| 319 | − /* USB X-Fi S51 Pro */ | |
| 320 | − if (chip->usb_id == USB_ID(0x041e, 0x30df)) | |
| 314 | + if (chip->usb_id == USB_ID(0x041e, 0x3042) || /* USB X-Fi S51 */ | |
| 315 | + chip->usb_id == USB_ID(0x041e, 0x30df)) /* USB X-Fi S51 Pro */ | |
| 321 | 316 | err = snd_usb_ctl_msg(chip->dev, |
| 322 | 317 | usb_sndctrlpipe(chip->dev, 0), 0x24, |
| 323 | 318 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, |