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 | properties: | 46 | properties: |
| 47 | compatible: | 47 | compatible: |
| 48 | enum: | 48 | enum: |
| 49 | - ti,tlv320aic23 | ||
| 49 | - ti,tlv320aic3x | 50 | - ti,tlv320aic3x |
| 50 | - ti,tlv320aic33 | 51 | - ti,tlv320aic33 |
| 51 | - ti,tlv320aic3007 | 52 | - ti,tlv320aic3007 |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | * Cirrus Logic International Semiconductor Ltd. | 9 | * Cirrus Logic International Semiconductor Ltd. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <kunit/visibility.h> | ||
| 12 | #include <linux/cleanup.h> | 13 | #include <linux/cleanup.h> |
| 13 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
| 14 | #include <linux/debugfs.h> | 15 | #include <linux/debugfs.h> |
| @@ -24,6 +25,41 @@ · 9 unmodified lines | |||
| 24 | #include <linux/firmware/cirrus/cs_dsp.h> | 25 | #include <linux/firmware/cirrus/cs_dsp.h> |
| 25 | #include <linux/firmware/cirrus/wmfw.h> | 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 | #define cs_dsp_err(_dsp, fmt, ...) \ | 63 | #define cs_dsp_err(_dsp, fmt, ...) \ |
| 28 | dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) | 64 | dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
| 29 | #define cs_dsp_warn(_dsp, fmt, ...) \ | 65 | #define cs_dsp_warn(_dsp, fmt, ...) \ |
| @@ -32,6 +68,7 @@ · 2 unmodified lines | |||
| 32 | dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) | 68 | dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
| 33 | #define cs_dsp_dbg(_dsp, fmt, ...) \ | 69 | #define cs_dsp_dbg(_dsp, fmt, ...) \ |
| 34 | dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) | 70 | dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
| 71 | #endif | ||
| 35 | 72 | ||
| 36 | #define ADSP1_CONTROL_1 0x00 | 73 | #define ADSP1_CONTROL_1 0x00 |
| 37 | #define ADSP1_CONTROL_2 0x02 | 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 | #include <linux/random.h> | 17 | #include <linux/random.h> |
| 18 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
| 19 | 19 | ||
| 20 | #include "../cs_dsp.h" | ||
| 21 | |||
| 20 | /* | 22 | /* |
| 21 | * Test method is: | 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 | return ret; | 2226 | return ret; |
| 2225 | 2227 | ||
| 2226 | /* Automatically call cs_dsp_remove() when test case ends */ | 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 | static int cs_dsp_bin_test_halo_init(struct kunit *test) | 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 | static struct kunit_suite cs_dsp_bin_test_halo = { | 2553 | static struct kunit_suite cs_dsp_bin_test_halo = { |
| 2537 | .name = "cs_dsp_bin_halo", | 2554 | .name = "cs_dsp_bin_halo", |
| 2538 | .init = cs_dsp_bin_test_halo_init, | 2555 | .init = cs_dsp_bin_test_halo_init, |
| 2556 | .exit = cs_dsp_bin_test_exit, | ||
| 2539 | .test_cases = cs_dsp_bin_test_cases_halo, | 2557 | .test_cases = cs_dsp_bin_test_cases_halo, |
| 2540 | }; | 2558 | }; |
| 2541 | 2559 | ||
| 2542 | static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = { | 2560 | static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = { |
| 2543 | .name = "cs_dsp_bin_adsp2_32bit", | 2561 | .name = "cs_dsp_bin_adsp2_32bit", |
| 2544 | .init = cs_dsp_bin_test_adsp2_32bit_init, | 2562 | .init = cs_dsp_bin_test_adsp2_32bit_init, |
| 2563 | .exit = cs_dsp_bin_test_exit, | ||
| 2545 | .test_cases = cs_dsp_bin_test_cases_adsp2, | 2564 | .test_cases = cs_dsp_bin_test_cases_adsp2, |
| 2546 | }; | 2565 | }; |
| 2547 | 2566 | ||
| 2548 | static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = { | 2567 | static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = { |
| 2549 | .name = "cs_dsp_bin_adsp2_16bit", | 2568 | .name = "cs_dsp_bin_adsp2_16bit", |
| 2550 | .init = cs_dsp_bin_test_adsp2_16bit_init, | 2569 | .init = cs_dsp_bin_test_adsp2_16bit_init, |
| 2570 | .exit = cs_dsp_bin_test_exit, | ||
| 2551 | .test_cases = cs_dsp_bin_test_cases_adsp2, | 2571 | .test_cases = cs_dsp_bin_test_cases_adsp2, |
| 2552 | }; | 2572 | }; |
| 2553 | 2573 | ||
| @@ -18,6 +18,8 @@ · 17 unmodified lines | |||
| 18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | ||
| 21 | #include "../cs_dsp.h" | ||
| 22 | |||
| 21 | KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); | 23 | KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); |
| 22 | KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *); | 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 | static void cs_dsp_bin_err_test_exit(struct kunit *test) | 383 | static void cs_dsp_bin_err_test_exit(struct kunit *test) |
| 382 | { | 384 | { |
| 383 | /* | 385 | cs_dsp_suppress_err_messages = false; |
| 384 | * Testing error conditions can produce a lot of log output | 386 | cs_dsp_suppress_warn_messages = false; |
| 385 | * from cs_dsp error messages, so rate limit the test cases. | 387 | cs_dsp_suppress_info_messages = false; |
| 386 | */ | ||
| 387 | usleep_range(200, 500); | ||
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *dsp, | 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 | return ret; | 474 | return ret; |
| 475 | 475 | ||
| 476 | /* Automatically call cs_dsp_remove() when test case ends */ | 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 | static int cs_dsp_bin_err_test_halo_init(struct kunit *test) | 492 | static int cs_dsp_bin_err_test_halo_init(struct kunit *test) |
| @@ -18,6 +18,8 @@ · 17 unmodified lines | |||
| 18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | ||
| 21 | #include "../cs_dsp.h" | ||
| 22 | |||
| 21 | /* | 23 | /* |
| 22 | * Test method is: | 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 | return ret; | 1855 | return ret; |
| 1854 | 1856 | ||
| 1855 | /* Automatically call cs_dsp_remove() when test case ends */ | 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 | static int cs_dsp_wmfw_test_halo_init(struct kunit *test) | 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 | static struct kunit_suite cs_dsp_wmfw_test_halo = { | 2180 | static struct kunit_suite cs_dsp_wmfw_test_halo = { |
| 2164 | .name = "cs_dsp_wmfwV3_halo", | 2181 | .name = "cs_dsp_wmfwV3_halo", |
| 2165 | .init = cs_dsp_wmfw_test_halo_init, | 2182 | .init = cs_dsp_wmfw_test_halo_init, |
| 2183 | .exit = cs_dsp_wmfw_test_exit, | ||
| 2166 | .test_cases = cs_dsp_wmfw_test_cases_halo, | 2184 | .test_cases = cs_dsp_wmfw_test_cases_halo, |
| 2167 | }; | 2185 | }; |
| 2168 | 2186 | ||
| 2169 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = { | 2187 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = { |
| 2170 | .name = "cs_dsp_wmfwV0_adsp2_32bit", | 2188 | .name = "cs_dsp_wmfwV0_adsp2_32bit", |
| 2171 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init, | 2189 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init, |
| 2190 | .exit = cs_dsp_wmfw_test_exit, | ||
| 2172 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, | 2191 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2173 | }; | 2192 | }; |
| 2174 | 2193 | ||
| 2175 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = { | 2194 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = { |
| 2176 | .name = "cs_dsp_wmfwV1_adsp2_32bit", | 2195 | .name = "cs_dsp_wmfwV1_adsp2_32bit", |
| 2177 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init, | 2196 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init, |
| 2197 | .exit = cs_dsp_wmfw_test_exit, | ||
| 2178 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, | 2198 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2179 | }; | 2199 | }; |
| 2180 | 2200 | ||
| 2181 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = { | 2201 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = { |
| 2182 | .name = "cs_dsp_wmfwV2_adsp2_32bit", | 2202 | .name = "cs_dsp_wmfwV2_adsp2_32bit", |
| 2183 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init, | 2203 | .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init, |
| 2204 | .exit = cs_dsp_wmfw_test_exit, | ||
| 2184 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, | 2205 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2185 | }; | 2206 | }; |
| 2186 | 2207 | ||
| 2187 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = { | 2208 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = { |
| 2188 | .name = "cs_dsp_wmfwV0_adsp2_16bit", | 2209 | .name = "cs_dsp_wmfwV0_adsp2_16bit", |
| 2189 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init, | 2210 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init, |
| 2211 | .exit = cs_dsp_wmfw_test_exit, | ||
| 2190 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, | 2212 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2191 | }; | 2213 | }; |
| 2192 | 2214 | ||
| 2193 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = { | 2215 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = { |
| 2194 | .name = "cs_dsp_wmfwV1_adsp2_16bit", | 2216 | .name = "cs_dsp_wmfwV1_adsp2_16bit", |
| 2195 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init, | 2217 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init, |
| 2218 | .exit = cs_dsp_wmfw_test_exit, | ||
| 2196 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, | 2219 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2197 | }; | 2220 | }; |
| 2198 | 2221 | ||
| 2199 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = { | 2222 | static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = { |
| 2200 | .name = "cs_dsp_wmfwV2_adsp2_16bit", | 2223 | .name = "cs_dsp_wmfwV2_adsp2_16bit", |
| 2201 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init, | 2224 | .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init, |
| 2225 | .exit = cs_dsp_wmfw_test_exit, | ||
| 2202 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, | 2226 | .test_cases = cs_dsp_wmfw_test_cases_adsp2, |
| 2203 | }; | 2227 | }; |
| 2204 | 2228 | ||
| @@ -18,6 +18,8 @@ · 17 unmodified lines | |||
| 18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | ||
| 21 | #include "../cs_dsp.h" | ||
| 22 | |||
| 21 | KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); | 23 | KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); |
| 22 | KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *); | 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 | static void cs_dsp_wmfw_err_test_exit(struct kunit *test) | 992 | static void cs_dsp_wmfw_err_test_exit(struct kunit *test) |
| 991 | { | 993 | { |
| 992 | /* | 994 | cs_dsp_suppress_err_messages = false; |
| 993 | * Testing error conditions can produce a lot of log output | 995 | cs_dsp_suppress_warn_messages = false; |
| 994 | * from cs_dsp error messages, so rate limit the test cases. | 996 | cs_dsp_suppress_info_messages = false; |
| 995 | */ | ||
| 996 | usleep_range(200, 500); | ||
| 997 | } | 997 | } |
| 998 | 998 | ||
| 999 | static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp, | 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 | return ret; | 1072 | return ret; |
| 1073 | 1073 | ||
| 1074 | /* Automatically call cs_dsp_remove() when test case ends */ | 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 | static int cs_dsp_wmfw_err_test_halo_init(struct kunit *test) | 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 | MODULE_LICENSE("GPL"); | 12 | MODULE_LICENSE("GPL"); |
| 13 | MODULE_IMPORT_NS("FW_CS_DSP"); | 13 | MODULE_IMPORT_NS("FW_CS_DSP"); |
| 14 | MODULE_IMPORT_NS("FW_CS_DSP_KUNIT_TEST_UTILS"); | 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 | static int loopback_check_format(struct loopback_cable *cable, int stream) | 337 | static int loopback_check_format(struct loopback_cable *cable, int stream) |
| 338 | { | 338 | { |
| 339 | struct loopback_pcm *dpcm_play, *dpcm_capt; | ||
| 339 | struct snd_pcm_runtime *runtime, *cruntime; | 340 | struct snd_pcm_runtime *runtime, *cruntime; |
| 340 | struct loopback_setup *setup; | 341 | struct loopback_setup *setup; |
| 341 | struct snd_card *card; | 342 | struct snd_card *card; |
| 343 | bool stop_capture = false; | ||
| 342 | int check; | 344 | int check; |
| 343 | 345 | ||
| 344 | if (cable->valid != CABLE_VALID_BOTH) { | 346 | scoped_guard(spinlock_irqsave, &cable->lock) { |
| 345 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 347 | dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
| 346 | goto __notify; | 348 | dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; |
| 347 | return 0; | 349 | |
| 348 | } | 350 | if (cable->valid != CABLE_VALID_BOTH) { |
| 349 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | 351 | if (stream == SNDRV_PCM_STREAM_CAPTURE || !dpcm_play) |
| 350 | substream->runtime; | 352 | return 0; |
| 351 | cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | 353 | } else { |
| 352 | substream->runtime; | 354 | if (!dpcm_play || !dpcm_capt) |
| 353 | check = runtime->format != cruntime->format || | 355 | return -EIO; |
| 354 | runtime->rate != cruntime->rate || | 356 | runtime = dpcm_play->substream->runtime; |
| 355 | runtime->channels != cruntime->channels || | 357 | cruntime = dpcm_capt->substream->runtime; |
| 356 | is_access_interleaved(runtime->access) != | 358 | if (!runtime || !cruntime) |
| 357 | is_access_interleaved(cruntime->access); | 359 | return -EIO; |
| 358 | if (!check) | 360 | check = runtime->format != cruntime->format || |
| 359 | return 0; | 361 | runtime->rate != cruntime->rate || |
| 360 | if (stream == SNDRV_PCM_STREAM_CAPTURE) { | 362 | runtime->channels != cruntime->channels || |
| 361 | return -EIO; | 363 | is_access_interleaved(runtime->access) != |
| 362 | } else { | 364 | is_access_interleaved(cruntime->access); |
| 363 | snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | 365 | if (!check) |
| 364 | substream, SNDRV_PCM_STATE_DRAINING); | 366 | return 0; |
| 365 | __notify: | 367 | if (stream == SNDRV_PCM_STREAM_CAPTURE) |
| 366 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | 368 | return -EIO; |
| 367 | substream->runtime; | 369 | else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) |
| 368 | setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); | 370 | stop_capture = true; |
| 369 | card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; | 371 | } |
| 372 | |||
| 373 | setup = get_setup(dpcm_play); | ||
| 374 | card = dpcm_play->loopback->card; | ||
| 375 | runtime = dpcm_play->substream->runtime; | ||
| 370 | if (setup->format != runtime->format) { | 376 | if (setup->format != runtime->format) { |
| 371 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | 377 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, |
| 372 | &setup->format_id); | 378 | &setup->format_id); |
| @@ -389,6 +395,10 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) · 16 unmodified lines | |||
| 389 | setup->access = runtime->access; | 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 | return 0; | 402 | return 0; |
| 393 | } | 403 | } |
| 394 | 404 | ||
| @@ -6353,6 +6353,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { · 6352 unmodified lines | |||
| 6353 | SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), | 6353 | SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), |
| 6354 | SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), | 6354 | SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), |
| 6355 | SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), | 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 | SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), | 6357 | SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), |
| 6357 | SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), | 6358 | SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), |
| 6358 | SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), | 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 | struct snd_pcm_substream *substream) | 301 | struct snd_pcm_substream *substream) |
| 302 | { | 302 | { |
| 303 | struct pdm_dev_data *adata = dev_get_drvdata(component->dev); | 303 | struct pdm_dev_data *adata = dev_get_drvdata(component->dev); |
| 304 | struct pdm_stream_instance *rtd = substream->runtime->private_data; | ||
| 304 | 305 | ||
| 305 | disable_pdm_interrupts(adata->acp_base); | 306 | disable_pdm_interrupts(adata->acp_base); |
| 306 | adata->capture_stream = NULL; | 307 | adata->capture_stream = NULL; |
| 308 | kfree(rtd); | ||
| 307 | return 0; | 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 | DMI_MATCH(DMI_BOARD_NAME, "8BD6"), | 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 | .driver_data = &acp6x_card, | 651 | .driver_data = &acp6x_card, |
| 645 | .matches = { | 652 | .matches = { |
| @@ -496,7 +496,23 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) · 495 unmodified lines | |||
| 496 | pm_runtime_put_autosuspend(priv->dev); | 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 | struct cs42l43 *cs42l43 = priv->core; | 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 | dev_err(priv->dev, "Load detect HP power down timed out\n"); | 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 | regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, | 548 | regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, |
| 524 | CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0); | 549 | CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0); |
| 525 | regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, CS42L43_HP_HPF_EN_MASK, 0); | 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 | reinit_completion(&priv->load_detect); | 624 | reinit_completion(&priv->load_detect); |
| 600 | 625 | ||
| 601 | cs42l43_start_load_detect(priv); | 626 | cs42l43_start_load_detect(priv, mic); |
| 602 | time_left = wait_for_completion_timeout(&priv->load_detect, | 627 | time_left = wait_for_completion_timeout(&priv->load_detect, |
| 603 | msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS)); | 628 | msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS)); |
| 604 | cs42l43_stop_load_detect(priv); | 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 | switch (val & CS42L43_AMP3_RES_DET_MASK) { | 649 | switch (val & CS42L43_AMP3_RES_DET_MASK) { |
| 625 | case 0x0: // low impedance | 650 | case 0x0: // < 22 Ohm impedance |
| 626 | case 0x1: // high impedance | 651 | case 0x1: // < 150 Ohm impedance |
| 652 | case 0x2: // < 1000 Ohm impedance | ||
| 627 | return CS42L43_JACK_HEADPHONE; | 653 | return CS42L43_JACK_HEADPHONE; |
| 628 | case 0x2: // lineout | 654 | case 0x3: // > 1000 Ohm impedance |
| 629 | case 0x3: // Open circuit | ||
| 630 | return CS42L43_JACK_LINEOUT; | 655 | return CS42L43_JACK_LINEOUT; |
| 631 | default: | 656 | default: |
| 632 | return -EINVAL; | 657 | return -EINVAL; |
| @@ -203,6 +203,7 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { · 202 unmodified lines | |||
| 203 | { 0x3fc2bfc2, 0x00 }, | 203 | { 0x3fc2bfc2, 0x00 }, |
| 204 | { 0x3fc2bfc1, 0x00 }, | 204 | { 0x3fc2bfc1, 0x00 }, |
| 205 | { 0x3fc2bfc0, 0x07 }, | 205 | { 0x3fc2bfc0, 0x07 }, |
| 206 | { 0x1000cc46, 0x00 }, | ||
| 206 | { 0x0000d486, 0x43 }, | 207 | { 0x0000d486, 0x43 }, |
| 207 | { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 }, | 208 | { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 }, |
| 208 | { 0x1000db00, 0x07 }, | 209 | { 0x1000db00, 0x07 }, |
| @@ -354,6 +355,7 @@ static const struct reg_sequence rt1321_blind_write[] = { · 145 unmodified lines | |||
| 354 | { 0x0000d73d, 0xd7 }, | 355 | { 0x0000d73d, 0xd7 }, |
| 355 | { 0x0000d73e, 0x00 }, | 356 | { 0x0000d73e, 0x00 }, |
| 356 | { 0x0000d73f, 0x10 }, | 357 | { 0x0000d73f, 0x10 }, |
| 358 | { 0x1000cd56, 0x00 }, | ||
| 357 | { 0x3fc2dfc3, 0x00 }, | 359 | { 0x3fc2dfc3, 0x00 }, |
| 358 | { 0x3fc2dfc2, 0x00 }, | 360 | { 0x3fc2dfc2, 0x00 }, |
| 359 | { 0x3fc2dfc1, 0x00 }, | 361 | { 0x3fc2dfc1, 0x00 }, |
| @@ -223,10 +223,13 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, · 222 unmodified lines | |||
| 223 | 223 | ||
| 224 | xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); | 224 | xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); |
| 225 | 225 | ||
| 226 | down_read(&card->snd_card->controls_rwsem); | ||
| 226 | fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, | 227 | fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, |
| 227 | (xcvr->mode == FSL_XCVR_MODE_ARC)); | 228 | (xcvr->mode == FSL_XCVR_MODE_ARC)); |
| 228 | fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, | 229 | fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, |
| 229 | (xcvr->mode == FSL_XCVR_MODE_EARC)); | 230 | (xcvr->mode == FSL_XCVR_MODE_EARC)); |
| 231 | up_read(&card->snd_card->controls_rwsem); | ||
| 232 | |||
| 230 | /* Allow playback for SPDIF only */ | 233 | /* Allow playback for SPDIF only */ |
| 231 | rtd = snd_soc_get_pcm_runtime(card, card->dai_link); | 234 | rtd = snd_soc_get_pcm_runtime(card, card->dai_link); |
| 232 | rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = | 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 | * if the topology file is modified as well. | 334 | * if the topology file is modified as well. |
| 335 | */ | 335 | */ |
| 336 | static const struct dmi_system_id sof_es8336_quirk_table[] = { | 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 | .callback = sof_es8336_quirk_cb, | 347 | .callback = sof_es8336_quirk_cb, |
| 339 | .matches = { | 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 | int i; | 1304 | int i; |
| 1305 | 1305 | ||
| 1306 | hdev = pdata->hw_pdata; | 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 | dev_info(sdev->dev, "SoundWire links not enabled\n"); | 1309 | dev_info(sdev->dev, "SoundWire links not enabled\n"); |
| 1311 | return NULL; | 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 | * link_mask supported by hw and then go on searching | 1336 | * link_mask supported by hw and then go on searching |
| 1338 | * link_adr | 1337 | * link_adr |
| 1339 | */ | 1338 | */ |
| 1340 | if (~link_mask & mach->link_mask) | 1339 | if (~hdev->info.link_mask & mach->link_mask) |
| 1341 | continue; | 1340 | continue; |
| 1342 | 1341 | ||
| 1343 | /* No need to match adr if there is no links defined */ | 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 | if (pm.err < 0) | 311 | if (pm.err < 0) |
| 312 | return pm.err; | 312 | return pm.err; |
| 313 | 313 | ||
| 314 | if (chip->usb_id == USB_ID(0x041e, 0x3042)) | 314 | if (chip->usb_id == USB_ID(0x041e, 0x3042) || /* USB X-Fi S51 */ |
| 315 | err = snd_usb_ctl_msg(chip->dev, | 315 | chip->usb_id == USB_ID(0x041e, 0x30df)) /* USB X-Fi S51 Pro */ |
| 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)) | ||
| 321 | err = snd_usb_ctl_msg(chip->dev, | 316 | err = snd_usb_ctl_msg(chip->dev, |
| 322 | usb_sndctrlpipe(chip->dev, 0), 0x24, | 317 | usb_sndctrlpipe(chip->dev, 0), 0x24, |
| 323 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | 318 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, |