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 @@ static void tasdevice_fw_ready(const struct firmware *fmw, 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 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) /* 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, ®ister_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)(®ister_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)(®ister_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, ®ister_mutex) { - devices[chip->regidx] = NULL; - chips[chip->regidx] = NULL; - } + /* if !chip, fw upload has been performed */ + if (!chip) + return; - /* - * 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); - } - } + 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. */