diff options
Diffstat (limited to 'sound')
25 files changed, 647 insertions, 225 deletions
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index cbd7d8badf91..92ca2b3b6c92 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1826,6 +1826,7 @@ err: if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type)) gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); gpiod_put(cs35l41->reset_gpio); + gpiod_put(cs35l41->cs_gpio); acpi_dev_put(cs35l41->dacpi); kfree(cs35l41->acpi_subsystem_id); @@ -1853,6 +1854,7 @@ void cs35l41_hda_remove(struct device *dev) if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type)) gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); gpiod_put(cs35l41->reset_gpio); + gpiod_put(cs35l41->cs_gpio); kfree(cs35l41->acpi_subsystem_id); } EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h index ce3f2bb6ffd0..3d925d677213 100644 --- a/sound/pci/hda/cs35l41_hda.h +++ b/sound/pci/hda/cs35l41_hda.h @@ -35,8 +35,8 @@ struct cs35l41_amp_efi_data { } __packed; enum cs35l41_hda_spk_pos { - CS35l41_LEFT, - CS35l41_RIGHT, + CS35L41_LEFT, + CS35L41_RIGHT, }; enum cs35l41_hda_gpio_function { @@ -50,6 +50,7 @@ struct cs35l41_hda { struct device *dev; struct regmap *regmap; struct gpio_desc *reset_gpio; + struct gpio_desc *cs_gpio; struct cs35l41_hw_cfg hw_cfg; struct hda_codec *codec; diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index c83328971728..c1afb721b4c6 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -6,9 +6,301 @@ // // Author: Stefan Binding <sbinding@opensource.cirrus.com> +#include <linux/acpi.h> #include <linux/gpio/consumer.h> #include <linux/string.h> #include "cs35l41_hda_property.h" +#include <linux/spi/spi.h> + +#define MAX_AMPS 4 + +struct cs35l41_config { + const char *ssid; + enum { + SPI, + I2C + } bus; + int num_amps; + enum { + INTERNAL, + EXTERNAL + } boost_type; + u8 channel[MAX_AMPS]; + int reset_gpio_index; /* -1 if no reset gpio */ + int spkid_gpio_index; /* -1 if no spkid gpio */ + int cs_gpio_index; /* -1 if no cs gpio, or cs-gpios already exists, max num amps == 2 */ + int boost_ind_nanohenry; /* Required if boost_type == Internal */ + int boost_peak_milliamp; /* Required if boost_type == Internal */ + int boost_cap_microfarad; /* Required if boost_type == Internal */ +}; + +static const struct cs35l41_config cs35l41_config_table[] = { +/* + * Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type. + * We can override the _DSD to correct the boost type here. + * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists + * in the ACPI. The Reset GPIO is also valid, so we can use the Reset defined in _DSD. + */ + { "103C89C6", SPI, 2, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, -1, -1, -1, 1000, 4500, 24 }, + { "104312AF", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10431433", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431463", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431473", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 }, + { "10431483", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 }, + { "10431493", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "104314D3", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "104314E3", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431503", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431533", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431573", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10431663", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 }, + { "104316D3", SPI, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + { "104316F3", SPI, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + { "104317F3", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431863", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "104318D3", I2C, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, + { "10431C9F", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10431CAF", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10431CCF", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10431CDF", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10431CEF", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10431D1F", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431DA2", SPI, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + { "10431E02", SPI, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + { "10431EE2", I2C, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "10431F12", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431F1F", SPI, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 }, + { "10431F62", SPI, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + {} +}; + +static int cs35l41_add_gpios(struct cs35l41_hda *cs35l41, struct device *physdev, int reset_gpio, + int spkid_gpio, int cs_gpio_index, int num_amps) +{ + struct acpi_gpio_mapping *gpio_mapping = NULL; + struct acpi_gpio_params *reset_gpio_params = NULL; + struct acpi_gpio_params *spkid_gpio_params = NULL; + struct acpi_gpio_params *cs_gpio_params = NULL; + unsigned int num_entries = 0; + unsigned int reset_index, spkid_index, csgpio_index; + int i; + + /* + * GPIO Mapping only needs to be done once, since it would be available for subsequent amps + */ + if (cs35l41->dacpi->driver_gpios) + return 0; + + if (reset_gpio >= 0) { + reset_index = num_entries; + num_entries++; + } + + if (spkid_gpio >= 0) { + spkid_index = num_entries; + num_entries++; + } + + if ((cs_gpio_index >= 0) && (num_amps == 2)) { + csgpio_index = num_entries; + num_entries++; + } + + if (!num_entries) + return 0; + + /* must include termination entry */ + num_entries++; + + gpio_mapping = devm_kcalloc(physdev, num_entries, sizeof(struct acpi_gpio_mapping), + GFP_KERNEL); + + if (!gpio_mapping) + goto err; + + if (reset_gpio >= 0) { + gpio_mapping[reset_index].name = "reset-gpios"; + reset_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params), + GFP_KERNEL); + if (!reset_gpio_params) + goto err; + + for (i = 0; i < num_amps; i++) + reset_gpio_params[i].crs_entry_index = reset_gpio; + + gpio_mapping[reset_index].data = reset_gpio_params; + gpio_mapping[reset_index].size = num_amps; + } + + if (spkid_gpio >= 0) { + gpio_mapping[spkid_index].name = "spk-id-gpios"; + spkid_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params), + GFP_KERNEL); + if (!spkid_gpio_params) + goto err; + + for (i = 0; i < num_amps; i++) + spkid_gpio_params[i].crs_entry_index = spkid_gpio; + + gpio_mapping[spkid_index].data = spkid_gpio_params; + gpio_mapping[spkid_index].size = num_amps; + } + + if ((cs_gpio_index >= 0) && (num_amps == 2)) { + gpio_mapping[csgpio_index].name = "cs-gpios"; + /* only one GPIO CS is supported without using _DSD, obtained using index 0 */ + cs_gpio_params = devm_kzalloc(physdev, sizeof(struct acpi_gpio_params), GFP_KERNEL); + if (!cs_gpio_params) + goto err; + + cs_gpio_params->crs_entry_index = cs_gpio_index; + + gpio_mapping[csgpio_index].data = cs_gpio_params; + gpio_mapping[csgpio_index].size = 1; + } + + return devm_acpi_dev_add_driver_gpios(physdev, gpio_mapping); +err: + devm_kfree(physdev, gpio_mapping); + devm_kfree(physdev, reset_gpio_params); + devm_kfree(physdev, spkid_gpio_params); + devm_kfree(physdev, cs_gpio_params); + return -ENOMEM; +} + +static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; + const struct cs35l41_config *cfg; + struct gpio_desc *cs_gpiod; + struct spi_device *spi; + bool dsd_found; + int ret; + + for (cfg = cs35l41_config_table; cfg->ssid; cfg++) { + if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id)) + break; + } + + if (!cfg->ssid) + return -ENOENT; + + if (!cs35l41->dacpi || cs35l41->dacpi != ACPI_COMPANION(physdev)) { + dev_err(cs35l41->dev, "ACPI Device does not match, cannot override _DSD.\n"); + return -ENODEV; + } + + dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id); + + dsd_found = acpi_dev_has_props(cs35l41->dacpi); + + if (!dsd_found) { + ret = cs35l41_add_gpios(cs35l41, physdev, cfg->reset_gpio_index, + cfg->spkid_gpio_index, cfg->cs_gpio_index, + cfg->num_amps); + if (ret) { + dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret); + return ret; + } + } else if (cfg->reset_gpio_index >= 0 || cfg->spkid_gpio_index >= 0) { + dev_warn(cs35l41->dev, "Cannot add Reset/Speaker ID/SPI CS GPIO Mapping, " + "_DSD already exists.\n"); + } + + if (cfg->bus == SPI) { + cs35l41->index = id; + + /* + * Manually set the Chip Select for the second amp <cs_gpio_index> in the node. + * This is only supported for systems with 2 amps, since we cannot expand the + * default number of chip selects without using cs-gpios + * The CS GPIO must be set high prior to communicating with the first amp (which + * uses a native chip select), to ensure the second amp does not clash with the + * first. + */ + if (IS_ENABLED(CONFIG_SPI) && cfg->cs_gpio_index >= 0) { + spi = to_spi_device(cs35l41->dev); + + if (cfg->num_amps != 2) { + dev_warn(cs35l41->dev, + "Cannot update SPI CS, Number of Amps (%d) != 2\n", + cfg->num_amps); + } else if (dsd_found) { + dev_warn(cs35l41->dev, + "Cannot update SPI CS, _DSD already exists.\n"); + } else { + /* + * This is obtained using driver_gpios, since only one GPIO for CS + * exists, this can be obtained using index 0. + */ + cs_gpiod = gpiod_get_index(physdev, "cs", 0, GPIOD_OUT_LOW); + if (IS_ERR(cs_gpiod)) { + dev_err(cs35l41->dev, + "Unable to get Chip Select GPIO descriptor\n"); + return PTR_ERR(cs_gpiod); + } + if (id == 1) { + spi_set_csgpiod(spi, 0, cs_gpiod); + cs35l41->cs_gpio = cs_gpiod; + } else { + gpiod_set_value_cansleep(cs_gpiod, true); + gpiod_put(cs_gpiod); + } + spi_setup(spi); + } + } + } else { + if (cfg->num_amps > 2) + /* + * i2c addresses for 3/4 amps are used in order: 0x40, 0x41, 0x42, 0x43, + * subtracting 0x40 would give zero-based index + */ + cs35l41->index = id - 0x40; + else + /* i2c addr 0x40 for first amp (always), 0x41/0x42 for 2nd amp */ + cs35l41->index = id == 0x40 ? 0 : 1; + } + + if (cfg->num_amps == 3) + /* 3 amps means a center channel, so no duplicate channels */ + cs35l41->channel_index = 0; + else + /* + * if 4 amps, there are duplicate channels, so they need different indexes + * if 2 amps, no duplicate channels, channel_index would be 0 + */ + cs35l41->channel_index = cs35l41->index / 2; + + cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset", + cs35l41->index, GPIOD_OUT_LOW, + "cs35l41-reset"); + cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, cfg->num_amps, -1); + + hw_cfg->spk_pos = cfg->channel[cs35l41->index]; + + if (cfg->boost_type == INTERNAL) { + hw_cfg->bst_type = CS35L41_INT_BOOST; + hw_cfg->bst_ind = cfg->boost_ind_nanohenry; + hw_cfg->bst_ipk = cfg->boost_peak_milliamp; + hw_cfg->bst_cap = cfg->boost_cap_microfarad; + hw_cfg->gpio1.func = CS35L41_NOT_USED; + hw_cfg->gpio1.valid = true; + } else { + hw_cfg->bst_type = CS35L41_EXT_BOOST; + hw_cfg->bst_ind = -1; + hw_cfg->bst_ipk = -1; + hw_cfg->bst_cap = -1; + hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH; + hw_cfg->gpio1.valid = true; + } + + hw_cfg->gpio2.func = CS35L41_INTERRUPT; + hw_cfg->gpio2.valid = true; + hw_cfg->valid = true; + + return 0; +} /* * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work. @@ -43,44 +335,6 @@ static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *phy return 0; } -/* - * Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type. - * We can override the _DSD to correct the boost type here. - * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists - * in the ACPI. - */ -static int hp_vision_acpi_fix(struct cs35l41_hda *cs35l41, struct device *physdev, int id, - const char *hid) -{ - struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; - - dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id); - - cs35l41->index = id; - cs35l41->channel_index = 0; - - /* - * This system has _DSD, it just contains an error, so we can still get the reset using - * the "reset" label. - */ - cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset", - cs35l41->index, GPIOD_OUT_LOW, - "cs35l41-reset"); - cs35l41->speaker_id = -ENOENT; - hw_cfg->spk_pos = cs35l41->index ? 0 : 1; // right:left - hw_cfg->gpio1.func = CS35L41_NOT_USED; - hw_cfg->gpio1.valid = true; - hw_cfg->gpio2.func = CS35L41_INTERRUPT; - hw_cfg->gpio2.valid = true; - hw_cfg->bst_type = CS35L41_INT_BOOST; - hw_cfg->bst_ind = 1000; - hw_cfg->bst_ipk = 4500; - hw_cfg->bst_cap = 24; - hw_cfg->valid = true; - - return 0; -} - struct cs35l41_prop_model { const char *hid; const char *ssid; @@ -91,7 +345,36 @@ struct cs35l41_prop_model { static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CLSA0100", NULL, lenovo_legion_no_acpi }, { "CLSA0101", NULL, lenovo_legion_no_acpi }, - { "CSC3551", "103C89C6", hp_vision_acpi_fix }, + { "CSC3551", "103C89C6", generic_dsd_config }, + { "CSC3551", "104312AF", generic_dsd_config }, + { "CSC3551", "10431433", generic_dsd_config }, + { "CSC3551", "10431463", generic_dsd_config }, + { "CSC3551", "10431473", generic_dsd_config }, + { "CSC3551", "10431483", generic_dsd_config }, + { "CSC3551", "10431493", generic_dsd_config }, + { "CSC3551", "104314D3", generic_dsd_config }, + { "CSC3551", "104314E3", generic_dsd_config }, + { "CSC3551", "10431503", generic_dsd_config }, + { "CSC3551", "10431533", generic_dsd_config }, + { "CSC3551", "10431573", generic_dsd_config }, + { "CSC3551", "10431663", generic_dsd_config }, + { "CSC3551", "104316D3", generic_dsd_config }, + { "CSC3551", "104316F3", generic_dsd_config }, + { "CSC3551", "104317F3", generic_dsd_config }, + { "CSC3551", "10431863", generic_dsd_config }, + { "CSC3551", "104318D3", generic_dsd_config }, + { "CSC3551", "10431C9F", generic_dsd_config }, + { "CSC3551", "10431CAF", generic_dsd_config }, + { "CSC3551", "10431CCF", generic_dsd_config }, + { "CSC3551", "10431CDF", generic_dsd_config }, + { "CSC3551", "10431CEF", generic_dsd_config }, + { "CSC3551", "10431D1F", generic_dsd_config }, + { "CSC3551", "10431DA2", generic_dsd_config }, + { "CSC3551", "10431E02", generic_dsd_config }, + { "CSC3551", "10431EE2", generic_dsd_config }, + { "CSC3551", "10431F12", generic_dsd_config }, + { "CSC3551", "10431F1F", generic_dsd_config }, + { "CSC3551", "10431F62", generic_dsd_config }, {} }; @@ -104,7 +387,7 @@ int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physd if (!strcmp(model->hid, hid) && (!model->ssid || (cs35l41->acpi_subsystem_id && - !strcmp(model->ssid, cs35l41->acpi_subsystem_id)))) + !strcasecmp(model->ssid, cs35l41->acpi_subsystem_id)))) return model->add_prop(cs35l41, physdev, id, hid); } diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c index 27d7fbc56b4c..080426de9083 100644 --- a/sound/pci/hda/cs35l56_hda_spi.c +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -33,7 +33,7 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi) return ret; } - ret = cs35l56_hda_common_probe(cs35l56, spi->chip_select); + ret = cs35l56_hda_common_probe(cs35l56, spi_get_chipselect(spi, 0)); if (ret) return ret; ret = cs35l56_irq_request(&cs35l56->base, spi->irq); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e45d4c405f8f..70b17b08d4ff 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9799,6 +9799,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN), SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360), + SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), @@ -9881,6 +9882,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), @@ -9925,6 +9927,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), @@ -9948,21 +9951,28 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), - SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650P", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604V", ALC285_FIXUP_ASUS_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603V", ALC285_FIXUP_ASUS_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601V", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X/GA402N", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604VI/VC/VE/VG/VJ/VQ/VU/VV/VY/VZ", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603VQ/VU/VV/VJ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601VV/VU/VJ/VQ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G614JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS G513PI/PU/PV", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1503, "ASUS G733PY/PZ/PZV/PYV", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), - SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301V", ALC285_FIXUP_ASUS_HEADSET_MIC), + 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, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK), - SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZV", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), + SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS UX7602VI/BZ", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS), SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), - SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally RC71L_RC71L", ALC294_FIXUP_ASUS_ALLY), + SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY), + SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2), @@ -9987,23 +9997,30 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS), - SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JI", ALC285_FIXUP_ASUS_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), - SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS ROG Strix G17 2023 (G713PV)", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1ccf, "ASUS G814JU/JV/JI", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1cdf, "ASUS G814JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1cef, "ASUS G834JY/JZ/JI/JG", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS G713PI/PU/PV/PVN", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), + SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), - SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS), SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), + SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1f1f, "ASUS H7604JI/JV/J3D", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC245_FIXUP_CS35L41_SPI_2), diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 63a90c7e8976..dfe281b57aa6 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -65,6 +65,15 @@ enum calib_data { CALIB_MAX }; +struct tas2781_hda { + struct device *dev; + struct tasdevice_priv *priv; + struct snd_kcontrol *dsp_prog_ctl; + struct snd_kcontrol *dsp_conf_ctl; + struct snd_kcontrol *prof_ctl; + struct snd_kcontrol *snd_ctls[3]; +}; + static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) { struct tasdevice_priv *tas_priv = data; @@ -125,26 +134,26 @@ err: static void tas2781_hda_playback_hook(struct device *dev, int action) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); - dev_dbg(tas_priv->dev, "%s: action = %d\n", __func__, action); + dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action); switch (action) { case HDA_GEN_PCM_ACT_OPEN: pm_runtime_get_sync(dev); - mutex_lock(&tas_priv->codec_lock); - tasdevice_tuning_switch(tas_priv, 0); - mutex_unlock(&tas_priv->codec_lock); + mutex_lock(&tas_hda->priv->codec_lock); + tasdevice_tuning_switch(tas_hda->priv, 0); + mutex_unlock(&tas_hda->priv->codec_lock); break; case HDA_GEN_PCM_ACT_CLOSE: - mutex_lock(&tas_priv->codec_lock); - tasdevice_tuning_switch(tas_priv, 1); - mutex_unlock(&tas_priv->codec_lock); + mutex_lock(&tas_hda->priv->codec_lock); + tasdevice_tuning_switch(tas_hda->priv, 1); + mutex_unlock(&tas_hda->priv->codec_lock); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); break; default: - dev_dbg(tas_priv->dev, "Playback action not supported: %d\n", + dev_dbg(tas_hda->dev, "Playback action not supported: %d\n", action); break; } @@ -421,9 +430,9 @@ static void tas2781_apply_calib(struct tasdevice_priv *tas_priv) } } -/* Update the calibrate data, including speaker impedance, f0, etc, into algo. +/* Update the calibration data, including speaker impedance, f0, etc, into algo. * Calibrate data is done by manufacturer in the factory. These data are used - * by Algo for calucating the speaker temperature, speaker membrance excursion + * by Algo for calculating the speaker temperature, speaker membrane excursion * and f0 in real time during playback. */ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) @@ -477,9 +486,28 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) return 0; } +static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) +{ + struct hda_codec *codec = tas_hda->priv->codec; + + if (tas_hda->dsp_prog_ctl) + snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); + + if (tas_hda->dsp_conf_ctl) + snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); + + for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--) + if (tas_hda->snd_ctls[i]) + snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]); + + if (tas_hda->prof_ctl) + snd_ctl_remove(codec->card, tas_hda->prof_ctl); +} + static void tasdev_fw_ready(const struct firmware *fmw, void *context) { struct tasdevice_priv *tas_priv = context; + struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); struct hda_codec *codec = tas_priv->codec; int i, ret; @@ -490,8 +518,8 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) if (ret) goto out; - ret = snd_ctl_add(codec->card, - snd_ctl_new1(&tas2781_prof_ctrl, tas_priv)); + tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, tas_priv); + ret = snd_ctl_add(codec->card, tas_hda->prof_ctl); if (ret) { dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n", @@ -500,8 +528,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) } for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) { - ret = snd_ctl_add(codec->card, - snd_ctl_new1(&tas2781_snd_controls[i], tas_priv)); + tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i], + tas_priv); + ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]); if (ret) { dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n", @@ -523,8 +552,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) goto out; } - ret = snd_ctl_add(codec->card, - snd_ctl_new1(&tas2781_dsp_prog_ctrl, tas_priv)); + tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl, + tas_priv); + ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl); if (ret) { dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n", @@ -532,8 +562,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) goto out; } - ret = snd_ctl_add(codec->card, - snd_ctl_new1(&tas2781_dsp_conf_ctrl, tas_priv)); + tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl, + tas_priv); + ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl); if (ret) { dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n", @@ -543,6 +574,10 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; tasdevice_prmg_load(tas_priv, 0); + if (tas_priv->fmw->nr_programs > 0) + tas_priv->cur_prog = 0; + if (tas_priv->fmw->nr_configurations > 0) + tas_priv->cur_conf = 0; /* If calibrated data occurs error, dsp will still works with default * calibrated data inside algo. @@ -550,27 +585,27 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) tas2781_save_calibration(tas_priv); out: - mutex_unlock(&tas_priv->codec_lock); + mutex_unlock(&tas_hda->priv->codec_lock); if (fmw) release_firmware(fmw); - pm_runtime_mark_last_busy(tas_priv->dev); - pm_runtime_put_autosuspend(tas_priv->dev); + pm_runtime_mark_last_busy(tas_hda->dev); + pm_runtime_put_autosuspend(tas_hda->dev); } static int tas2781_hda_bind(struct device *dev, struct device *master, void *master_data) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); struct hda_component *comps = master_data; struct hda_codec *codec; unsigned int subid; int ret; - if (!comps || tas_priv->index < 0 || - tas_priv->index >= HDA_MAX_COMPONENTS) + if (!comps || tas_hda->priv->index < 0 || + tas_hda->priv->index >= HDA_MAX_COMPONENTS) return -EINVAL; - comps = &comps[tas_priv->index]; + comps = &comps[tas_hda->priv->index]; if (comps->dev) return -EBUSY; @@ -579,10 +614,10 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, switch (subid) { case 0x17aa: - tas_priv->catlog_id = LENOVO; + tas_hda->priv->catlog_id = LENOVO; break; default: - tas_priv->catlog_id = OTHERS; + tas_hda->priv->catlog_id = OTHERS; break; } @@ -592,7 +627,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, strscpy(comps->name, dev_name(dev), sizeof(comps->name)); - ret = tascodec_init(tas_priv, codec, tasdev_fw_ready); + ret = tascodec_init(tas_hda->priv, codec, tasdev_fw_ready); if (!ret) comps->playback_hook = tas2781_hda_playback_hook; @@ -605,9 +640,9 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, static void tas2781_hda_unbind(struct device *dev, struct device *master, void *master_data) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); struct hda_component *comps = master_data; - comps = &comps[tas_priv->index]; + comps = &comps[tas_hda->priv->index]; if (comps->dev == dev) { comps->dev = NULL; @@ -615,10 +650,12 @@ static void tas2781_hda_unbind(struct device *dev, comps->playback_hook = NULL; } - tasdevice_config_info_remove(tas_priv); - tasdevice_dsp_remove(tas_priv); + tas2781_hda_remove_controls(tas_hda); - tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; + tasdevice_config_info_remove(tas_hda->priv); + tasdevice_dsp_remove(tas_hda->priv); + + tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING; } static const struct component_ops tas2781_hda_comp_ops = { @@ -628,21 +665,21 @@ static const struct component_ops tas2781_hda_comp_ops = { static void tas2781_hda_remove(struct device *dev) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); - pm_runtime_get_sync(tas_priv->dev); - pm_runtime_disable(tas_priv->dev); + pm_runtime_get_sync(tas_hda->dev); + pm_runtime_disable(tas_hda->dev); - component_del(tas_priv->dev, &tas2781_hda_comp_ops); + component_del(tas_hda->dev, &tas2781_hda_comp_ops); - pm_runtime_put_noidle(tas_priv->dev); + pm_runtime_put_noidle(tas_hda->dev); - tasdevice_remove(tas_priv); + tasdevice_remove(tas_hda->priv); } static int tas2781_hda_i2c_probe(struct i2c_client *clt) { - struct tasdevice_priv *tas_priv; + struct tas2781_hda *tas_hda; const char *device_name; int ret; @@ -651,35 +688,42 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) else return -ENODEV; - tas_priv = tasdevice_kzalloc(clt); - if (!tas_priv) + tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL); + if (!tas_hda) return -ENOMEM; - tas_priv->irq_info.irq = clt->irq; - ret = tas2781_read_acpi(tas_priv, device_name); + dev_set_drvdata(&clt->dev, tas_hda); + tas_hda->dev = &clt->dev; + + tas_hda->priv = tasdevice_kzalloc(clt); + if (!tas_hda->priv) + return -ENOMEM; + + tas_hda->priv->irq_info.irq = clt->irq; + ret = tas2781_read_acpi(tas_hda->priv, device_name); if (ret) - return dev_err_probe(tas_priv->dev, ret, + return dev_err_probe(tas_hda->dev, ret, "Platform not supported\n"); - ret = tasdevice_init(tas_priv); + ret = tasdevice_init(tas_hda->priv); if (ret) goto err; - pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000); - pm_runtime_use_autosuspend(tas_priv->dev); - pm_runtime_mark_last_busy(tas_priv->dev); - pm_runtime_set_active(tas_priv->dev); - pm_runtime_get_noresume(tas_priv->dev); - pm_runtime_enable(tas_priv->dev); + pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000); + pm_runtime_use_autosuspend(tas_hda->dev); + pm_runtime_mark_last_busy(tas_hda->dev); + pm_runtime_set_active(tas_hda->dev); + pm_runtime_get_noresume(tas_hda->dev); + pm_runtime_enable(tas_hda->dev); - pm_runtime_put_autosuspend(tas_priv->dev); + pm_runtime_put_autosuspend(tas_hda->dev); - tas2781_reset(tas_priv); + tas2781_reset(tas_hda->priv); - ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops); + ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops); if (ret) { - dev_err(tas_priv->dev, "Register component failed: %d\n", ret); - pm_runtime_disable(tas_priv->dev); + dev_err(tas_hda->dev, "Register component failed: %d\n", ret); + pm_runtime_disable(tas_hda->dev); } err: @@ -695,81 +739,65 @@ static void tas2781_hda_i2c_remove(struct i2c_client *clt) static int tas2781_runtime_suspend(struct device *dev) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); int i; - dev_dbg(tas_priv->dev, "Runtime Suspend\n"); + dev_dbg(tas_hda->dev, "Runtime Suspend\n"); - mutex_lock(&tas_priv->codec_lock); + mutex_lock(&tas_hda->priv->codec_lock); - if (tas_priv->playback_started) { - tasdevice_tuning_switch(tas_priv, 1); - tas_priv->playback_started = false; + if (tas_hda->priv->playback_started) { + tasdevice_tuning_switch(tas_hda->priv, 1); + tas_hda->priv->playback_started = false; } - for (i = 0; i < tas_priv->ndev; i++) { - tas_priv->tasdevice[i].cur_book = -1; - tas_priv->tasdevice[i].cur_prog = -1; - tas_priv->tasdevice[i].cur_conf = -1; + for (i = 0; i < tas_hda->priv->ndev; i++) { + tas_hda->priv->tasdevice[i].cur_book = -1; + tas_hda->priv->tasdevice[i].cur_prog = -1; + tas_hda->priv->tasdevice[i].cur_conf = -1; } - regcache_cache_only(tas_priv->regmap, true); - regcache_mark_dirty(tas_priv->regmap); - - mutex_unlock(&tas_priv->codec_lock); + mutex_unlock(&tas_hda->priv->codec_lock); return 0; } static int tas2781_runtime_resume(struct device *dev) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); unsigned long calib_data_sz = - tas_priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE; - int ret; - - dev_dbg(tas_priv->dev, "Runtime Resume\n"); + tas_hda->priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE; - mutex_lock(&tas_priv->codec_lock); + dev_dbg(tas_hda->dev, "Runtime Resume\n"); - regcache_cache_only(tas_priv->regmap, false); - ret = regcache_sync(tas_priv->regmap); - if (ret) { - dev_err(tas_priv->dev, - "Failed to restore register cache: %d\n", ret); - goto out; - } + mutex_lock(&tas_hda->priv->codec_lock); - tasdevice_prmg_load(tas_priv, tas_priv->cur_prog); + tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); /* If calibrated data occurs error, dsp will still works with default * calibrated data inside algo. */ - if (tas_priv->cali_data.total_sz > calib_data_sz) - tas2781_apply_calib(tas_priv); + if (tas_hda->priv->cali_data.total_sz > calib_data_sz) + tas2781_apply_calib(tas_hda->priv); -out: - mutex_unlock(&tas_priv->codec_lock); + mutex_unlock(&tas_hda->priv->codec_lock); - return ret; + return 0; } static int tas2781_system_suspend(struct device *dev) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); int ret; - dev_dbg(tas_priv->dev, "System Suspend\n"); + dev_dbg(tas_hda->priv->dev, "System Suspend\n"); ret = pm_runtime_force_suspend(dev); if (ret) return ret; /* Shutdown chip before system suspend */ - regcache_cache_only(tas_priv->regmap, false); - tasdevice_tuning_switch(tas_priv, 1); - regcache_cache_only(tas_priv->regmap, true); - regcache_mark_dirty(tas_priv->regmap); + tasdevice_tuning_switch(tas_hda->priv, 1); /* * Reset GPIO may be shared, so cannot reset here. @@ -780,33 +808,33 @@ static int tas2781_system_suspend(struct device *dev) static int tas2781_system_resume(struct device *dev) { - struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); unsigned long calib_data_sz = - tas_priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE; + tas_hda->priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE; int i, ret; - dev_dbg(tas_priv->dev, "System Resume\n"); + dev_info(tas_hda->priv->dev, "System Resume\n"); ret = pm_runtime_force_resume(dev); if (ret) return ret; - mutex_lock(&tas_priv->codec_lock); + mutex_lock(&tas_hda->priv->codec_lock); - for (i = 0; i < tas_priv->ndev; i++) { - tas_priv->tasdevice[i].cur_book = -1; - tas_priv->tasdevice[i].cur_prog = -1; - tas_priv->tasdevice[i].cur_conf = -1; + for (i = 0; i < tas_hda->priv->ndev; i++) { + tas_hda->priv->tasdevice[i].cur_book = -1; + tas_hda->priv->tasdevice[i].cur_prog = -1; + tas_hda->priv->tasdevice[i].cur_conf = -1; } - tas2781_reset(tas_priv); - tasdevice_prmg_load(tas_priv, tas_priv->cur_prog); + tas2781_reset(tas_hda->priv); + tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); /* If calibrated data occurs error, dsp will still work with default * calibrated data inside algo. */ - if (tas_priv->cali_data.total_sz > calib_data_sz) - tas2781_apply_calib(tas_priv); - mutex_unlock(&tas_priv->codec_lock); + if (tas_hda->priv->cali_data.total_sz > calib_data_sz) + tas2781_apply_calib(tas_hda->priv); + mutex_unlock(&tas_hda->priv->codec_lock); return 0; } diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c index 77e0f8750f37..bc2af1ed0fe9 100644 --- a/sound/soc/codecs/cs35l45-i2c.c +++ b/sound/soc/codecs/cs35l45-i2c.c @@ -62,7 +62,7 @@ static struct i2c_driver cs35l45_i2c_driver = { .driver = { .name = "cs35l45", .of_match_table = cs35l45_of_match, - .pm = &cs35l45_pm_ops, + .pm = pm_ptr(&cs35l45_pm_ops), }, .id_table = cs35l45_id_i2c, .probe = cs35l45_i2c_probe, diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c index 5efb77530cc3..39e203a5f060 100644 --- a/sound/soc/codecs/cs35l45-spi.c +++ b/sound/soc/codecs/cs35l45-spi.c @@ -64,7 +64,7 @@ static struct spi_driver cs35l45_spi_driver = { .driver = { .name = "cs35l45", .of_match_table = cs35l45_of_match, - .pm = &cs35l45_pm_ops, + .pm = pm_ptr(&cs35l45_pm_ops), }, .id_table = cs35l45_id_spi, .probe = cs35l45_spi_probe, diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c index b68853e42fd1..44c221745c3b 100644 --- a/sound/soc/codecs/cs35l45.c +++ b/sound/soc/codecs/cs35l45.c @@ -947,6 +947,8 @@ static int cs35l45_enter_hibernate(struct cs35l45_private *cs35l45) cs35l45_setup_hibernate(cs35l45); + regmap_set_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2, CS35L45_DSP_VIRT2_MBOX_MASK); + // Don't wait for ACK since bus activity would wake the device regmap_write(cs35l45->regmap, CS35L45_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE); @@ -967,6 +969,8 @@ static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45) CSPL_MBOX_CMD_OUT_OF_HIBERNATE); if (!ret) { dev_dbg(cs35l45->dev, "Wake success at cycle: %d\n", j); + regmap_clear_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2, + CS35L45_DSP_VIRT2_MBOX_MASK); return 0; } usleep_range(100, 200); @@ -982,7 +986,7 @@ static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45) return -ETIMEDOUT; } -static int __maybe_unused cs35l45_runtime_suspend(struct device *dev) +static int cs35l45_runtime_suspend(struct device *dev) { struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); @@ -999,7 +1003,7 @@ static int __maybe_unused cs35l45_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused cs35l45_runtime_resume(struct device *dev) +static int cs35l45_runtime_resume(struct device *dev) { struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); int ret; @@ -1026,6 +1030,46 @@ static int __maybe_unused cs35l45_runtime_resume(struct device *dev) return ret; } +static int cs35l45_sys_suspend(struct device *dev) +{ + struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); + + dev_dbg(cs35l45->dev, "System suspend, disabling IRQ\n"); + disable_irq(cs35l45->irq); + + return 0; +} + +static int cs35l45_sys_suspend_noirq(struct device *dev) +{ + struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); + + dev_dbg(cs35l45->dev, "Late system suspend, reenabling IRQ\n"); + enable_irq(cs35l45->irq); + + return 0; +} + +static int cs35l45_sys_resume_noirq(struct device *dev) +{ + struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); + + dev_dbg(cs35l45->dev, "Early system resume, disabling IRQ\n"); + disable_irq(cs35l45->irq); + + return 0; +} + +static int cs35l45_sys_resume(struct device *dev) +{ + struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); + + dev_dbg(cs35l45->dev, "System resume, reenabling IRQ\n"); + enable_irq(cs35l45->irq); + + return 0; +} + static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45) { struct device_node *node = cs35l45->dev->of_node; @@ -1466,10 +1510,12 @@ void cs35l45_remove(struct cs35l45_private *cs35l45) } EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45); -const struct dev_pm_ops cs35l45_pm_ops = { - SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL) +EXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops) = { + RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL) + + SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend, cs35l45_sys_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend_noirq, cs35l45_sys_resume_noirq) }; -EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45); MODULE_DESCRIPTION("ASoC CS35L45 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c index 73454de068cf..54a3ea606443 100644 --- a/sound/soc/codecs/cs42l43-jack.c +++ b/sound/soc/codecs/cs42l43-jack.c @@ -237,7 +237,7 @@ error: return ret; } -static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool force_high) +static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect) { struct cs42l43 *cs42l43 = priv->core; unsigned int val = 0x3 << CS42L43_HSBIAS_MODE_SHIFT; @@ -247,16 +247,17 @@ static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool force_high) regmap_update_bits(cs42l43->regmap, CS42L43_HS2, CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK); - if (!force_high && priv->bias_low) - val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT; - - if (priv->bias_sense_ua) { - regmap_update_bits(cs42l43->regmap, - CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, - CS42L43_HSBIAS_SENSE_EN_MASK | - CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, - CS42L43_HSBIAS_SENSE_EN_MASK | - CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); + if (!type_detect) { + if (priv->bias_low) + val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT; + + if (priv->bias_sense_ua) + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); } regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 20da1eaa4f1c..0938671700c6 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -850,8 +850,9 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, unsigned int jack_status) { - if (hcp->jack && jack_status != hcp->jack_status) { - snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT); + if (jack_status != hcp->jack_status) { + if (hcp->jack) + snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT); hcp->jack_status = jack_status; } } @@ -880,6 +881,13 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component, if (hcp->hcd.ops->hook_plugged_cb) { hcp->jack = jack; + + /* + * Report the initial jack status which may have been provided + * by the parent hdmi driver while the hpd hook was registered. + */ + snd_soc_jack_report(jack, hcp->jack_status, SND_JACK_LINEOUT); + return 0; } diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index ffb26e4a7e2f..00e35169ae49 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -39,7 +39,7 @@ static const struct regmap_range_cfg tasdevice_ranges[] = { static const struct regmap_config tasdevice_regmap = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_NONE, .ranges = tasdevice_ranges, .num_ranges = ARRAY_SIZE(tasdevice_ranges), .max_register = 256 * 128, @@ -316,8 +316,6 @@ int tasdevice_init(struct tasdevice_priv *tas_priv) tas_priv->tasdevice[i].cur_conf = -1; } - dev_set_drvdata(tas_priv->dev, tas_priv); - mutex_init(&tas_priv->codec_lock); out: diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 4efe95b60aaa..5c09e441a936 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -2189,11 +2189,11 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no, goto out; } - conf = &(tas_fmw->configs[cfg_no]); for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) { if (cfg_info[rca_conf_no]->active_dev & (1 << i)) { - if (tas_priv->tasdevice[i].cur_prog != prm_no - || tas_priv->force_fwload_status) { + if (prm_no >= 0 + && (tas_priv->tasdevice[i].cur_prog != prm_no + || tas_priv->force_fwload_status)) { tas_priv->tasdevice[i].cur_conf = -1; tas_priv->tasdevice[i].is_loading = true; prog_status++; @@ -2228,7 +2228,8 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no, } for (i = 0, status = 0; i < tas_priv->ndev; i++) { - if (tas_priv->tasdevice[i].cur_conf != cfg_no + if (cfg_no >= 0 + && tas_priv->tasdevice[i].cur_conf != cfg_no && (cfg_info[rca_conf_no]->active_dev & (1 << i)) && (tas_priv->tasdevice[i].is_loaderr == false)) { status++; @@ -2238,6 +2239,7 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no, } if (status) { + conf = &(tas_fmw->configs[cfg_no]); status = 0; tasdevice_load_data(tas_priv, &(conf->dev_data)); for (i = 0; i < tas_priv->ndev; i++) { @@ -2281,7 +2283,7 @@ int tasdevice_prmg_load(void *context, int prm_no) } for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) { - if (tas_priv->tasdevice[i].cur_prog != prm_no) { + if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) { tas_priv->tasdevice[i].cur_conf = -1; tas_priv->tasdevice[i].is_loading = true; prog_status++; @@ -2326,7 +2328,7 @@ int tasdevice_prmg_calibdata_load(void *context, int prm_no) } for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) { - if (tas_priv->tasdevice[i].cur_prog != prm_no) { + if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) { tas_priv->tasdevice[i].cur_conf = -1; tas_priv->tasdevice[i].is_loading = true; prog_status++; diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 55cd5e3c23a5..917b1c15f71d 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -689,6 +689,8 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c) if (!tas_priv) return -ENOMEM; + dev_set_drvdata(&i2c->dev, tas_priv); + if (ACPI_HANDLE(&i2c->dev)) { acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table, &i2c->dev); diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 5c5c04ce9db7..00852f174a69 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -238,7 +238,7 @@ static int fsl_rpmsg_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, &fsl_rpmsg_dai, 1); if (ret) - return ret; + goto err_pm_disable; rpmsg->card_pdev = platform_device_register_data(&pdev->dev, "imx-audio-rpmsg", @@ -248,16 +248,22 @@ static int fsl_rpmsg_probe(struct platform_device *pdev) if (IS_ERR(rpmsg->card_pdev)) { dev_err(&pdev->dev, "failed to register rpmsg card\n"); ret = PTR_ERR(rpmsg->card_pdev); - return ret; + goto err_pm_disable; } return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + return ret; } static void fsl_rpmsg_remove(struct platform_device *pdev) { struct fsl_rpmsg *rpmsg = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); + if (rpmsg->card_pdev) platform_device_unregister(rpmsg->card_pdev); } diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 32bbe5056a63..546bd4e333b5 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -714,6 +714,9 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int ofs = sai->soc_data->reg_offset; + /* Clear xMR to avoid channel swap with mclk_with_tere enabled case */ + regmap_write(sai->regmap, FSL_SAI_xMR(tx), 0); + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), FSL_SAI_CR3_TRCE_MASK, 0); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ed14d9e4aa53..42466b4b1ca4 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -83,6 +83,7 @@ enum { #define BYT_RT5640_HSMIC2_ON_IN1 BIT(27) #define BYT_RT5640_JD_HP_ELITEP_1000G2 BIT(28) #define BYT_RT5640_USE_AMCR0F28 BIT(29) +#define BYT_RT5640_SWAPPED_SPEAKERS BIT(30) #define BYTCR_INPUT_DEFAULTS \ (BYT_RT5640_IN3_MAP | \ @@ -157,6 +158,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk MONO_SPEAKER enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) dev_info(dev, "quirk NO_SPEAKERS enabled\n"); + if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS) + dev_info(dev, "quirk SWAPPED_SPEAKERS enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) dev_info(dev, "quirk LINEOUT enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2) @@ -894,6 +897,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + /* Medion Lifetab S10346 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are much too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "10/22/2015"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_SWAPPED_SPEAKERS | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Mele PCG03 Mini PC */ .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"), @@ -1619,11 +1635,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) const char *platform_name; struct acpi_device *adev; struct device *codec_dev; + const char *cfg_spk; bool sof_parent; int ret_val = 0; int dai_index = 0; - int i, cfg_spk; - int aif; + int i, aif; is_bytcr = false; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -1783,13 +1799,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) { - cfg_spk = 0; + cfg_spk = "0"; spk_type = "none"; } else if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { - cfg_spk = 1; + cfg_spk = "1"; spk_type = "mono"; + } else if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS) { + cfg_spk = "swapped"; + spk_type = "swapped"; } else { - cfg_spk = 2; + cfg_spk = "2"; spk_type = "stereo"; } @@ -1804,7 +1823,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) headset2_string = " cfg-hs2:in1"; snprintf(byt_rt5640_components, sizeof(byt_rt5640_components), - "cfg-spk:%d cfg-mic:%s aif:%d%s%s", cfg_spk, + "cfg-spk:%s cfg-mic:%s aif:%d%s%s", cfg_spk, map_name[BYT_RT5640_MAP(byt_rt5640_quirk)], aif, lineout_string, headset2_string); byt_rt5640_card.components = byt_rt5640_components; 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 301b8142d554..9008b6768205 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -306,13 +306,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = { .adr = 0x00013701FA355601ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, - .name_prefix = "cs35l56-8" + .name_prefix = "AMP8" }, { .adr = 0x00013601FA355601ull, .num_endpoints = 1, .endpoints = &spk_3_endpoint, - .name_prefix = "cs35l56-7" + .name_prefix = "AMP7" } }; @@ -321,13 +321,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_adr[] = { .adr = 0x00023301FA355601ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, - .name_prefix = "cs35l56-1" + .name_prefix = "AMP1" }, { .adr = 0x00023201FA355601ull, .num_endpoints = 1, .endpoints = &spk_2_endpoint, - .name_prefix = "cs35l56-2" + .name_prefix = "AMP2" } }; diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c index 85ae3f76d951..ad6d4b5cf697 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c @@ -499,7 +499,7 @@ static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP, - 0, 0, 0, + AFE_AUD_PAD_TOP, RG_RX_FIFO_ON_SFT, 0, mtk_adda_pad_top_event, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG, diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index 6c4503766fdc..531bb8707a3e 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -71,6 +71,9 @@ static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, reg; + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); regmap_field_read(priv->field_dat_sel, ®); @@ -101,7 +104,7 @@ static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol, snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); - return 0; + return 1; } static SOC_ENUM_SINGLE_DECL(g12a_toacodec_mux_enum, TOACODEC_CTRL0, diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index f7ef9aa1eed8..b92434125fac 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -45,6 +45,9 @@ static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, changed; + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); changed = snd_soc_component_test_bits(component, e->reg, CTRL0_I2S_DAT_SEL, @@ -93,6 +96,9 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, changed; + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); changed = snd_soc_component_test_bits(component, TOHDMITX_CTRL0, CTRL0_SPDIF_SEL, @@ -112,7 +118,7 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); - return 0; + return 1; } static SOC_ENUM_SINGLE_DECL(g12a_tohdmitx_spdif_mux_enum, TOHDMITX_CTRL0, diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 28ecbebb4b84..9f84b0d287a5 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -54,8 +54,16 @@ static int request_codec_module(struct hda_codec *codec) static int hda_codec_load_module(struct hda_codec *codec) { - int ret = request_codec_module(codec); + int ret; + + ret = snd_hdac_device_register(&codec->core); + if (ret) { + dev_err(&codec->core.dev, "failed to register hdac device\n"); + put_device(&codec->core.dev); + return ret; + } + ret = request_codec_module(codec); if (ret <= 0) { codec->probe_id = HDA_CODEC_ID_GENERIC; ret = request_codec_module(codec); @@ -116,7 +124,6 @@ EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC); static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, int type) { struct hda_codec *codec; - int ret; codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr); if (IS_ERR(codec)) { @@ -126,13 +133,6 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i codec->core.type = type; - ret = snd_hdac_device_register(&codec->core); - if (ret) { - dev_err(bus->dev, "failed to register hdac device\n"); - put_device(&codec->core.dev); - return ERR_PTR(ret); - } - return codec; } diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index e0d88e7aa8ca..b69fa788b16f 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -597,9 +597,6 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { static struct snd_sof_of_mach sof_mt8186_machs[] = { { - .compatible = "google,steelix", - .sof_tplg_filename = "sof-mt8186-google-steelix.tplg" - }, { .compatible = "mediatek,mt8186", .sof_tplg_filename = "sof-mt8186.tplg", }, diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index f7c57a2c3028..33a3d1161885 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -1966,7 +1966,7 @@ static int scarlett2_usb_get_meter_levels(struct usb_mixer_interface *mixer, __le16 num_meters; __le32 magic; } __packed req; - u32 resp[SCARLETT2_MAX_METERS]; + __le32 resp[SCARLETT2_MAX_METERS]; int i, err; req.pad = 0; @@ -1979,7 +1979,7 @@ static int scarlett2_usb_get_meter_levels(struct usb_mixer_interface *mixer, /* copy, convert to u16 */ for (i = 0; i < num_meters; i++) - levels[i] = resp[i]; + levels[i] = le32_to_cpu(resp[i]); return 0; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index ab2b938502eb..07cc6a201579 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1387,7 +1387,7 @@ free_buf: static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev) { - msleep(2000); + msleep(4000); return 0; } @@ -1630,7 +1630,7 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev, unsigned int id) { switch (id) { - case USB_ID(0x07fd, 0x0008): /* MOTU M Series */ + case USB_ID(0x07fd, 0x0008): /* MOTU M Series, 1st hardware version */ return snd_usb_motu_m_series_boot_quirk(dev); } |