diff options
Diffstat (limited to 'sound')
51 files changed, 874 insertions, 185 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 48db44fa56fe..4e7bc370ffd7 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -155,7 +155,7 @@ config SND_MAX_CARDS config SND_SUPPORT_OLD_API bool "Support old ALSA API" - default y + default n help Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3 or older). diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c index 981c19430cb0..89dc436a0652 100644 --- a/sound/firewire/motu/motu-hwdep.c +++ b/sound/firewire/motu/motu-hwdep.c @@ -75,7 +75,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, while (consumed < count && snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) { ptr = (u32 __user *)(buf + consumed); - if (put_user(ev, ptr)) + if (consumed + sizeof(ev) > count || put_user(ev, ptr)) return -EFAULT; consumed += sizeof(ev); } @@ -83,10 +83,11 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE; event.motu_register_dsp_change.count = (consumed - sizeof(event.motu_register_dsp_change)) / 4; - if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change))) + if (copy_to_user(buf, &event, + min_t(long, count, sizeof(event.motu_register_dsp_change)))) return -EFAULT; - count = consumed; + count = min_t(long, count, consumed); } else { spin_unlock_irq(&motu->lock); diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index d90a6c01f63b..1de46c06f8c2 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -1656,6 +1656,18 @@ static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec, alc236_fixup_hp_micmute_led_vref(codec, fix, action); } +static void alc236_fixup_hp_mute_led_micmute_gpio(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->micmute_led_polarity = 1; + + alc236_fixup_hp_mute_led_coefbit2(codec, fix, action); + alc_fixup_hp_gpio_led(codec, action, 0x00, 0x01); +} + static inline void alc298_samsung_write_coef_pack(struct hda_codec *codec, const unsigned short coefs[2]) { @@ -3753,6 +3765,7 @@ enum { ALC295_FIXUP_DELL_TAS2781_I2C, ALC245_FIXUP_TAS2781_SPI_2, ALC287_FIXUP_TXNW2781_I2C, + ALC287_FIXUP_TXNW2781_I2C_ASUS, ALC287_FIXUP_YOGA7_14ARB7_I2C, ALC245_FIXUP_HP_MUTE_LED_COEFBIT, ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT, @@ -5326,9 +5339,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO] = { .type = HDA_FIXUP_FUNC, - .v.func = alc236_fixup_hp_mute_led_coefbit2, - .chained = true, - .chain_id = ALC236_FIXUP_HP_GPIO_LED, + .v.func = alc236_fixup_hp_mute_led_micmute_gpio, }, [ALC236_FIXUP_LENOVO_INV_DMIC] = { .type = HDA_FIXUP_FUNC, @@ -6053,6 +6064,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK, }, + [ALC287_FIXUP_TXNW2781_I2C_ASUS] = { + .type = HDA_FIXUP_FUNC, + .v.func = tas2781_fixup_txnw_i2c, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_SPK, + }, [ALC287_FIXUP_YOGA7_14ARB7_I2C] = { .type = HDA_FIXUP_FUNC, .v.func = yoga7_14arb7_fixup_i2c, @@ -6770,8 +6787,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e8a, "HP NexusX", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8e9c, "HP 16 Clipper OmniBook X X360", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e9e, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8eb6, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), - SND_PCI_QUIRK(0x103c, 0x8eb7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), SND_PCI_QUIRK(0x103c, 0x8eb8, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), SND_PCI_QUIRK(0x103c, 0x8ec1, "HP 200 G2i", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), SND_PCI_QUIRK(0x103c, 0x8ec4, "HP Bantie I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), @@ -6787,11 +6807,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8eda, "HP ZBook Firefly 16W", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8ee4, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), SND_PCI_QUIRK(0x103c, 0x8ee5, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), + SND_PCI_QUIRK(0x103c, 0x8ee7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), SND_PCI_QUIRK(0x103c, 0x8f0c, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED), 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), + SND_PCI_QUIRK(0x103c, 0x8f57, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), @@ -6824,8 +6846,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1384, "ASUS RC73XA", ALC287_FIXUP_TXNW2781_I2C), - SND_PCI_QUIRK(0x1043, 0x1394, "ASUS RC73YA", ALC287_FIXUP_TXNW2781_I2C), + SND_PCI_QUIRK(0x1043, 0x1384, "ASUS RC73XA", ALC287_FIXUP_TXNW2781_I2C_ASUS), + SND_PCI_QUIRK(0x1043, 0x1394, "ASUS RC73YA", ALC287_FIXUP_TXNW2781_I2C_ASUS), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), @@ -6842,6 +6864,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1584, "ASUS UM3406GA ", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK), SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK), SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC), @@ -7292,6 +7315,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC), 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(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c index c0f2a3ff77a1..21e00055c0c4 100644 --- a/sound/hda/codecs/side-codecs/cs35l41_hda.c +++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c @@ -1901,6 +1901,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i cs35l41->dacpi = adev; physdev = get_device(acpi_get_first_physical_node(adev)); + if (!physdev) + return -ENODEV; sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); if (IS_ERR(sub)) diff --git a/sound/hda/controllers/Kconfig b/sound/hda/controllers/Kconfig index 34721f50b055..72855f2df451 100644 --- a/sound/hda/controllers/Kconfig +++ b/sound/hda/controllers/Kconfig @@ -30,6 +30,20 @@ config SND_HDA_TEGRA To compile this driver as a module, choose M here: the module will be called snd-hda-tegra. +config SND_HDA_CIX_IPBLOQ + tristate "CIX IPBLOQ HD Audio" + depends on ARCH_CIX || COMPILE_TEST + select SND_HDA + select SND_HDA_ALIGNED_MMIO + help + Say Y here to support the HDA controller present in CIX SoCs + + This options enables support for the HD Audio controller + present in some CIX SoCs. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-cix-ipbloq. + config SND_HDA_ACPI tristate "HD Audio ACPI" depends on ACPI diff --git a/sound/hda/controllers/Makefile b/sound/hda/controllers/Makefile index a4bcd055e9ae..8967b6771d90 100644 --- a/sound/hda/controllers/Makefile +++ b/sound/hda/controllers/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 snd-hda-intel-y := intel.o snd-hda-tegra-y := tegra.o +snd-hda-cix-ipbloq-y := cix-ipbloq.o snd-hda-acpi-y := acpi.o subdir-ccflags-y += -I$(src)/../common @@ -10,4 +11,5 @@ CFLAGS_intel.o := -I$(src) obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o +obj-$(CONFIG_SND_HDA_CIX_IPBLOQ) += snd-hda-cix-ipbloq.o obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o diff --git a/sound/hda/controllers/cix-ipbloq.c b/sound/hda/controllers/cix-ipbloq.c new file mode 100644 index 000000000000..c1084a915c13 --- /dev/null +++ b/sound/hda/controllers/cix-ipbloq.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2025 Cix Technology Group Co., Ltd. + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/string.h> + +#include <sound/hda_codec.h> +#include "hda_controller.h" + +#define CIX_IPBLOQ_JACKPOLL_DEFAULT_TIME_MS 1000 +#define CIX_IPBLOQ_POWER_SAVE_DEFAULT_TIME_MS 100 + +#define CIX_IPBLOQ_SKY1_ADDR_HOST_TO_HDAC_OFFSET (-0x90000000ULL) + +struct cix_ipbloq_hda { + struct azx chip; + struct device *dev; + void __iomem *regs; + + struct reset_control *reset; + struct clk_bulk_data clocks[2]; + unsigned int nclocks; +}; + +static const struct hda_controller_ops cix_ipbloq_hda_ops; + +static int cix_ipbloq_hda_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + + return 0; +} + +static int cix_ipbloq_hda_dev_free(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + if (azx_bus(chip)->chip_init) { + azx_stop_all_streams(chip); + azx_stop_chip(chip); + } + + azx_free_stream_pages(chip); + azx_free_streams(chip); + snd_hdac_bus_exit(azx_bus(chip)); + + return 0; +} + +static int cix_ipbloq_hda_probe_codec(struct cix_ipbloq_hda *hda) +{ + struct azx *chip = &hda->chip; + struct hdac_bus *bus = azx_bus(chip); + int err; + + to_hda_bus(bus)->bus_probing = 1; + + /* create codec instances */ + err = azx_probe_codecs(chip, 8); + if (err < 0) { + dev_err(hda->dev, "probe codecs failed: %d\n", err); + return err; + } + + err = azx_codec_configure(chip); + if (err < 0) { + dev_err(hda->dev, "codec configure failed: %d\n", err); + return err; + } + + err = snd_card_register(chip->card); + if (err < 0) { + dev_err(hda->dev, "card register failed: %d\n", err); + return err; + } + + chip->running = 1; + + to_hda_bus(bus)->bus_probing = 0; + + snd_hda_set_power_save(&chip->bus, CIX_IPBLOQ_POWER_SAVE_DEFAULT_TIME_MS); + + return 0; +} + +static int cix_ipbloq_hda_init(struct cix_ipbloq_hda *hda, + struct azx *chip, + struct platform_device *pdev) +{ + const char *sname = NULL, *drv_name = "cix-ipbloq-hda"; + struct hdac_bus *bus = azx_bus(chip); + struct snd_card *card = chip->card; + struct resource *res; + unsigned short gcap; + int irq_id, err; + + hda->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(hda->regs)) { + dev_err(hda->dev, "failed to get and ioremap resource\n"); + return PTR_ERR(hda->regs); + } + bus->remap_addr = hda->regs; + bus->addr = res->start; + + irq_id = platform_get_irq(pdev, 0); + if (irq_id < 0) + return irq_id; + + err = devm_request_irq(hda->dev, irq_id, azx_interrupt, + 0, KBUILD_MODNAME, chip); + if (err < 0) + return dev_err_probe(hda->dev, err, + "unable to request IRQ %d : err = %d\n", irq_id, err); + bus->irq = irq_id; + card->sync_irq = bus->irq; + + gcap = azx_readw(chip, GCAP); + chip->capture_streams = (gcap >> 8) & 0x0f; + chip->playback_streams = (gcap >> 12) & 0x0f; + chip->capture_index_offset = 0; + chip->playback_index_offset = chip->capture_streams; + chip->num_streams = chip->playback_streams + chip->capture_streams; + + /* initialize streams */ + err = azx_init_streams(chip); + if (err < 0) { + dev_err(hda->dev, "failed to initialize streams: %d\n", err); + return err; + } + + err = azx_alloc_stream_pages(chip); + if (err < 0) { + dev_err(hda->dev, "failed to allocate stream pages: %d\n", err); + return err; + } + + /* initialize chip */ + azx_init_chip(chip, 1); + + /* codec detection */ + if (!bus->codec_mask) { + dev_err(hda->dev, "no codecs found\n"); + return -ENODEV; + } + dev_dbg(card->dev, "codec detection mask = 0x%lx\n", bus->codec_mask); + + /* driver name */ + strscpy(card->driver, drv_name, sizeof(card->driver)); + + /* shortname for card */ + sname = of_get_property(pdev->dev.of_node, "model", NULL); + if (!sname) + sname = drv_name; + if (strlen(sname) > sizeof(card->shortname)) + dev_dbg(card->dev, "truncating shortname for card\n"); + strscpy(card->shortname, sname, sizeof(card->shortname)); + + /* longname for card */ + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", + card->shortname, bus->addr, bus->irq); + + return 0; +} + +static int cix_ipbloq_hda_create(struct cix_ipbloq_hda *hda, + struct snd_card *card, + unsigned int driver_caps) +{ + static const struct snd_device_ops ops = { + .dev_disconnect = cix_ipbloq_hda_dev_disconnect, + .dev_free = cix_ipbloq_hda_dev_free, + }; + struct azx *chip; + int err; + + chip = &hda->chip; + chip->card = card; + chip->ops = &cix_ipbloq_hda_ops; + chip->driver_caps = driver_caps; + chip->driver_type = driver_caps & 0xff; + chip->dev_index = 0; + chip->single_cmd = 0; + chip->codec_probe_mask = -1; + chip->align_buffer_size = 1; + chip->jackpoll_interval = msecs_to_jiffies(CIX_IPBLOQ_JACKPOLL_DEFAULT_TIME_MS); + mutex_init(&chip->open_mutex); + INIT_LIST_HEAD(&chip->pcm_list); + + /* + * HD-audio controllers appear pretty inaccurate about the update-IRQ timing. + * The IRQ is issued before actually the data is processed. So use stream + * link position by default instead of dma position buffer. + */ + chip->get_position[0] = chip->get_position[1] = azx_get_pos_lpib; + + err = azx_bus_init(chip, NULL); + if (err < 0) { + dev_err(hda->dev, "failed to init bus, err = %d\n", err); + return err; + } + + /* RIRBSTS.RINTFL cannot be cleared, cause interrupt storm */ + chip->bus.core.polling_mode = 1; + chip->bus.core.not_use_interrupts = 1; + + chip->bus.core.aligned_mmio = 1; + chip->bus.core.dma_stop_delay = 100; + chip->bus.core.addr_offset = (dma_addr_t)CIX_IPBLOQ_SKY1_ADDR_HOST_TO_HDAC_OFFSET; + + chip->bus.jackpoll_in_suspend = 1; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + dev_err(card->dev, "failed to create device, err = %d\n", err); + return err; + } + + return 0; +} + +static int cix_ipbloq_hda_probe(struct platform_device *pdev) +{ + const unsigned int driver_flags = AZX_DCAPS_PM_RUNTIME; + struct cix_ipbloq_hda *hda; + struct snd_card *card; + struct azx *chip; + int err; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + hda->dev = &pdev->dev; + + hda->reset = devm_reset_control_get(hda->dev, NULL); + if (IS_ERR(hda->reset)) + return dev_err_probe(hda->dev, PTR_ERR(hda->reset), + "failed to get reset, err = %ld\n", PTR_ERR(hda->reset)); + + hda->clocks[hda->nclocks++].id = "ipg"; + hda->clocks[hda->nclocks++].id = "per"; + err = devm_clk_bulk_get(hda->dev, hda->nclocks, hda->clocks); + if (err < 0) + return dev_err_probe(hda->dev, err, "failed to get clk, err = %d\n", err); + + dma_set_mask_and_coherent(hda->dev, DMA_BIT_MASK(32)); + + err = of_reserved_mem_device_init(hda->dev); + if (err < 0 && err != -ENODEV) { + dev_err(hda->dev, + "failed to init reserved mem for DMA, err = %d\n", err); + return err; + } + + err = snd_card_new(hda->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); + if (err < 0) + return dev_err_probe(hda->dev, err, "failed to crate card, err = %d\n", err); + + err = cix_ipbloq_hda_create(hda, card, driver_flags); + if (err < 0) + goto out_free_card; + + chip = &hda->chip; + card->private_data = chip; + dev_set_drvdata(hda->dev, card); + + pm_runtime_enable(hda->dev); + if (!azx_has_pm_runtime(chip)) + pm_runtime_forbid(hda->dev); + + err = pm_runtime_resume_and_get(hda->dev); + if (err < 0) { + dev_err(hda->dev, "runtime resume and get failed, err = %d\n", err); + goto out_free_device; + } + + err = cix_ipbloq_hda_init(hda, chip, pdev); + if (err < 0) + goto out_free_device; + + err = cix_ipbloq_hda_probe_codec(hda); + if (err < 0) + goto out_free_device; + + pm_runtime_put(hda->dev); + + return 0; + +out_free_device: + snd_device_free(card, chip); +out_free_card: + snd_card_free(card); + + return err; +} + +static void cix_ipbloq_hda_remove(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip = card->private_data; + + snd_device_free(card, chip); + snd_card_free(card); + + pm_runtime_disable(&pdev->dev); +} + +static void cix_ipbloq_hda_shutdown(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip; + + if (!card) + return; + + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + +static int cix_ipbloq_hda_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_suspend(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D3cold); + + return 0; +} + +static int cix_ipbloq_hda_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_resume(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static int cix_ipbloq_hda_runtime_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct cix_ipbloq_hda *hda = container_of(chip, struct cix_ipbloq_hda, chip); + + if (chip && chip->running) { + azx_stop_chip(chip); + azx_enter_link_reset(chip); + } + + clk_bulk_disable_unprepare(hda->nclocks, hda->clocks); + + return 0; +} + +static int cix_ipbloq_hda_runtime_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct cix_ipbloq_hda *hda = container_of(chip, struct cix_ipbloq_hda, chip); + int rc; + + rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks); + if (rc) { + dev_err(dev, "failed to enable clk bulk, rc: %d\n", rc); + return rc; + } + + rc = reset_control_assert(hda->reset); + if (rc) { + dev_err(dev, "failed to assert reset, rc: %d\n", rc); + return rc; + } + + rc = reset_control_deassert(hda->reset); + if (rc) { + dev_err(dev, "failed to deassert reset, rc: %d\n", rc); + return rc; + } + + if (chip && chip->running) + azx_init_chip(chip, 1); + + return 0; +} + +static const struct dev_pm_ops cix_ipbloq_hda_pm = { + SYSTEM_SLEEP_PM_OPS(cix_ipbloq_hda_suspend, + cix_ipbloq_hda_resume) + RUNTIME_PM_OPS(cix_ipbloq_hda_runtime_suspend, + cix_ipbloq_hda_runtime_resume, NULL) +}; + +static const struct of_device_id cix_ipbloq_hda_match[] = { + { .compatible = "cix,sky1-ipbloq-hda" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cix_ipbloq_hda_match); + +static struct platform_driver cix_ipbloq_hda_driver = { + .driver = { + .name = "cix-ipbloq-hda", + .pm = pm_ptr(&cix_ipbloq_hda_pm), + .of_match_table = cix_ipbloq_hda_match, + }, + .probe = cix_ipbloq_hda_probe, + .remove = cix_ipbloq_hda_remove, + .shutdown = cix_ipbloq_hda_shutdown, +}; +module_platform_driver(cix_ipbloq_hda_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CIX IPBLOQ HDA bus driver"); +MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>"); diff --git a/sound/hda/core/bus.c b/sound/hda/core/bus.c index 9b196c915f37..81498f1e413e 100644 --- a/sound/hda/core/bus.c +++ b/sound/hda/core/bus.c @@ -47,6 +47,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, INIT_LIST_HEAD(&bus->hlink_list); init_waitqueue_head(&bus->rirb_wq); bus->irq = -1; + bus->addr_offset = 0; /* * Default value of '8' is as per the HD audio specification (Rev 1.0a). diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c index a7c00ad80117..69e11d62bbfa 100644 --- a/sound/hda/core/controller.c +++ b/sound/hda/core/controller.c @@ -48,8 +48,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus) /* CORB set up */ bus->corb.addr = bus->rb.addr; bus->corb.buf = (__le32 *)bus->rb.area; - snd_hdac_chip_writel(bus, CORBLBASE, (u32)bus->corb.addr); - snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr)); + snd_hdac_chip_writel(bus, CORBLBASE, (u32)(bus->corb.addr + bus->addr_offset)); + snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr + bus->addr_offset)); /* set the corb size to 256 entries (ULI requires explicitly) */ snd_hdac_chip_writeb(bus, CORBSIZE, 0x02); @@ -70,8 +70,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus) bus->rirb.buf = (__le32 *)(bus->rb.area + 2048); bus->rirb.wp = bus->rirb.rp = 0; memset(bus->rirb.cmds, 0, sizeof(bus->rirb.cmds)); - snd_hdac_chip_writel(bus, RIRBLBASE, (u32)bus->rirb.addr); - snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr)); + snd_hdac_chip_writel(bus, RIRBLBASE, (u32)(bus->rirb.addr + bus->addr_offset)); + snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr + bus->addr_offset)); /* set the rirb size to 256 entries (ULI requires explicitly) */ snd_hdac_chip_writeb(bus, RIRBSIZE, 0x02); @@ -625,8 +625,8 @@ bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) /* program the position buffer */ if (bus->use_posbuf && bus->posbuf.addr) { - snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr); - snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr)); + snd_hdac_chip_writel(bus, DPLBASE, (u32)(bus->posbuf.addr + bus->addr_offset)); + snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr + bus->addr_offset)); } bus->chip_init = true; diff --git a/sound/hda/core/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c index c401c0658421..0c25e87408de 100644 --- a/sound/hda/core/intel-dsp-config.c +++ b/sound/hda/core/intel-dsp-config.c @@ -718,7 +718,8 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) /* find the configuration for the specific device */ cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); if (!cfg) - return SND_INTEL_DSP_DRIVER_ANY; + return IS_ENABLED(CONFIG_SND_HDA_INTEL) ? + SND_INTEL_DSP_DRIVER_LEGACY : SND_INTEL_DSP_DRIVER_ANY; if (cfg->flags & FLAG_SOF) { if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c index 579ec544ef4a..b471a038b314 100644 --- a/sound/hda/core/stream.c +++ b/sound/hda/core/stream.c @@ -288,16 +288,16 @@ int snd_hdac_stream_setup(struct hdac_stream *azx_dev, bool code_loading) /* program the BDL address */ /* lower BDL address */ - snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); + snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)(azx_dev->bdl.addr + bus->addr_offset)); /* upper BDL address */ snd_hdac_stream_writel(azx_dev, SD_BDLPU, - upper_32_bits(azx_dev->bdl.addr)); + upper_32_bits(azx_dev->bdl.addr + bus->addr_offset)); /* enable the position buffer */ if (bus->use_posbuf && bus->posbuf.addr) { if (!(snd_hdac_chip_readl(bus, DPLBASE) & AZX_DPLBASE_ENABLE)) snd_hdac_chip_writel(bus, DPLBASE, - (u32)bus->posbuf.addr | AZX_DPLBASE_ENABLE); + (u32)(bus->posbuf.addr + bus->addr_offset) | AZX_DPLBASE_ENABLE); } /* set the interrupt enable bits in the descriptor control register */ @@ -464,8 +464,8 @@ static int setup_bdle(struct hdac_bus *bus, addr = snd_sgbuf_get_addr(dmab, ofs); /* program the address field of the BDL entry */ - bdl[0] = cpu_to_le32((u32)addr); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); + bdl[0] = cpu_to_le32((u32)(addr + bus->addr_offset)); + bdl[1] = cpu_to_le32(upper_32_bits(addr + bus->addr_offset)); /* program the size field of the BDL entry */ chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size); /* one BDLE cannot cross 4K boundary on CTHDA chips */ diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 13419837dfb7..a3291e626440 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -131,7 +131,13 @@ static int snd_pdacf_probe(struct pcmcia_device *link) link->config_index = 1; link->config_regs = PRESENT_OPTION; - return pdacf_config(link); + err = pdacf_config(link); + if (err < 0) { + card_list[i] = NULL; + snd_card_free(card); + return err; + } + return 0; } diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 2e09f2a513a6..9a5c9aa8eec4 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -284,7 +284,13 @@ static int vxpocket_probe(struct pcmcia_device *p_dev) vxp->p_dev = p_dev; - return vxpocket_config(p_dev); + err = vxpocket_config(p_dev); + if (err < 0) { + card_alloc &= ~(1 << i); + snd_card_free(card); + return err; + } + return 0; } static void vxpocket_detach(struct pcmcia_device *link) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 4ba0a66981ea..283a674c7e2c 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -157,6 +157,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas spin_lock_irq(&chip->acp_lock); list_for_each_entry(stream, &chip->stream_list, list) { + if (dai->id != stream->dai_id) + continue; switch (chip->acp_rev) { case ACP_RN_PCI_ID: case ACP_RMB_PCI_ID: diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 3078f459e005..4e477c48d4bd 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -219,7 +219,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, SP_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip); reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip); - phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START; + else + phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip)); } else { reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip); @@ -227,7 +230,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, SP_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip); reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip); - phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START; + else + phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip)); } break; @@ -238,7 +244,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, BT_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip); reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip); - phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START; + else + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip)); } else { reg_dma_size = ACP_BT_RX_DMA_SIZE(chip); @@ -246,7 +255,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, BT_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip); reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip); - phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START; + else + phy_addr = I2S_BT_RX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip)); } break; @@ -257,7 +269,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, HS_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_HS_TX_FIFOADDR; reg_fifo_size = ACP_HS_TX_FIFOSIZE; - phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START; + else + phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR); } else { reg_dma_size = ACP_HS_RX_DMA_SIZE; @@ -265,7 +280,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, HS_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_HS_RX_FIFOADDR; reg_fifo_size = ACP_HS_RX_FIFOSIZE; - phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START; + else + phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR); } break; diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index f210a253da9f..bf4d9d336561 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -661,6 +661,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7UCX"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "HONOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "GOH-X"), + } + }, {} }; diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c index e3a4fcc63a56..efeb06ddabeb 100644 --- a/sound/soc/bcm/bcm63xx-pcm-whistler.c +++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c @@ -358,7 +358,9 @@ static int bcm63xx_soc_pcm_new(struct snd_soc_component *component, i2s_priv = dev_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)->dev); - of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1); + ret = of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1); + if (ret) + return ret; ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(32)); if (ret) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6087ebde9523..061791e61907 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -777,7 +777,6 @@ config SND_SOC_CQ0093VC config SND_SOC_CROS_EC_CODEC tristate "codec driver for ChromeOS EC" depends on CROS_EC - select CRYPTO select CRYPTO_LIB_SHA256 help If you say yes here you will get support for the @@ -918,7 +917,7 @@ config SND_SOC_CS35L56_CAL_DEBUGFS config SND_SOC_CS35L56_CAL_SET_CTRL bool "CS35L56 ALSA control to restore factory calibration" default N - select SND_SOC_CS35L56_CAL_SYSFS_COMMON + select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON help Allow restoring factory calibration data through an ALSA control. This is only needed on platforms without UEFI or diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index f0b465f9ded5..f81cd8cebdd8 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -671,7 +671,15 @@ static int ak4458_runtime_resume(struct device *dev) regcache_cache_only(ak4458->regmap, false); regcache_mark_dirty(ak4458->regmap); - return regcache_sync(ak4458->regmap); + ret = regcache_sync(ak4458->regmap); + if (ret) + goto err; + + return 0; +err: + regcache_cache_only(ak4458->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(ak4458->supplies), ak4458->supplies); + return ret; } static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { @@ -775,16 +783,12 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) pm_runtime_enable(&i2c->dev); regcache_cache_only(ak4458->regmap, true); - ak4458_reset(ak4458, false); return 0; } static void ak4458_i2c_remove(struct i2c_client *i2c) { - struct ak4458_priv *ak4458 = i2c_get_clientdata(i2c); - - ak4458_reset(ak4458, true); pm_runtime_disable(&i2c->dev); } diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 683f3e472f50..73684fc5beb1 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -372,7 +372,15 @@ static int ak5558_runtime_resume(struct device *dev) regcache_cache_only(ak5558->regmap, false); regcache_mark_dirty(ak5558->regmap); - return regcache_sync(ak5558->regmap); + ret = regcache_sync(ak5558->regmap); + if (ret) + goto err; + + return 0; +err: + regcache_cache_only(ak5558->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(ak5558->supplies), ak5558->supplies); + return ret; } static const struct dev_pm_ops ak5558_pm = { diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c index 8c9fd9980a7d..d8f8b0259cd1 100644 --- a/sound/soc/codecs/cs-amp-lib.c +++ b/sound/soc/codecs/cs-amp-lib.c @@ -7,7 +7,6 @@ #include <asm/byteorder.h> #include <kunit/static_stub.h> -#include <linux/cleanup.h> #include <linux/debugfs.h> #include <linux/dev_printk.h> #include <linux/efi.h> @@ -310,8 +309,9 @@ static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev, efi_guid_t **guid, u32 *attr) { - struct cirrus_amp_efi_data *efi_data __free(kfree) = NULL; + struct cirrus_amp_efi_data *efi_data; unsigned long data_size = 0; + u8 *data; efi_status_t status; int i, ret; @@ -339,18 +339,19 @@ static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev, } /* Get variable contents into buffer */ - efi_data = kmalloc(data_size, GFP_KERNEL); - if (!efi_data) + data = kmalloc(data_size, GFP_KERNEL); + if (!data) return ERR_PTR(-ENOMEM); status = cs_amp_get_efi_variable(cs_amp_lib_cal_efivars[i].name, cs_amp_lib_cal_efivars[i].guid, - attr, &data_size, efi_data); + attr, &data_size, data); if (status != EFI_SUCCESS) { ret = -EINVAL; goto err; } + efi_data = (struct cirrus_amp_efi_data *)data; dev_dbg(dev, "Calibration: Size=%d, Amp Count=%d\n", efi_data->size, efi_data->count); if ((efi_data->count > 128) || @@ -364,9 +365,10 @@ static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev, if (efi_data->size == 0) efi_data->size = data_size; - return_ptr(efi_data); + return efi_data; err: + kfree(data); dev_err(dev, "Failed to read calibration data from EFI: %d\n", ret); return ERR_PTR(ret); @@ -389,9 +391,9 @@ static int cs_amp_set_cal_efi_buffer(struct device *dev, static int _cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index, struct cirrus_amp_cal_data *out_data) { - struct cirrus_amp_efi_data *efi_data __free(kfree) = NULL; + struct cirrus_amp_efi_data *efi_data; struct cirrus_amp_cal_data *cal = NULL; - int i; + int i, ret; efi_data = cs_amp_get_cal_efi_buffer(dev, NULL, NULL, NULL); if (IS_ERR(efi_data)) @@ -432,14 +434,17 @@ static int _cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, dev_warn(dev, "Calibration entry %d does not match silicon ID", amp_index); } - if (!cal) { + if (cal) { + memcpy(out_data, cal, sizeof(*out_data)); + ret = 0; + } else { dev_warn(dev, "No calibration for silicon ID %#llx\n", target_uid); - return -ENOENT; + ret = -ENOENT; } - memcpy(out_data, cal, sizeof(*out_data)); + kfree(efi_data); - return 0; + return ret; } static int _cs_amp_set_efi_calibration_data(struct device *dev, int amp_index, int num_amps, diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 3a8a8dd065b7..ee56dfceedeb 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1188,13 +1188,14 @@ static int cs35l41_get_system_name(struct cs35l41_private *cs35l41) } } -err: if (sub) { cs35l41->dsp.system_name = sub; dev_info(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name); - } else - dev_warn(cs35l41->dev, "Subsystem ID not found\n"); + return 0; + } +err: + dev_warn(cs35l41->dev, "Subsystem ID not found\n"); return ret; } diff --git a/sound/soc/codecs/nau8325.c b/sound/soc/codecs/nau8325.c index 3bfdb448f8bd..e651263a9812 100644 --- a/sound/soc/codecs/nau8325.c +++ b/sound/soc/codecs/nau8325.c @@ -386,7 +386,8 @@ static int nau8325_clksrc_choose(struct nau8325 *nau8325, const struct nau8325_srate_attr **srate_table, int *n1_sel, int *mult_sel, int *n2_sel) { - int i, j, mclk, mclk_max, ratio, ratio_sel, n2_max; + int i, j, mclk, ratio; + int mclk_max = 0, ratio_sel = 0, n2_max = 0; if (!nau8325->mclk || !nau8325->fs) goto proc_err; @@ -408,7 +409,6 @@ static int nau8325_clksrc_choose(struct nau8325 *nau8325, } /* Get MCLK_SRC through 1/N, Multiplier, and then 1/N2. */ - mclk_max = 0; for (i = 0; i < ARRAY_SIZE(mclk_n1_div); i++) { for (j = 0; j < ARRAY_SIZE(mclk_n3_mult); j++) { mclk = nau8325->mclk << mclk_n3_mult[j].param; diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index e3f9b03df3aa..feecef258b65 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -115,7 +115,8 @@ static const struct reg_sequence rt1320_blind_write[] = { static const struct reg_sequence rt1320_vc_blind_write[] = { { 0xc003, 0xe0 }, { 0xe80a, 0x01 }, - { 0xc5c3, 0xf3 }, + { 0xc5c3, 0xf2 }, + { 0xc5c8, 0x03 }, { 0xc057, 0x51 }, { 0xc054, 0x35 }, { 0xca05, 0xd6 }, @@ -126,8 +127,6 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0xc609, 0x40 }, { 0xc046, 0xff }, { 0xc045, 0xff }, - { 0xda81, 0x14 }, - { 0xda8d, 0x14 }, { 0xc044, 0xff }, { 0xc043, 0xff }, { 0xc042, 0xff }, @@ -136,8 +135,8 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0xcc10, 0x01 }, { 0xc700, 0xf0 }, { 0xc701, 0x13 }, - { 0xc901, 0x09 }, - { 0xc900, 0xd0 }, + { 0xc901, 0x04 }, + { 0xc900, 0x73 }, { 0xde03, 0x05 }, { 0xdd0b, 0x0d }, { 0xdd0a, 0xff }, @@ -153,6 +152,7 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0xf082, 0xff }, { 0xf081, 0xff }, { 0xf080, 0xff }, + { 0xe801, 0x01 }, { 0xe802, 0xf8 }, { 0xe803, 0xbe }, { 0xc003, 0xc0 }, @@ -202,7 +202,7 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0x3fc2bfc3, 0x00 }, { 0x3fc2bfc2, 0x00 }, { 0x3fc2bfc1, 0x00 }, - { 0x3fc2bfc0, 0x03 }, + { 0x3fc2bfc0, 0x07 }, { 0x0000d486, 0x43 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 }, { 0x1000db00, 0x07 }, @@ -241,9 +241,7 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0x1000db21, 0x00 }, { 0x1000db22, 0x00 }, { 0x1000db23, 0x00 }, - { 0x0000d540, 0x01 }, - { 0x0000c081, 0xfc }, - { 0x0000f01e, 0x80 }, + { 0x0000d540, 0x21 }, { 0xc01b, 0xfc }, { 0xc5d1, 0x89 }, { 0xc5d8, 0x0a }, diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index f1dced57a59b..f4dbcf04be49 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -2866,7 +2866,7 @@ static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x, dev_err(dev, "Couldn't parse phandle to qcom,rx-device!\n"); return -ENODEV; } - of_node_get(wcd937x->rxnode); + component_match_add_release(dev, matchptr, component_release_of, component_compare_of, wcd937x->rxnode); @@ -2875,7 +2875,7 @@ static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x, dev_err(dev, "Couldn't parse phandle to qcom,tx-device\n"); return -ENODEV; } - of_node_get(wcd937x->txnode); + component_match_add_release(dev, matchptr, component_release_of, component_compare_of, wcd937x->txnode); diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index f5b7de2bc896..cb0a0bfdb6e3 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -3464,7 +3464,6 @@ static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, return -ENODEV; } - of_node_get(wcd938x->rxnode); component_match_add_release(dev, matchptr, component_release_of, component_compare_of, wcd938x->rxnode); @@ -3473,7 +3472,7 @@ static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, dev_err(dev, "%s: Tx-device node not defined\n", __func__); return -ENODEV; } - of_node_get(wcd938x->txnode); + component_match_add_release(dev, matchptr, component_release_of, component_compare_of, wcd938x->txnode); return 0; diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 7c5dd0484384..01f1a08f48e6 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -3526,7 +3526,6 @@ static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x, return -ENODEV; } - of_node_get(wcd939x->rxnode); component_match_add_release(dev, matchptr, component_release_of, component_compare_of, wcd939x->rxnode); @@ -3535,7 +3534,7 @@ static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x, dev_err(dev, "%s: Tx-device node not defined\n", __func__); return -ENODEV; } - of_node_get(wcd939x->txnode); + component_match_add_release(dev, matchptr, component_release_of, component_compare_of, wcd939x->txnode); return 0; diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 2c7eb0baa0f3..70a6159430ed 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -1045,8 +1045,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) * The notifier is initialized in snd_soc_card_jack_new(), then * snd_soc_jack_notifier_register can be called. */ - if (of_property_read_bool(np, "hp-det-gpios") || - of_property_read_bool(np, "hp-det-gpio") /* deprecated */) { + if (of_property_present(np, "hp-det-gpios") || + of_property_present(np, "hp-det-gpio") /* deprecated */) { ret = simple_util_init_jack(&priv->card, &priv->hp_jack, 1, NULL, "Headphone Jack"); if (ret) @@ -1055,8 +1055,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb); } - if (of_property_read_bool(np, "mic-det-gpios") || - of_property_read_bool(np, "mic-det-gpio") /* deprecated */) { + if (of_property_present(np, "mic-det-gpios") || + of_property_present(np, "mic-det-gpio") /* deprecated */) { ret = simple_util_init_jack(&priv->card, &priv->mic_jack, 0, NULL, "Mic Jack"); if (ret) diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 1bba48318e2d..7dacc06b2f02 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -473,5 +473,8 @@ struct snd_soc_component_driver fsl_asrc_component = { .pointer = fsl_asrc_dma_pcm_pointer, .pcm_construct = fsl_asrc_dma_pcm_new, .legacy_dai_naming = 1, +#ifdef CONFIG_DEBUG_FS + .debugfs_prefix = "asrc", +#endif }; EXPORT_SYMBOL_GPL(fsl_asrc_component); diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index f404a39009e1..e64a0d97afd0 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1577,6 +1577,9 @@ static const struct snd_soc_component_driver fsl_easrc_component = { .controls = fsl_easrc_snd_controls, .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls), .legacy_dai_naming = 1, +#ifdef CONFIG_DEBUG_FS + .debugfs_prefix = "easrc", +#endif }; static const struct reg_default fsl_easrc_reg_defaults[] = { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 72bfc91e21b9..2fa14fbdfe1a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -917,8 +917,14 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, tx ? sai->dma_params_tx.maxburst : sai->dma_params_rx.maxburst); - ret = snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &sai->constraint_rates); + if (sai->is_consumer_mode[tx]) + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &fsl_sai_rate_constraints); + else + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &sai->constraint_rates); return ret; } @@ -1075,6 +1081,7 @@ static const struct reg_default fsl_sai_reg_defaults_ofs0[] = { {FSL_SAI_TDR6, 0}, {FSL_SAI_TDR7, 0}, {FSL_SAI_TMR, 0}, + {FSL_SAI_TTCTL, 0}, {FSL_SAI_RCR1(0), 0}, {FSL_SAI_RCR2(0), 0}, {FSL_SAI_RCR3(0), 0}, @@ -1098,12 +1105,14 @@ static const struct reg_default fsl_sai_reg_defaults_ofs8[] = { {FSL_SAI_TDR6, 0}, {FSL_SAI_TDR7, 0}, {FSL_SAI_TMR, 0}, + {FSL_SAI_TTCTL, 0}, {FSL_SAI_RCR1(8), 0}, {FSL_SAI_RCR2(8), 0}, {FSL_SAI_RCR3(8), 0}, {FSL_SAI_RCR4(8), 0}, {FSL_SAI_RCR5(8), 0}, {FSL_SAI_RMR, 0}, + {FSL_SAI_RTCTL, 0}, {FSL_SAI_MCTL, 0}, {FSL_SAI_MDIV, 0}, }; diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 06434b2c9a0f..a268fb81a2f8 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1323,6 +1323,7 @@ static const struct reg_default fsl_xcvr_phy_reg_defaults[] = { }; static const struct regmap_config fsl_xcvr_regmap_phy_cfg = { + .name = "phy", .reg_bits = 8, .reg_stride = 4, .val_bits = 32, @@ -1335,6 +1336,7 @@ static const struct regmap_config fsl_xcvr_regmap_phy_cfg = { }; static const struct regmap_config fsl_xcvr_regmap_pllv0_cfg = { + .name = "pllv0", .reg_bits = 8, .reg_stride = 4, .val_bits = 32, @@ -1345,6 +1347,7 @@ static const struct regmap_config fsl_xcvr_regmap_pllv0_cfg = { }; static const struct regmap_config fsl_xcvr_regmap_pllv1_cfg = { + .name = "pllv1", .reg_bits = 8, .reg_stride = 4, .val_bits = 32, diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index ec9fd8486c05..1270ee21ee72 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -699,6 +699,69 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_fb_adr[] = { }, }; +static const struct snd_soc_acpi_adr_device cs35l56_6amp_1_fb_adr[] = { + { + .adr = 0x00013701FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP6" + }, + { + .adr = 0x00013601FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints), + .endpoints = cs35l56_3_fb_endpoints, + .name_prefix = "AMP5" + }, + { + .adr = 0x00013501FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints), + .endpoints = cs35l56_5_fb_endpoints, + .name_prefix = "AMP4" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l63_6amp_3_fb_adr[] = { + { + .adr = 0x00033001FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints), + .endpoints = cs35l56_l_fb_endpoints, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033201FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints), + .endpoints = cs35l56_2_fb_endpoints, + .name_prefix = "AMP3" + }, + { + .adr = 0x00033401FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_4_fb_endpoints), + .endpoints = cs35l56_4_fb_endpoints, + .name_prefix = "AMP5" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l63_6amp_2_fb_adr[] = { + { + .adr = 0x00023101FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP2" + }, + { + .adr = 0x00023301FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints), + .endpoints = cs35l56_3_fb_endpoints, + .name_prefix = "AMP4" + }, + { + .adr = 0x00023501FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints), + .endpoints = cs35l56_5_fb_endpoints, + .name_prefix = "AMP6" + }, +}; + static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { { .adr = 0x00023201FA355601ull, @@ -1069,6 +1132,35 @@ static const struct snd_soc_acpi_link_adr mtl_cs35l56_x8_link0_link1_fb[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_cs35l56_x6_link0_link1_fb[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_6amp_1_fb_adr), + .adr_d = cs35l56_6amp_1_fb_adr, + }, + { + .mask = BIT(0), + /* First 3 amps in cs35l56_0_fb_adr */ + .num_adr = 3, + .adr_d = cs35l56_0_fb_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr mtl_cs35l63_x6_link2_link3_fb[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l63_6amp_3_fb_adr), + .adr_d = cs35l63_6amp_3_fb_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l63_6amp_2_fb_adr), + .adr_d = cs35l63_6amp_2_fb_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr mtl_cs35l63_x2_link1_link3_fb[] = { { .mask = BIT(3), @@ -1190,6 +1282,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .get_function_tplg_files = sof_sdw_get_tplg_files, }, { + .link_mask = BIT(0) | BIT(1), + .links = mtl_cs35l56_x6_link0_link1_fb, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb6.tplg" + }, + { .link_mask = BIT(0), .links = mtl_cs42l43_l0, .drv_name = "sof_sdw", @@ -1203,6 +1301,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg", }, { + .link_mask = BIT(2) | BIT(3), + .links = mtl_cs35l63_x6_link2_link3_fb, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb6.tplg", + }, + { .link_mask = GENMASK(3, 0), .links = mtl_3_in_1_sdca, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c index 2768dd10aaa0..b8695d47e55b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c @@ -15,49 +15,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_machines); -/* - * Multi-function codecs with three endpoints created for - * headset, amp and dmic functions. - */ -static const struct snd_soc_acpi_endpoint rt_mf_endpoints[] = { - { - .num = 0, - .aggregated = 0, - .group_position = 0, - .group_id = 0, - }, - { - .num = 1, - .aggregated = 0, - .group_position = 0, - .group_id = 0, - }, - { - .num = 2, - .aggregated = 0, - .group_position = 0, - .group_id = 0, - }, -}; - -static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = { - { - .adr = 0x000330025d072201ull, - .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), - .endpoints = rt_mf_endpoints, - .name_prefix = "rt722" - } -}; - -static const struct snd_soc_acpi_link_adr nvl_rt722_l3[] = { - { - .mask = BIT(3), - .num_adr = ARRAY_SIZE(rt722_3_single_adr), - .adr_d = rt722_3_single_adr, - }, - {} -}; - /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_sdw_machines[] = { /* mockup tests need to be first */ @@ -79,12 +36,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-nvl-rt715-rt711-rt1308-mono.tplg", }, - { - .link_mask = BIT(3), - .links = nvl_rt722_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-nvl-rt722.tplg", - }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_sdw_machines); diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c index b10d4794159a..0daa7d83808b 100644 --- a/sound/soc/intel/common/sof-function-topology-lib.c +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -28,7 +28,7 @@ enum tplg_device_id { #define SOF_INTEL_PLATFORM_NAME_MAX 4 int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, - const char *prefix, const char ***tplg_files) + const char *prefix, const char ***tplg_files, bool best_effort) { struct snd_soc_acpi_mach_params mach_params = mach->mach_params; struct snd_soc_dai_link *dai_link; @@ -87,6 +87,9 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ dev_dbg(card->dev, "dai_link %s is not supported by separated tplg yet\n", dai_link->name); + if (best_effort) + continue; + return 0; } if (tplg_mask & BIT(tplg_dev)) diff --git a/sound/soc/intel/common/sof-function-topology-lib.h b/sound/soc/intel/common/sof-function-topology-lib.h index e7d0c39d0788..f358f8c52d78 100644 --- a/sound/soc/intel/common/sof-function-topology-lib.h +++ b/sound/soc/intel/common/sof-function-topology-lib.h @@ -10,6 +10,6 @@ #define _SND_SOC_ACPI_INTEL_GET_TPLG_H int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, - const char *prefix, const char ***tplg_files); + const char *prefix, const char ***tplg_files, bool best_effort); #endif diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 980851a12976..0b01fc9e13a7 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -947,7 +947,7 @@ static struct q6afe_port *q6afe_find_port(struct q6afe *afe, int token) struct q6afe_port *p; struct q6afe_port *ret = NULL; - guard(spinlock)(&afe->port_list_lock); + guard(spinlock_irqsave)(&afe->port_list_lock); list_for_each_entry(p, &afe->port_list, node) if (p->token == token) { ret = p; @@ -1807,7 +1807,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) port->cfg_type = cfg_type; kref_init(&port->refcount); - guard(spinlock)(&afe->port_list_lock); + guard(spinlock_irqsave)(&afe->port_list_lock); list_add_tail(&port->node, &afe->port_list); return port; diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index e18a8e44f2db..0ce9dff4dc52 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -365,10 +365,12 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; case QUATERNARY_MI2S_RX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; case QUATERNARY_TDM_RX_0: diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index c1ee470ec607..c69cdd6f2499 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -580,7 +580,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev) if (!pdm) return -ENOMEM; - pdm->version = (enum rk_pdm_version)device_get_match_data(&pdev->dev); + pdm->version = (unsigned long)device_get_match_data(&pdev->dev); if (pdm->version == RK_PDM_RK3308) { pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m"); if (IS_ERR(pdm->reset)) diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 6c656b2f7f3a..f169d95895ea 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -1534,8 +1534,10 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, * endpoint check is not necessary */ if (dai_info->quirk && - !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) + !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) { + (*num_devs)--; continue; + } } else { /* Check SDCA codec endpoint if there is no matching quirk */ ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j); @@ -1543,8 +1545,10 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, return ret; /* The endpoint is not present, skip */ - if (!ret) + if (!ret) { + (*num_devs)--; continue; + } } dev_dbg(dev, diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index ce86978c158d..624e9269fc25 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -111,7 +111,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, - unsigned int mask, unsigned int shift, int max) + unsigned int mask, unsigned int shift, int max, + bool sx) { int val = reg_val; @@ -141,20 +142,26 @@ static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int va } static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, - unsigned int mask, unsigned int shift, int max) + unsigned int mask, unsigned int shift, int max, + bool sx) { int val = (reg_val >> shift) & mask; if (mc->sign_bit) val = sign_extend32(val, mc->sign_bit); - val = clamp(val, mc->min, mc->max); - val -= mc->min; + if (sx) { + val -= mc->min; // SX controls intentionally can overflow here + val = min_t(unsigned int, val & mask, max); + } else { + val = clamp(val, mc->min, mc->max); + val -= mc->min; + } if (mc->invert) val = max - val; - return val & mask; + return val; } static unsigned int soc_mixer_ctl_to_reg(struct soc_mixer_control *mc, int val, @@ -280,9 +287,10 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol, static int soc_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, - struct soc_mixer_control *mc, int mask, int max) + struct soc_mixer_control *mc, int mask, int max, bool sx) { - int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, unsigned int, int); + int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, + unsigned int, int, bool); struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); unsigned int reg_val; int val; @@ -293,16 +301,16 @@ static int soc_get_volsw(struct snd_kcontrol *kcontrol, reg_to_ctl = soc_mixer_reg_to_ctl; reg_val = snd_soc_component_read(component, mc->reg); - val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx); ucontrol->value.integer.value[0] = val; if (snd_soc_volsw_is_stereo(mc)) { if (mc->reg == mc->rreg) { - val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max, sx); } else { reg_val = snd_soc_component_read(component, mc->rreg); - val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx); } ucontrol->value.integer.value[1] = val; @@ -371,7 +379,7 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int mask = soc_mixer_mask(mc); - return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min); + return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min, false); } EXPORT_SYMBOL_GPL(snd_soc_get_volsw); @@ -413,7 +421,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int mask = soc_mixer_sx_mask(mc); - return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max); + return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max, true); } EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c index ff5abccf0d88..e45dd051ab8c 100644 --- a/sound/soc/sof/intel/hda-sdw-bpt.c +++ b/sound/soc/sof/intel/hda-sdw-bpt.c @@ -10,6 +10,7 @@ * Hardware interface for SoundWire BPT support with HDA DMA */ +#include <linux/lcm.h> #include <sound/hdaudio_ext.h> #include <sound/hda-mlink.h> #include <sound/hda-sdw-bpt.h> @@ -236,6 +237,18 @@ static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *s return ret; } +#define FIFO_ALIGNMENT 64 + +unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth) +{ + unsigned int num_channels = DIV_ROUND_UP(dma_bandwidth, BPT_FREQUENCY * 32); + unsigned int data_block = num_channels * 4; + unsigned int alignment = lcm(data_block, FIFO_ALIGNMENT); + + return alignment; +} +EXPORT_SYMBOL_NS(hda_sdw_bpt_get_buf_size_alignment, "SND_SOC_SOF_INTEL_HDA_SDW_BPT"); + int hda_sdw_bpt_open(struct device *dev, int link_id, struct hdac_ext_stream **bpt_tx_stream, struct snd_dma_buffer *dmab_tx_bdl, u32 bpt_tx_num_bytes, u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream, diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 7b2533999195..23adc5d765b4 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -47,7 +47,7 @@ static const struct sof_dev_desc mtl_desc = { [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/mtl", }, .default_tplg_path = { - [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_4] = "sof-mtl.ri", @@ -77,7 +77,7 @@ static const struct sof_dev_desc arl_desc = { [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl", }, .default_tplg_path = { - [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_4] = "sof-arl.ri", @@ -107,7 +107,7 @@ static const struct sof_dev_desc arl_s_desc = { [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl-s", }, .default_tplg_path = { - [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_4] = "sof-arl-s.ri", diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 221e9d4052b8..d621e7914a73 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1752,11 +1752,9 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai channel_count = params_channels(params); sample_rate = params_rate(params); bit_depth = params_width(params); - /* - * Look for 32-bit blob first instead of 16-bit if copier - * supports multiple formats - */ - if (bit_depth == 16 && !single_bitdepth) { + + /* Prefer 32-bit blob if copier supports multiple formats */ + if (bit_depth <= 16 && !single_bitdepth) { dev_dbg(sdev->dev, "Looking for 32-bit blob first for DMIC\n"); format_change = true; bit_depth = 32; @@ -1799,10 +1797,18 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai if (format_change) { /* * The 32-bit blob was not found in NHLT table, try to - * look for one based on the params + * look for 16-bit for DMIC or based on the params for + * SSP */ - bit_depth = params_width(params); - format_change = false; + if (linktype == SOF_DAI_INTEL_DMIC) { + bit_depth = 16; + if (params_width(params) == 16) + format_change = false; + } else { + bit_depth = params_width(params); + format_change = false; + } + get_new_blob = true; } else if (linktype == SOF_DAI_INTEL_DMIC && !single_bitdepth) { /* @@ -1837,7 +1843,7 @@ out: *len = cfg->size >> 2; *dst = (u32 *)cfg->caps; - if (format_change) { + if (format_change || params_format(params) == SNDRV_PCM_FORMAT_FLOAT_LE) { /* * Update the params to reflect that different blob was loaded * instead of the requested bit depth (16 -> 32 or 32 -> 16). @@ -2280,8 +2286,19 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ch_map >>= 4; } - step = ch_count / blob->alh_cfg.device_count; - mask = GENMASK(step - 1, 0); + if (swidget->id == snd_soc_dapm_dai_in && ch_count == out_ref_channels) { + /* + * For playback DAI widgets where the channel number is equal to + * the output reference channels, set the step = 0 to ensure all + * the ch_mask is applied to all alh mappings. + */ + mask = ch_mask; + step = 0; + } else { + step = ch_count / blob->alh_cfg.device_count; + mask = GENMASK(step - 1, 0); + } + /* * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] * for all widgets with the same stream name @@ -2316,8 +2333,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* - * Set the same channel mask for playback as the audio data is - * duplicated for all speakers. For capture, split the channels + * Set the same channel mask if the widget channel count is the same + * as the FE channels for playback as the audio data is duplicated + * for all speakers in this case. Otherwise, split the channels * among the aggregated DAIs. For example, with 4 channels on 2 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the * two DAI's. @@ -2326,10 +2344,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * the tables in soc_acpi files depending on the _ADR and devID * registers for each codec. */ - if (w->id == snd_soc_dapm_dai_in) - blob->alh_cfg.mapping[i].channel_mask = ch_mask; - else - blob->alh_cfg.mapping[i].channel_mask = mask << (step * i); + blob->alh_cfg.mapping[i].channel_mask = mask << (step * i); i++; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c1083ea4624a..9bf8ab610a7e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2106,8 +2106,8 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* source component */ source_swidget = snd_sof_find_swidget(scomp, (char *)route->source); if (!source_swidget) { - dev_err(scomp->dev, "error: source %s not found\n", - route->source); + dev_err(scomp->dev, "source %s for sink %s is not found\n", + route->source, route->sink); ret = -EINVAL; goto err; } @@ -2125,8 +2125,8 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* sink component */ sink_swidget = snd_sof_find_swidget(scomp, (char *)route->sink); if (!sink_swidget) { - dev_err(scomp->dev, "error: sink %s not found\n", - route->sink); + dev_err(scomp->dev, "sink %s for source %s is not found\n", + route->sink, route->source); ret = -EINVAL; goto err; } @@ -2506,12 +2506,28 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) if (!tplg_files) return -ENOMEM; + /* Try to use function topologies if possible */ if (!sof_pdata->disable_function_topology && !disable_function_topology && sof_pdata->machine && sof_pdata->machine->get_function_tplg_files) { + /* + * When the topology name contains 'dummy' word, it means that + * there is no fallback option to monolithic topology in case + * any of the function topologies might be missing. + * In this case we should use best effort to form the card, + * ignoring functionalities that we are missing a fragment for. + * + * Note: monolithic topologies also ignore these possibly + * missing functions, so the functionality of the card would be + * identical to the case if there would be a fallback monolithic + * topology created for the configuration. + */ + bool no_fallback = strstr(file, "dummy"); + tplg_cnt = sof_pdata->machine->get_function_tplg_files(scomp->card, sof_pdata->machine, tplg_filename_prefix, - &tplg_files); + &tplg_files, + no_fallback); if (tplg_cnt < 0) { kfree(tplg_files); return tplg_cnt; diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index e795907a3963..261d9067d27b 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -2077,7 +2077,7 @@ static const struct regmap_config tegra210_ahub_regmap_config = { .val_bits = 32, .reg_stride = 4, .max_register = TEGRA210_MAX_REGISTER_ADDR, - .cache_type = REGCACHE_FLAT, + .cache_type = REGCACHE_FLAT_S, }; static const struct regmap_config tegra186_ahub_regmap_config = { @@ -2085,7 +2085,7 @@ static const struct regmap_config tegra186_ahub_regmap_config = { .val_bits = 32, .reg_stride = 4, .max_register = TEGRA186_MAX_REGISTER_ADDR, - .cache_type = REGCACHE_FLAT, + .cache_type = REGCACHE_FLAT_S, }; static const struct regmap_config tegra264_ahub_regmap_config = { @@ -2094,7 +2094,7 @@ static const struct regmap_config tegra264_ahub_regmap_config = { .reg_stride = 4, .writeable_reg = tegra264_ahub_wr_reg, .max_register = TEGRA264_MAX_REGISTER_ADDR, - .cache_type = REGCACHE_FLAT, + .cache_type = REGCACHE_FLAT_S, }; static const struct tegra_ahub_soc_data soc_data_tegra210 = { diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index cc15624ecaff..8f9313857ee9 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1481,15 +1481,15 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, return err; } - err = snd_usb_init_pitch(chip, ep->cur_audiofmt); + err = snd_usb_select_mode_quirk(chip, ep->cur_audiofmt); if (err < 0) return err; - err = init_sample_rate(chip, ep); + err = snd_usb_init_pitch(chip, ep->cur_audiofmt); if (err < 0) return err; - err = snd_usb_select_mode_quirk(chip, ep->cur_audiofmt); + err = init_sample_rate(chip, ep); if (err < 0) return err; diff --git a/sound/usb/format.c b/sound/usb/format.c index ec95a063beb1..64cfe4a9d8cd 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -34,6 +34,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, { int sample_width, sample_bytes; u64 pcm_formats = 0; + u64 dsd_formats = 0; switch (fp->protocol) { case UAC_VERSION_1: @@ -154,7 +155,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, fp->iface, fp->altsetting, format); } - pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes); + dsd_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes); + if (dsd_formats && !fp->dsd_dop) + pcm_formats = dsd_formats; return pcm_formats; } diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index f7189990dd6a..f8eccb1c58da 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2545,6 +2545,7 @@ static int snd_rme_get_status1(struct snd_kcontrol *kcontrol, struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = list->mixer->chip; + *status1 = 0; CLASS(snd_usb_lock, pm)(chip); if (pm.err < 0) return pm.err; diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c index 1c5712c31f5e..f9df40730eff 100644 --- a/sound/usb/mixer_us16x08.c +++ b/sound/usb/mixer_us16x08.c @@ -655,17 +655,25 @@ static void get_meter_levels_from_urb(int s, u8 *meter_urb) { int val = MUC2(meter_urb, s) + (MUC3(meter_urb, s) << 8); + int ch = MUB2(meter_urb, s) - 1; + + if (ch < 0) + return; if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 && MUA2(meter_urb, s) == 0x04 && MUB0(meter_urb, s) == 0x62) { - if (MUC0(meter_urb, s) == 0x72) - store->meter_level[MUB2(meter_urb, s) - 1] = val; - if (MUC0(meter_urb, s) == 0xb2) - store->comp_level[MUB2(meter_urb, s) - 1] = val; + if (ch < SND_US16X08_MAX_CHANNELS) { + if (MUC0(meter_urb, s) == 0x72) + store->meter_level[ch] = val; + if (MUC0(meter_urb, s) == 0xb2) + store->comp_level[ch] = val; + } } if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 && - MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62) - store->master_level[MUB2(meter_urb, s) - 1] = val; + MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62) { + if (ch < ARRAY_SIZE(store->master_level)) + store->master_level[ch] = val; + } } /* Function to retrieve current meter values from the device. diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 61bd61ffb1b2..f38330b095e9 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2221,7 +2221,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_IFACE_DELAY), DEVICE_FLG(0x0644, 0x8044, /* Esoteric D-05X */ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | - QUIRK_FLAG_IFACE_DELAY), + QUIRK_FLAG_IFACE_DELAY | QUIRK_FLAG_FORCE_IFACE_RESET), DEVICE_FLG(0x0644, 0x804a, /* TEAC UD-301 */ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY), @@ -2229,7 +2229,13 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_FORCE_IFACE_RESET), DEVICE_FLG(0x0644, 0x806b, /* TEAC UD-701 */ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | - QUIRK_FLAG_IFACE_DELAY), + QUIRK_FLAG_IFACE_DELAY | QUIRK_FLAG_FORCE_IFACE_RESET), + DEVICE_FLG(0x0644, 0x807d, /* TEAC UD-507 */ + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | + QUIRK_FLAG_IFACE_DELAY | QUIRK_FLAG_FORCE_IFACE_RESET), + DEVICE_FLG(0x0644, 0x806c, /* Esoteric XD */ + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | + QUIRK_FLAG_IFACE_DELAY | QUIRK_FLAG_FORCE_IFACE_RESET), DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */ QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */ @@ -2388,6 +2394,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */ QUIRK_FLAG_IGNORE_CTL_ERROR), + DEVICE_FLG(0x3255, 0x0000, /* Luxman D-10X */ + 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(0x413c, 0xa506, /* Dell AE515 sound bar */ @@ -2431,6 +2439,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x2622, /* IAG Limited devices */ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x2772, /* Musical Fidelity devices */ + QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x278b, /* Rotel? */ QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x292b, /* Gustard/Ess based devices */ |
