summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-24 11:49:20 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-24 11:49:20 -0700
commit1fe93b2a2ace9bba2cb90920f9300834e537665c (patch)
treec6c53d4a4348603d1da32922903c9e35b2045b40
parentcf950766e96e36c90871d955cfd2a2c1feddba37 (diff)
parent2724fbc90e5c133fbbd030e72fe8a3869a20df08 (diff)
Merge tag 'sound-fix-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai: "Here are the rest of small updates for 7.1-rc1. All small fixes mostly for device-specific issues or regressions. Core: - Fix a potential data race in fasync handling USB-audio: - New device support: Line6 POD HD PRO, NexiGo N930W webcam - Fixes for Audio Advantage Micro II SPDIF switch and E-MU sample rates - Limit UAC2 rate parsing to prevent potential overflows HD-Audio: - Device-specific quirks for HP, Acer, and Honor laptops - Fix for TAS2781 SPI device abnormal sound - Move Intel firmware loading into probe work to avoid stalling ASoC: - New support for TI TAS5832 - Fixes for SoundWire SDCA/DisCo boolean parsing - Driver-specific fixes for Intel SOF, ES8311, RT1320, and PXA2xx Misc: - Fixes for resource leaks and data races in 6fire, caiaq, als4000, and pcmtest drivers" * tag 'sound-fix-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (41 commits) Revert "ALSA: pcmtest: fix reference leak on failed device registration" ASoC: tas2781: Add tas5832 support ASoC: dt-bindings: ti,tas2781: Add TAS5832 support ALSA: usb-audio: Fix Audio Advantage Micro II SPDIF switch ALSA: usb-audio: Avoid false E-MU sample-rate notifications ASoC: sdw_utils: cs42l43: allow spk component names to be combined ASoC: qcom: x1e80100: limit speaker volumes ALSA: hda/realtek - Add mute LED support for HP Victus 15-fa2xxx ALSA: pcmtest: Fix resource leaks in module init error paths ALSA: usb-audio/line6: Add support for POD HD PRO ALSA: hda/realtek: Add LED fixup for HP EliteBook 6 G2a Laptops ASoC: SDCA: Fix reading of mipi-sdca-control-deferrable regmap: sdw-mbq: Allow defers on undeferrable controls Revert "ALSA: usb-audio: Add quirk for SmartlinkTechnology M01" ALSA: als4000: Fix capture trigger chip->mode race ALSA: core: Fix potential data race at fasync handling ALSA: hda/tas2781: Fix sound abnormal issue on some SPI device ALSA: hda/realtek: add quirk for Acer Nitro 16 AN16-41 ALSA: caiaq: Fix control_put() result and cache rollback ALSA: pcmtest: fix reference leak on failed device registration ...
-rw-r--r--Documentation/devicetree/bindings/sound/ti,tas2781.yaml7
-rw-r--r--drivers/base/regmap/regmap-sdw-mbq.c36
-rw-r--r--include/sound/tas2781.h1
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c15
-rw-r--r--sound/core/misc.c13
-rw-r--r--sound/drivers/pcmtest.c15
-rw-r--r--sound/drivers/vx/vx_cmd.h2
-rw-r--r--sound/hda/codecs/realtek/alc269.c17
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_spi.c1
-rw-r--r--sound/hda/common/hda_controller.h4
-rw-r--r--sound/hda/controllers/intel.c58
-rw-r--r--sound/pci/als4000.c44
-rw-r--r--sound/soc/codecs/es8311.c22
-rw-r--r--sound/soc/codecs/rt1320-sdw.c1
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c7
-rw-r--r--sound/soc/codecs/tas2781-i2c.c15
-rw-r--r--sound/soc/qcom/x1e80100.c19
-rw-r--r--sound/soc/sdca/sdca_functions.c7
-rw-r--r--sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c6
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs42l43.c12
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c20
-rw-r--r--sound/soc/sof/intel/nvl.c2
-rw-r--r--sound/usb/6fire/chip.c115
-rw-r--r--sound/usb/6fire/control.c10
-rw-r--r--sound/usb/caiaq/control.c52
-rw-r--r--sound/usb/caiaq/device.c33
-rw-r--r--sound/usb/format.c2
-rw-r--r--sound/usb/line6/podhd.c14
-rw-r--r--sound/usb/mixer.c34
-rw-r--r--sound/usb/mixer_quirks.c12
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--sound/virtio/virtio_pcm.h1
32 files changed, 340 insertions, 259 deletions
diff --git a/Documentation/devicetree/bindings/sound/ti,tas2781.yaml b/Documentation/devicetree/bindings/sound/ti,tas2781.yaml
index f3a5638f4239..b21466bb0730 100644
--- a/Documentation/devicetree/bindings/sound/ti,tas2781.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tas2781.yaml
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-# Copyright (C) 2022 - 2025 Texas Instruments Incorporated
+# Copyright (C) 2022 - 2026 Texas Instruments Incorporated
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,tas2781.yaml#
@@ -107,6 +107,9 @@ properties:
ti,tas5830: 65-W Stereo, Digital Input, High Efficiency Closed-Loop
Class-D Amplifier with Class-H Algorithm
+
+ ti,tas5832: 81-W Stereo, Digital Input, High Efficiency Closed-Loop
+ Class-D Amplifier with Class-H Algorithm
oneOf:
- items:
- enum:
@@ -128,6 +131,7 @@ properties:
- ti,tas5827
- ti,tas5828
- ti,tas5830
+ - ti,tas5832
- const: ti,tas2781
- enum:
- ti,tas2781
@@ -264,6 +268,7 @@ allOf:
- ti,tas5827
- ti,tas5828
- ti,tas5830
+ - ti,tas5832
then:
properties:
reg:
diff --git a/drivers/base/regmap/regmap-sdw-mbq.c b/drivers/base/regmap/regmap-sdw-mbq.c
index 6a61629f5f89..4533fe793c5f 100644
--- a/drivers/base/regmap/regmap-sdw-mbq.c
+++ b/drivers/base/regmap/regmap-sdw-mbq.c
@@ -74,7 +74,7 @@ static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
unsigned int reg, unsigned int val,
- int mbq_size, bool deferrable)
+ int mbq_size)
{
int shift = mbq_size * BITS_PER_BYTE;
int ret;
@@ -88,17 +88,14 @@ static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
return ret;
}
- ret = sdw_write_no_pm(slave, reg, val & 0xff);
- if (deferrable && ret == -ENODATA)
- return -EAGAIN;
-
- return ret;
+ return sdw_write_no_pm(slave, reg, val & 0xff);
}
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
{
struct regmap_mbq_context *ctx = context;
struct sdw_slave *slave = ctx->sdw;
+ struct device *dev = ctx->dev;
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
int ret;
@@ -113,13 +110,16 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
* process a single wait/timeout on function busy and a single retry
* of the transaction.
*/
- ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, deferrable);
- if (ret == -EAGAIN) {
+ ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size);
+ if (ret == -ENODATA) {
+ if (!deferrable)
+ dev_warn(dev, "Defer on undeferrable control: %x\n", reg);
+
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
if (ret)
return ret;
- ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, false);
+ ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size);
}
return ret;
@@ -127,18 +127,14 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
static int regmap_sdw_mbq_read_impl(struct sdw_slave *slave,
unsigned int reg, unsigned int *val,
- int mbq_size, bool deferrable)
+ int mbq_size)
{
int shift = BITS_PER_BYTE;
int read;
read = sdw_read_no_pm(slave, reg);
- if (read < 0) {
- if (deferrable && read == -ENODATA)
- return -EAGAIN;
-
+ if (read < 0)
return read;
- }
*val = read;
@@ -158,6 +154,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
{
struct regmap_mbq_context *ctx = context;
struct sdw_slave *slave = ctx->sdw;
+ struct device *dev = ctx->dev;
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
int ret;
@@ -172,13 +169,16 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
* process a single wait/timeout on function busy and a single retry
* of the transaction.
*/
- ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, deferrable);
- if (ret == -EAGAIN) {
+ ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
+ if (ret == -ENODATA) {
+ if (!deferrable)
+ dev_warn(dev, "Defer on undeferable control: %x\n", reg);
+
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
if (ret)
return ret;
- ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, false);
+ ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
}
return ret;
diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
index e847cf51878c..95296bb4a33a 100644
--- a/include/sound/tas2781.h
+++ b/include/sound/tas2781.h
@@ -131,6 +131,7 @@ enum audio_device {
TAS5827,
TAS5828,
TAS5830,
+ TAS5832,
TAS_OTHERS,
};
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index 1e114dbcf93c..79eb557d4942 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -331,12 +331,15 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
if (dev->dev.of_node) {
/* Assert reset using GPIOD_OUT_HIGH, because reset is GPIO_ACTIVE_LOW */
rst_gpio = devm_gpiod_get(&dev->dev, "reset", GPIOD_OUT_HIGH);
- ret = PTR_ERR(rst_gpio);
- if (ret == -ENOENT)
- reset_gpio = -1;
- else if (ret)
- return ret;
- reset_gpio = desc_to_gpio(rst_gpio);
+ if (IS_ERR(rst_gpio)) {
+ ret = PTR_ERR(rst_gpio);
+ if (ret == -ENOENT)
+ reset_gpio = -1;
+ else if (ret)
+ return ret;
+ } else {
+ reset_gpio = desc_to_gpio(rst_gpio);
+ }
} else {
if (cpu_is_pxa27x())
reset_gpio = 113;
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 88d9e1f9a6e9..5aca09edf971 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -100,14 +100,18 @@ static LIST_HEAD(snd_fasync_list);
static void snd_fasync_work_fn(struct work_struct *work)
{
struct snd_fasync *fasync;
+ int signal, poll;
spin_lock_irq(&snd_fasync_lock);
while (!list_empty(&snd_fasync_list)) {
fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list);
list_del_init(&fasync->list);
+ if (!fasync->on)
+ continue;
+ signal = fasync->signal;
+ poll = fasync->poll;
spin_unlock_irq(&snd_fasync_lock);
- if (fasync->on)
- kill_fasync(&fasync->fasync, fasync->signal, fasync->poll);
+ kill_fasync(&fasync->fasync, signal, poll);
spin_lock_irq(&snd_fasync_lock);
}
spin_unlock_irq(&snd_fasync_lock);
@@ -158,7 +162,10 @@ void snd_fasync_free(struct snd_fasync *fasync)
{
if (!fasync)
return;
- fasync->on = 0;
+
+ scoped_guard(spinlock_irq, &snd_fasync_lock)
+ list_del_init(&fasync->list);
+
flush_work(&snd_fasync_work);
kfree(fasync);
}
diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c
index 768bb698adfb..5bfec4c7bf71 100644
--- a/sound/drivers/pcmtest.c
+++ b/sound/drivers/pcmtest.c
@@ -754,13 +754,22 @@ static int __init mod_init(void)
err = init_debug_files(buf_allocated);
if (err)
- return err;
+ goto err_free_patterns;
err = platform_device_register(&pcmtst_pdev);
if (err)
- return err;
+ goto err_clear_debug;
err = platform_driver_register(&pcmtst_pdrv);
- if (err)
+ if (err) {
platform_device_unregister(&pcmtst_pdev);
+ goto err_clear_debug;
+ }
+
+ return 0;
+
+err_clear_debug:
+ clear_debug_files();
+err_free_patterns:
+ free_pattern_buffers();
return err;
}
diff --git a/sound/drivers/vx/vx_cmd.h b/sound/drivers/vx/vx_cmd.h
index c2a520274493..1fc70c98f041 100644
--- a/sound/drivers/vx/vx_cmd.h
+++ b/sound/drivers/vx/vx_cmd.h
@@ -199,7 +199,7 @@ struct vx_cmd_info {
void vx_init_rmh(struct vx_rmh *rmh, unsigned int cmd);
/**
- * vx_send_pipe_cmd_params - fill first command word for pipe commands
+ * vx_set_pipe_cmd_params - fill first command word for pipe commands
* @rmh: the rmh to be modified
* @is_capture: 0 = playback, 1 = capture operation
* @param1: first pipe-parameter
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index b33f425763f9..d720565db4aa 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -4111,6 +4111,7 @@ enum {
ALC245_FIXUP_ACER_MICMUTE_LED,
ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED,
ALC236_FIXUP_HP_DMIC,
+ ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -6653,6 +6654,16 @@ static const struct hda_fixup alc269_fixups[] = {
{ 0x12, 0x90a60160 }, /* use as internal mic */
{ }
},
+ },
+ [ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x90170111 },
+ { 0x19, 0x03a1113c },
+ { 0x1a, 0x22a190a0 },
+ { 0x1b, 0x90170110 },
+ { }
+ }
}
};
@@ -6706,6 +6717,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED),
@@ -7142,6 +7154,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dcd, "HP Victus 15-fa2xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
@@ -7214,6 +7227,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f2d, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f2e, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8f3c, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8f3d, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f41, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
@@ -7751,6 +7766,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK),
SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1ee7, 0x2081, "HONOR MRB-XXX M1020", ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO),
SND_PCI_QUIRK(0x1f4c, 0xe001, "Minisforum V3 (SE)", ALC245_FIXUP_BASS_HP_DAC),
SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -7971,6 +7987,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"},
{.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
{.id = ALC245_FIXUP_BASS_HP_DAC, .name = "alc245-fixup-bass-hp-dac"},
+ {.id = ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, .name = "alc256-honor-mrb-xxx-m1020-audio"},
{}
};
#define ALC225_STANDARD_PINS \
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
index f860e0eb7602..560f2385212d 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -788,6 +788,7 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
}
if (strstr(dev_name(&spi->dev), "TXNW2781")) {
device_name = "TXNW2781";
+ tas_hda->priv->chip_id = TAS2781;
} else {
dev_err(tas_priv->dev, "Unmatched spi dev %s\n",
dev_name(&spi->dev));
diff --git a/sound/hda/common/hda_controller.h b/sound/hda/common/hda_controller.h
index c2d0109866e6..7434f38038a0 100644
--- a/sound/hda/common/hda_controller.h
+++ b/sound/hda/common/hda_controller.h
@@ -127,10 +127,6 @@ struct azx {
unsigned int beep_mode;
bool ctl_dev_id;
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
- const struct firmware *fw;
-#endif
-
/* flags */
int bdl_pos_adj;
unsigned int running:1;
diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
index 257c498c3260..c87d75dbd8aa 100644
--- a/sound/hda/controllers/intel.c
+++ b/sound/hda/controllers/intel.c
@@ -1385,9 +1385,6 @@ static void azx_free(struct azx *chip)
azx_free_streams(chip);
snd_hdac_bus_exit(bus);
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
- release_firmware(chip->fw);
-#endif
display_power(chip, false);
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
@@ -2037,24 +2034,6 @@ static int azx_first_init(struct azx *chip)
return 0;
}
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
-/* callback from request_firmware_nowait() */
-static void azx_firmware_cb(const struct firmware *fw, void *context)
-{
- struct snd_card *card = context;
- struct azx *chip = card->private_data;
-
- if (fw)
- chip->fw = fw;
- else
- dev_err(card->dev, "Cannot load firmware, continue without patching\n");
- if (!chip->disabled) {
- /* continue probing */
- azx_probe_continue(chip);
- }
-}
-#endif
-
static int disable_msi_reset_irq(struct azx *chip)
{
struct hdac_bus *bus = azx_bus(chip);
@@ -2131,7 +2110,6 @@ static int azx_probe(struct pci_dev *pci,
struct snd_card *card;
struct hda_intel *hda;
struct azx *chip;
- bool schedule_probe;
int dev;
int err;
@@ -2227,22 +2205,7 @@ static int azx_probe(struct pci_dev *pci,
chip->disabled = true;
}
- schedule_probe = !chip->disabled;
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (patch[dev] && *patch[dev]) {
- dev_info(card->dev, "Applying patch firmware '%s'\n",
- patch[dev]);
- err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
- &pci->dev, GFP_KERNEL, card,
- azx_firmware_cb);
- if (err < 0)
- goto out_free;
- schedule_probe = false; /* continued in azx_firmware_cb() */
- }
-#endif /* CONFIG_SND_HDA_PATCH_LOADER */
-
- if (schedule_probe)
+ if (!chip->disabled)
schedule_delayed_work(&hda->probe_work, 0);
set_bit(dev, probed_devs);
@@ -2371,11 +2334,20 @@ static int azx_probe_continue(struct azx *chip)
}
#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (chip->fw) {
- err = snd_hda_load_patch(&chip->bus, chip->fw->size,
- chip->fw->data);
- if (err < 0)
- goto out_free;
+ if (patch[dev] && *patch[dev]) {
+ const struct firmware *fw = NULL;
+
+ dev_info(&pci->dev, "Applying patch firmware '%s'\n",
+ patch[dev]);
+ if (request_firmware(&fw, patch[dev], &pci->dev) < 0) {
+ dev_err(&pci->dev,
+ "Cannot load firmware, continue without patching\n");
+ } else {
+ err = snd_hda_load_patch(&chip->bus, fw->size, fw->data);
+ release_firmware(fw);
+ if (err < 0)
+ goto out_free;
+ }
}
#endif
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 33034e07b3d6..636f309c9424 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -421,30 +421,26 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
int result = 0;
-
- /* FIXME race condition in here!!!
- chip->mode non-atomic update gets consistently protected
- by reg_lock always, _except_ for this place!!
- Probably need to take reg_lock as outer (or inner??) lock, too.
- (or serialize both lock operations? probably not, though... - racy?)
- */
- guard(spinlock)(&chip->mixer_lock);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- chip->mode |= SB_RATE_LOCK_CAPTURE;
- snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
- capture_cmd(chip));
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- chip->mode &= ~SB_RATE_LOCK_CAPTURE;
- snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
- capture_cmd(chip));
- break;
- default:
- result = -EINVAL;
- break;
+
+ guard(spinlock)(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->mixer_lock) {
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ chip->mode |= SB_RATE_LOCK_CAPTURE;
+ snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
+ capture_cmd(chip));
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ chip->mode &= ~SB_RATE_LOCK_CAPTURE;
+ snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
+ capture_cmd(chip));
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
}
return result;
}
diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c
index 0b07a53cc792..564af5c04dbb 100644
--- a/sound/soc/codecs/es8311.c
+++ b/sound/soc/codecs/es8311.c
@@ -761,6 +761,7 @@ static int es8311_set_bias_level(struct snd_soc_component *component,
{
struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -769,17 +770,21 @@ static int es8311_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
- int ret = clk_prepare_enable(es8311->mclk);
+ ret = clk_prepare_enable(es8311->mclk);
if (ret) {
dev_err(component->dev,
"unable to prepare mclk\n");
return ret;
}
- snd_soc_component_update_bits(
- component, ES8311_SYS3,
- ES8311_SYS3_PDN_VMIDSEL_MASK,
- ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED);
+ ret = snd_soc_component_update_bits(
+ component, ES8311_SYS3,
+ ES8311_SYS3_PDN_VMIDSEL_MASK,
+ ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED);
+ if (ret < 0) {
+ clk_disable_unprepare(es8311->mclk);
+ return ret;
+ }
}
break;
@@ -862,13 +867,18 @@ static int es8311_suspend(struct snd_soc_component *component)
static int es8311_resume(struct snd_soc_component *component)
{
struct es8311_priv *es8311;
+ int ret;
es8311 = snd_soc_component_get_drvdata(component);
es8311_reset(component, false);
regcache_cache_only(es8311->regmap, false);
- regcache_sync(es8311->regmap);
+ ret = regcache_sync(es8311->regmap);
+ if (ret) {
+ dev_err(component->dev, "unable to sync regcache\n");
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index b0aeeab26bd9..192faa431b5e 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -1498,6 +1498,7 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
}
if (!retry && !(value & 0x40)) {
dev_err(dev, "%s: RAE is not ready to load\n", __func__);
+ release_firmware(rae_fw);
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index a1d86bd309f4..885e0b6fed00 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -2487,7 +2487,7 @@ static int tas2781_cali_preproc(struct tasdevice_priv *priv, int i)
if (spec == NULL)
return -ENOMEM;
priv->tasdevice[i].cali_specific = spec;
- rc = tasdevice_dev_bulk_read(priv, i, p->r0_reg, r0_deflt, 4);
+ rc = priv->dev_bulk_read(priv, i, p->r0_reg, r0_deflt, 4);
if (rc < 0) {
dev_err(priv->dev, "invalid RE from %d = %d\n", i, rc);
return rc;
@@ -2511,9 +2511,8 @@ static int tas2781_cali_preproc(struct tasdevice_priv *priv, int i)
TASDEVICE_REG(0, 0x1b, 0x34) :
TASDEVICE_REG(0, 0x18, 0x1c);
- rc = tasdevice_dev_bulk_read(priv, i,
- spec->sin_gni_reg,
- spec->sin_gni, 4);
+ rc = priv->dev_bulk_read(priv, i, spec->sin_gni_reg,
+ spec->sin_gni, 4);
if (rc < 0) {
dev_err(priv->dev, "wrong sinegaini %d = %d\n",
i, rc);
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index c593f9da0c5b..a78a8f9b9833 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -119,10 +119,10 @@ static const struct i2c_device_id tasdevice_id[] = {
{ "tas5827", TAS5827 },
{ "tas5828", TAS5828 },
{ "tas5830", TAS5830 },
+ { "tas5832", TAS5832 },
{}
};
-#ifdef CONFIG_OF
static const struct of_device_id tasdevice_of_match[] = {
{ .compatible = "ti,tas2020", .data = &tasdevice_id[TAS2020] },
{ .compatible = "ti,tas2118", .data = &tasdevice_id[TAS2118] },
@@ -143,10 +143,10 @@ static const struct of_device_id tasdevice_of_match[] = {
{ .compatible = "ti,tas5827", .data = &tasdevice_id[TAS5827] },
{ .compatible = "ti,tas5828", .data = &tasdevice_id[TAS5828] },
{ .compatible = "ti,tas5830", .data = &tasdevice_id[TAS5830] },
+ { .compatible = "ti,tas5832", .data = &tasdevice_id[TAS5832] },
{},
};
MODULE_DEVICE_TABLE(of, tasdevice_of_match);
-#endif
/**
* tas2781_digital_getvol - get the volum control
@@ -1746,6 +1746,7 @@ out:
case TAS5827:
case TAS5828:
case TAS5830:
+ case TAS5832:
/* If DSP FW fail, DSP kcontrol won't be created. */
tasdevice_dsp_remove(tas_priv);
}
@@ -1917,6 +1918,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec)
case TAS5827:
case TAS5828:
case TAS5830:
+ case TAS5832:
p = (struct snd_kcontrol_new *)tas5825_snd_controls;
size = ARRAY_SIZE(tas5825_snd_controls);
break;
@@ -2083,7 +2085,6 @@ static void tasdevice_i2c_remove(struct i2c_client *client)
tasdevice_remove(tas_priv);
}
-#ifdef CONFIG_ACPI
static const struct acpi_device_id tasdevice_acpi_match[] = {
{ "TXNW2020", (kernel_ulong_t)&tasdevice_id[TAS2020] },
{ "TXNW2118", (kernel_ulong_t)&tasdevice_id[TAS2118] },
@@ -2104,19 +2105,17 @@ static const struct acpi_device_id tasdevice_acpi_match[] = {
{ "TXNW5827", (kernel_ulong_t)&tasdevice_id[TAS5827] },
{ "TXNW5828", (kernel_ulong_t)&tasdevice_id[TAS5828] },
{ "TXNW5830", (kernel_ulong_t)&tasdevice_id[TAS5830] },
+ { "TXNW5832", (kernel_ulong_t)&tasdevice_id[TAS5832] },
{},
};
MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
-#endif
static struct i2c_driver tasdevice_i2c_driver = {
.driver = {
.name = "tasdev-codec",
- .of_match_table = of_match_ptr(tasdevice_of_match),
-#ifdef CONFIG_ACPI
- .acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
-#endif
+ .of_match_table = tasdevice_of_match,
+ .acpi_match_table = tasdevice_acpi_match,
},
.probe = tasdevice_i2c_probe,
.remove = tasdevice_i2c_remove,
diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c
index a3f4785c4bbe..c81df41ace88 100644
--- a/sound/soc/qcom/x1e80100.c
+++ b/sound/soc/qcom/x1e80100.c
@@ -27,10 +27,29 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
struct snd_soc_jack *dp_jack = NULL;
int dp_pcm_id = 0;
switch (cpu_dai->id) {
+ case WSA_CODEC_DMA_RX_0:
+ case WSA_CODEC_DMA_RX_1:
+ /*
+ * Set limit of -3 dB on Digital Volume and 0 dB on PA Volume
+ * to reduce the risk of speaker damage until we have active
+ * speaker protection in place.
+ */
+ snd_soc_limit_volume(card, "WSA WSA_RX0 Digital Volume", 81);
+ snd_soc_limit_volume(card, "WSA WSA_RX1 Digital Volume", 81);
+ snd_soc_limit_volume(card, "WSA2 WSA_RX0 Digital Volume", 81);
+ snd_soc_limit_volume(card, "WSA2 WSA_RX1 Digital Volume", 81);
+ snd_soc_limit_volume(card, "SpkrLeft PA Volume", 6);
+ snd_soc_limit_volume(card, "SpkrRight PA Volume", 6);
+ snd_soc_limit_volume(card, "WooferLeft PA Volume", 6);
+ snd_soc_limit_volume(card, "TweeterLeft PA Volume", 6);
+ snd_soc_limit_volume(card, "WooferRight PA Volume", 6);
+ snd_soc_limit_volume(card, "TweeterRight PA Volume", 6);
+ break;
case DISPLAY_PORT_RX_0:
dp_pcm_id = 0;
dp_jack = &data->dp_jack[dp_pcm_id];
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index fd6a254c9530..196bade11ab5 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -1006,8 +1006,11 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
control->has_fixed = true;
fallthrough;
case SDCA_ACCESS_MODE_RO:
- control->deferrable = fwnode_property_read_bool(control_node,
- "mipi-sdca-control-deferrable");
+ ret = fwnode_property_read_u32(control_node,
+ "mipi-sdca-control-deferrable",
+ &tmp);
+ if (ret == 0)
+ control->deferrable = !!tmp;
break;
default:
break;
diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
index 2a7109d53cbe..e0e32a279787 100644
--- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
+++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
@@ -40,12 +40,6 @@ static int asoc_sdw_bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s spk:cs35l56-bridge",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
ret = snd_soc_dapm_new_controls(dapm, bridge_widgets,
ARRAY_SIZE(bridge_widgets));
if (ret) {
diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
index 4a451b9d4f13..e99ea3c4e5dd 100644
--- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c
+++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
@@ -107,21 +107,11 @@ EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, "SND_SOC_SDW_UTILS");
int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
- struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = dai->component;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
- struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret;
- if (!(ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)) {
- /* Will be set by the bridge code in this case */
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s spk:cs42l43-spk",
- card->components);
- if (!card->components)
- return -ENOMEM;
- }
-
ret = snd_soc_limit_volume(card, "cs42l43 Speaker Digital Volume",
CS42L43_SPK_VOLUME_0DB);
if (ret)
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index 2807f536eef0..1637cc3f3d59 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -758,6 +758,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
{
.direction = {true, false},
.codec_name = "cs42l43-codec",
+ .component_name = "cs42l43-spk",
.dai_name = "cs42l43-dp6",
.dai_type = SOC_SDW_DAI_TYPE_AMP,
.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
@@ -1104,6 +1105,7 @@ static int asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info *
int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct asoc_sdw_codec_info *codec_info;
struct snd_soc_dai *dai;
@@ -1179,16 +1181,26 @@ skip_add_controls_widgets:
/* Generate the spk component string for card->components string */
if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP &&
codec_info->dais[dai_index].component_name) {
+ const char *component;
+
+ /*
+ * For the special case of cs42l43 with sidecar amps, use only
+ * "cs35l56-bridge" as the component name in card->components
+ */
+ if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS &&
+ !strcmp(codec_info->dais[dai_index].component_name, "cs42l43-spk"))
+ component = "cs35l56-bridge";
+ else
+ component = codec_info->dais[dai_index].component_name;
+
if (strlen (spk_components) == 0)
spk_components =
- devm_kasprintf(card->dev, GFP_KERNEL, "%s",
- codec_info->dais[dai_index].component_name);
+ devm_kasprintf(card->dev, GFP_KERNEL, "%s", component);
else
/* Append component name to spk_components */
spk_components =
devm_kasprintf(card->dev, GFP_KERNEL,
- "%s+%s", spk_components,
- codec_info->dais[dai_index].component_name);
+ "%s+%s", spk_components, component);
}
codec_info->dais[dai_index].rtd_init_done = true;
diff --git a/sound/soc/sof/intel/nvl.c b/sound/soc/sof/intel/nvl.c
index 0d763998558f..86d2e1aa0eec 100644
--- a/sound/soc/sof/intel/nvl.c
+++ b/sound/soc/sof/intel/nvl.c
@@ -48,6 +48,7 @@ const struct sof_intel_dsp_desc nvl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_4_0,
+ .platform = "nvl",
};
const struct sof_intel_dsp_desc nvl_s_chip_info = {
@@ -72,6 +73,7 @@ const struct sof_intel_dsp_desc nvl_s_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_4_0,
+ .platform = "nvl",
};
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
index 874f6cd503ca..2c5648966412 100644
--- a/sound/usb/6fire/chip.c
+++ b/sound/usb/6fire/chip.c
@@ -31,7 +31,6 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable card */
static struct sfire_chip *chips[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-static struct usb_device *devices[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the 6fire sound device");
@@ -44,32 +43,28 @@ static DEFINE_MUTEX(register_mutex);
static void usb6fire_chip_abort(struct sfire_chip *chip)
{
- if (chip) {
- if (chip->pcm)
- usb6fire_pcm_abort(chip);
- if (chip->midi)
- usb6fire_midi_abort(chip);
- if (chip->comm)
- usb6fire_comm_abort(chip);
- if (chip->control)
- usb6fire_control_abort(chip);
- }
+ if (chip->pcm)
+ usb6fire_pcm_abort(chip);
+ if (chip->midi)
+ usb6fire_midi_abort(chip);
+ if (chip->comm)
+ usb6fire_comm_abort(chip);
+ if (chip->control)
+ usb6fire_control_abort(chip);
}
static void usb6fire_card_free(struct snd_card *card)
{
struct sfire_chip *chip = card->private_data;
- if (chip) {
- if (chip->pcm)
- usb6fire_pcm_destroy(chip);
- if (chip->midi)
- usb6fire_midi_destroy(chip);
- if (chip->comm)
- usb6fire_comm_destroy(chip);
- if (chip->control)
- usb6fire_control_destroy(chip);
- }
+ if (chip->pcm)
+ usb6fire_pcm_destroy(chip);
+ if (chip->midi)
+ usb6fire_midi_destroy(chip);
+ if (chip->comm)
+ usb6fire_comm_destroy(chip);
+ if (chip->control)
+ usb6fire_control_destroy(chip);
}
static int usb6fire_chip_probe(struct usb_interface *intf,
@@ -83,21 +78,18 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
struct snd_card *card = NULL;
/* look if we already serve this card and return if so */
- scoped_guard(mutex, &register_mutex) {
- for (i = 0; i < SNDRV_CARDS; i++) {
- if (devices[i] == device) {
- if (chips[i])
- chips[i]->intf_count++;
- usb_set_intfdata(intf, chips[i]);
- return 0;
- } else if (!devices[i] && regidx < 0)
- regidx = i;
- }
- if (regidx < 0) {
- dev_err(&intf->dev, "too many cards registered.\n");
- return -ENODEV;
- }
- devices[regidx] = device;
+ guard(mutex)(&register_mutex);
+ for (i = 0; i < SNDRV_CARDS; i++) {
+ if (chips[i] && chips[i]->dev == device) {
+ chips[i]->intf_count++;
+ usb_set_intfdata(intf, chips[i]);
+ return 0;
+ } else if (!chips[i] && regidx < 0)
+ regidx = i;
+ }
+ if (regidx < 0) {
+ dev_err(&intf->dev, "too many cards registered.\n");
+ return -ENODEV;
}
/* check, if firmware is present on device, upload it if not */
@@ -124,7 +116,6 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
device->bus->busnum, device->devnum);
chip = card->private_data;
- chips[regidx] = chip;
chip->dev = device;
chip->regidx = regidx;
chip->intf_count = 1;
@@ -152,7 +143,10 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
dev_err(&intf->dev, "cannot register card.");
goto destroy_chip;
}
+
usb_set_intfdata(intf, chip);
+ chips[regidx] = chip;
+
return 0;
destroy_chip:
@@ -165,30 +159,31 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf)
struct sfire_chip *chip;
struct snd_card *card;
+ guard(mutex)(&register_mutex);
chip = usb_get_intfdata(intf);
- if (chip) { /* if !chip, fw upload has been performed */
- chip->intf_count--;
- if (!chip->intf_count) {
- scoped_guard(mutex, &register_mutex) {
- devices[chip->regidx] = NULL;
- chips[chip->regidx] = NULL;
- }
-
- /*
- * Save card pointer before teardown.
- * snd_card_free_when_closed() may free card (and
- * the embedded chip) immediately, so it must be
- * called last and chip must not be accessed after.
- */
- card = chip->card;
- chip->shutdown = true;
- if (card)
- snd_card_disconnect(card);
- usb6fire_chip_abort(chip);
- if (card)
- snd_card_free_when_closed(card);
- }
- }
+ /* if !chip, fw upload has been performed */
+ if (!chip)
+ return;
+
+ chip->intf_count--;
+ if (chip->intf_count)
+ return;
+
+ chips[chip->regidx] = NULL;
+
+ /*
+ * Save card pointer before teardown.
+ * snd_card_free_when_closed() may free card (and
+ * the embedded chip) immediately, so it must be
+ * called last and chip must not be accessed after.
+ */
+ card = chip->card;
+ chip->shutdown = true;
+ if (card)
+ snd_card_disconnect(card);
+ usb6fire_chip_abort(chip);
+ if (card)
+ snd_card_free_when_closed(card);
}
static const struct usb_device_id device_table[] = {
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index dd25a6407b63..c77a21a9acd7 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -290,15 +290,17 @@ static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ int vol0 = ucontrol->value.integer.value[0] - 15;
+ int vol1 = ucontrol->value.integer.value[1] - 15;
int changed = 0;
- if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
- rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
+ if (rt->input_vol[0] != vol0) {
+ rt->input_vol[0] = vol0;
rt->ivol_updated &= ~(1 << 0);
changed = 1;
}
- if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
- rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
+ if (rt->input_vol[1] != vol1) {
+ rt->input_vol[1] = vol1;
rt->ivol_updated &= ~(1 << 1);
changed = 1;
}
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index af459c49baf4..4598fb7e8be0 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -87,6 +87,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
int v = ucontrol->value.integer.value[0];
+ int ret;
unsigned char cmd;
switch (cdev->chip.usb_id) {
@@ -103,6 +104,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
if (pos & CNT_INTVAL) {
int i = pos & ~CNT_INTVAL;
+ unsigned char old = cdev->control_state[i];
+
+ if (old == v)
+ return 0;
cdev->control_state[i] = v;
@@ -113,10 +118,11 @@ static int control_put(struct snd_kcontrol *kcontrol,
cdev->ep8_out_buf[0] = i;
cdev->ep8_out_buf[1] = v;
- usb_bulk_msg(cdev->chip.dev,
- usb_sndbulkpipe(cdev->chip.dev, 8),
- cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),
- &actual_len, 200);
+ ret = usb_bulk_msg(cdev->chip.dev,
+ usb_sndbulkpipe(cdev->chip.dev, 8),
+ cdev->ep8_out_buf,
+ sizeof(cdev->ep8_out_buf),
+ &actual_len, 200);
} else if (cdev->chip.usb_id ==
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) {
@@ -128,21 +134,36 @@ static int control_put(struct snd_kcontrol *kcontrol,
offset = MASCHINE_BANK_SIZE;
}
- snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
- cdev->control_state + offset,
- MASCHINE_BANK_SIZE);
+ ret = snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
+ cdev->control_state + offset,
+ MASCHINE_BANK_SIZE);
} else {
- snd_usb_caiaq_send_command(cdev, cmd,
- cdev->control_state, sizeof(cdev->control_state));
+ ret = snd_usb_caiaq_send_command(cdev, cmd,
+ cdev->control_state,
+ sizeof(cdev->control_state));
+ }
+
+ if (ret < 0) {
+ cdev->control_state[i] = old;
+ return ret;
}
} else {
- if (v)
- cdev->control_state[pos / 8] |= 1 << (pos % 8);
- else
- cdev->control_state[pos / 8] &= ~(1 << (pos % 8));
+ int idx = pos / 8;
+ unsigned char mask = 1 << (pos % 8);
+ unsigned char old = cdev->control_state[idx];
+ unsigned char val = v ? (old | mask) : (old & ~mask);
- snd_usb_caiaq_send_command(cdev, cmd,
- cdev->control_state, sizeof(cdev->control_state));
+ if (old == val)
+ return 0;
+
+ cdev->control_state[idx] = val;
+ ret = snd_usb_caiaq_send_command(cdev, cmd,
+ cdev->control_state,
+ sizeof(cdev->control_state));
+ if (ret < 0) {
+ cdev->control_state[idx] = old;
+ return ret;
+ }
}
return 1;
@@ -640,4 +661,3 @@ int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)
return ret;
}
-
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 51177ebfb8c6..8af0c04041ee 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -290,7 +290,7 @@ int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *cdev,
tmp, sizeof(tmp));
}
-static void setup_card(struct snd_usb_caiaqdev *cdev)
+static int setup_card(struct snd_usb_caiaqdev *cdev)
{
int ret;
char val[4];
@@ -325,8 +325,10 @@ static void setup_card(struct snd_usb_caiaqdev *cdev)
snd_usb_caiaq_send_command(cdev, EP1_CMD_READ_IO, NULL, 0);
if (!wait_event_timeout(cdev->ep1_wait_queue,
- cdev->control_state[0] != 0xff, HZ))
- return;
+ cdev->control_state[0] != 0xff, HZ)) {
+ dev_err(dev, "Read timeout for control state\n");
+ return -EINVAL;
+ }
/* fix up some defaults */
if ((cdev->control_state[1] != 2) ||
@@ -347,33 +349,43 @@ static void setup_card(struct snd_usb_caiaqdev *cdev)
cdev->spec.num_digital_audio_out +
cdev->spec.num_digital_audio_in > 0) {
ret = snd_usb_caiaq_audio_init(cdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Unable to set up audio system (ret=%d)\n", ret);
+ return ret;
+ }
}
if (cdev->spec.num_midi_in +
cdev->spec.num_midi_out > 0) {
ret = snd_usb_caiaq_midi_init(cdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Unable to set up MIDI system (ret=%d)\n", ret);
+ return ret;
+ }
}
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
ret = snd_usb_caiaq_input_init(cdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);
+ return ret;
+ }
#endif
/* finally, register the card and all its sub-instances */
ret = snd_card_register(cdev->chip.card);
if (ret < 0) {
dev_err(dev, "snd_card_register() returned %d\n", ret);
- snd_card_free(cdev->chip.card);
+ return ret;
}
ret = snd_usb_caiaq_control_init(cdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Unable to set up control system (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
}
static void card_free(struct snd_card *card)
@@ -499,8 +511,11 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
cdev->vendor_name, cdev->product_name, usbpath);
- setup_card(cdev);
card->private_free = card_free;
+ err = setup_card(cdev);
+ if (err < 0)
+ return err;
+
return 0;
err_kill_urb:
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 030b4307927a..4830f9f93ad7 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -470,7 +470,7 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
nr_rates++;
if (nr_rates >= MAX_NR_RATES) {
usb_audio_err(chip, "invalid uac2 rates\n");
- break;
+ return nr_rates;
}
skip_rate:
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
index ea1324c22f46..841b64479252 100644
--- a/sound/usb/line6/podhd.c
+++ b/sound/usb/line6/podhd.c
@@ -28,6 +28,7 @@ enum {
LINE6_PODHD500X,
LINE6_PODHDDESKTOP,
LINE6_PODHDPROX,
+ LINE6_PODHDPRO,
};
struct usb_line6_podhd {
@@ -442,6 +443,7 @@ static const struct usb_device_id podhd_id_table[] = {
{ LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
{ LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
{ LINE6_IF_NUM(0x415A, 0), .driver_info = LINE6_PODHDPROX },
+ { LINE6_IF_NUM(0x4157, 0), .driver_info = LINE6_PODHDPRO },
{}
};
@@ -542,6 +544,18 @@ static const struct line6_properties podhd_properties_table[] = {
.ep_audio_r = 0x86,
.ep_audio_w = 0x02,
},
+ [LINE6_PODHDPRO] = {
+ .id = "PODHDPRO",
+ .name = "POD HD PRO",
+ .capabilities = LINE6_CAP_PCM | LINE6_CAP_CONTROL
+ | LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL | LINE6_CAP_IN_NEEDS_OUT,
+ .altsetting = 1,
+ .ctrl_if = 1,
+ .ep_ctrl_r = 0x81,
+ .ep_ctrl_w = 0x01,
+ .ep_audio_r = 0x86,
+ .ep_audio_w = 0x02,
+ },
};
/*
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index aa6ea3be100a..85653112e7f3 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -2664,6 +2664,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
/* get min/max values */
switch (type) {
+ case USB_XU_CLOCK_RATE:
+ /*
+ * E-Mu USB 0404/0202/TrackerPre/0204
+ * samplerate control quirk
+ */
+ cval->min = 0;
+ cval->max = 5;
+ cval->res = 1;
+ cval->initialized = 1;
+ break;
case UAC_PROCESS_UP_DOWNMIX: {
bool mode_sel = false;
@@ -2687,31 +2697,17 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
cval->max = control_spec[0];
cval->res = 1;
cval->initialized = 1;
- err = 0;
break;
}
- err = get_min_max(cval, valinfo->min_value);
- break;
+ fallthrough;
}
- case USB_XU_CLOCK_RATE:
- /*
- * E-Mu USB 0404/0202/TrackerPre/0204
- * samplerate control quirk
- */
- cval->min = 0;
- cval->max = 5;
- cval->res = 1;
- cval->initialized = 1;
- err = 0;
- break;
default:
err = get_min_max(cval, valinfo->min_value);
- break;
- }
- if (err < 0 && err != -EAGAIN) {
- usb_mixer_elem_info_free(cval);
- return err;
+ if (err < 0 && err != -EAGAIN) {
+ usb_mixer_elem_info_free(cval);
+ return err;
+ }
}
err = get_cur_ctl_value(cval, cval->control << 8, &val);
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index a01510a855c2..1bdaa46d4fe1 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1538,15 +1538,17 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
{
struct usb_mixer_interface *mixer;
struct usb_mixer_elem_info *cval;
+ int err;
int unitid = 12; /* SampleRate ExtensionUnit ID */
list_for_each_entry(mixer, &chip->mixer_list, list) {
if (mixer->id_elems[unitid]) {
cval = mixer_elem_list_to_info(mixer->id_elems[unitid]);
- snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
- cval->control << 8,
- samplerate_id);
- snd_usb_mixer_notify_id(mixer, unitid);
+ err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
+ cval->control << 8,
+ samplerate_id);
+ if (!err)
+ snd_usb_mixer_notify_id(mixer, unitid);
break;
}
}
@@ -2025,7 +2027,7 @@ static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
int err;
reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
- if (reg != list->kctl->private_value)
+ if (reg == list->kctl->private_value)
return 0;
kcontrol->private_value = reg;
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 8fc36d1cfb9d..7b803ad58487 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2474,6 +2474,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */
QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
+ DEVICE_FLG(0x3443, 0x930d, /* NexiGo N930W 60fps Webcam */
+ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */
diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
index 5dd1b43b9493..368dafa5df3f 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -37,7 +37,6 @@ struct virtio_pcm_msg;
* the device side at resume.
* @msgs: Allocated I/O messages.
* @nmsgs: Number of allocated I/O messages.
- * @msg_last_enqueued: Index of the last I/O message added to the virtqueue.
* @msg_count: Number of pending I/O messages in the virtqueue.
* @msg_empty: Notify when msg_count is zero.
*/