ASoC: Fixes for v6.8

A relatively large set of fixes and quirk additions here but they're all
 driver specific, people seem to be back into the swing of things after
 the holidays.  This is all driver specific and much of it fairly minor.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmXOEbkACgkQJNaLcl1U
 h9BzgAf/abgoQLJCpvLzEppfOvS3+uXjxZzOeRXcZJXa8a9RIzYx/GQoipsgL8n1
 1MpdbKKR63xeGiohASp0nUN6gVgviGZvutgI/+yISxlUktUn/g7P/vz2Zlq+7KMw
 T2/Vn3bYFFO2MXUZKaNdfizUVq67zXSNCT/+AAr6AYG//yGy5EfX2BO82vbwZm3e
 Yh/fQ3pMrhSI+el9gtSaeXrVs/KOyRDhJamVlE6q78Xm90z6wJ8wov4QTGEn5QjN
 8C3axogE4ZsXUsiq7o3G8Tn+YVHIZ10wGHlnSg3bIatn8CEA3kTi/QxboAVDZLeH
 0kyy98WPxtzJRYjNsz4YoT8t+He08A==
 =0kWz
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v6.8-rc4' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v6.8

A relatively large set of fixes and quirk additions here but they're all
driver specific, people seem to be back into the swing of things after
the holidays.  This is all driver specific and much of it fairly minor.
This commit is contained in:
Takashi Iwai 2024-02-15 15:00:31 +01:00
commit 3db9d4b395
29 changed files with 388 additions and 174 deletions

View file

@ -7,7 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Google SC7280-Herobrine ASoC sound card driver
maintainers:
- Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
- Judy Hsiao <judyhsiao@chromium.org>
description:

View file

@ -142,6 +142,7 @@ struct tasdevice_priv {
void tas2781_reset(struct tasdevice_priv *tas_dev);
int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
struct module *module,
void (*cont)(const struct firmware *fw, void *context));
struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c);
int tasdevice_init(struct tasdevice_priv *tas_priv);

View file

@ -710,7 +710,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_hda->priv, codec, tasdev_fw_ready);
ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready);
if (!ret)
comps->playback_hook = tas2781_hda_playback_hook;

View file

@ -234,6 +234,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "82UG"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "82UU"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
@ -248,6 +255,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "82YM"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "83AS"),
}
},
{
.driver_data = &acp6x_card,
.matches = {

View file

@ -51,7 +51,6 @@ static const struct reg_default cs35l56_reg_defaults[] = {
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
{ CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 },
{ CS35L56_IRQ1_CFG, 0x00000000 },
{ CS35L56_IRQ1_MASK_1, 0x83ffffff },
{ CS35L56_IRQ1_MASK_2, 0xffff7fff },
{ CS35L56_IRQ1_MASK_4, 0xe0ffffff },

View file

@ -5,6 +5,7 @@
// Copyright (C) 2023 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
#include <linux/acpi.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@ -15,6 +16,7 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@ -68,6 +70,66 @@ static const char * const cs35l56_asp1_mux_control_names[] = {
"ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source"
};
static int cs35l56_sync_asp1_mixer_widgets_with_firmware(struct cs35l56_private *cs35l56)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
const char *prefix = cs35l56->component->name_prefix;
char full_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
const char *name;
struct snd_kcontrol *kcontrol;
struct soc_enum *e;
unsigned int val[4];
int i, item, ret;
if (cs35l56->asp1_mixer_widgets_initialized)
return 0;
/*
* Resume so we can read the registers from silicon if the regmap
* cache has not yet been populated.
*/
ret = pm_runtime_resume_and_get(cs35l56->base.dev);
if (ret < 0)
return ret;
/* Wait for firmware download and reboot */
cs35l56_wait_dsp_ready(cs35l56);
ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT,
val, ARRAY_SIZE(val));
pm_runtime_mark_last_busy(cs35l56->base.dev);
pm_runtime_put_autosuspend(cs35l56->base.dev);
if (ret) {
dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) {
name = cs35l56_asp1_mux_control_names[i];
if (prefix) {
snprintf(full_name, sizeof(full_name), "%s %s", prefix, name);
name = full_name;
}
kcontrol = snd_soc_card_get_kcontrol(dapm->card, name);
if (!kcontrol) {
dev_warn(cs35l56->base.dev, "Could not find control %s\n", name);
continue;
}
e = (struct soc_enum *)kcontrol->private_value;
item = snd_soc_enum_val_to_item(e, val[i] & CS35L56_ASP_TXn_SRC_MASK);
snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
}
cs35l56->asp1_mixer_widgets_initialized = true;
return 0;
}
static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@ -78,9 +140,9 @@ static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
unsigned int addr, val;
int ret;
/* Wait for mux to be initialized */
cs35l56_wait_dsp_ready(cs35l56);
flush_work(&cs35l56->mux_init_work);
ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
if (ret)
return ret;
addr = cs35l56_asp1_mixer_regs[index];
ret = regmap_read(cs35l56->base.regmap, addr, &val);
@ -106,16 +168,16 @@ static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
bool changed;
int ret;
/* Wait for mux to be initialized */
cs35l56_wait_dsp_ready(cs35l56);
flush_work(&cs35l56->mux_init_work);
ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
if (ret)
return ret;
addr = cs35l56_asp1_mixer_regs[index];
val = snd_soc_enum_item_to_val(e, item);
ret = regmap_update_bits_check(cs35l56->base.regmap, addr,
CS35L56_ASP_TXn_SRC_MASK, val, &changed);
if (!ret)
if (ret)
return ret;
if (changed)
@ -124,70 +186,6 @@ static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
return changed;
}
static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l56)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
const char *prefix = cs35l56->component->name_prefix;
char full_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
const char *name;
struct snd_kcontrol *kcontrol;
struct soc_enum *e;
unsigned int val[4];
int i, item, ret;
/*
* Resume so we can read the registers from silicon if the regmap
* cache has not yet been populated.
*/
ret = pm_runtime_resume_and_get(cs35l56->base.dev);
if (ret < 0)
return;
ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT,
val, ARRAY_SIZE(val));
pm_runtime_mark_last_busy(cs35l56->base.dev);
pm_runtime_put_autosuspend(cs35l56->base.dev);
if (ret) {
dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret);
return;
}
snd_soc_card_mutex_lock(dapm->card);
WARN_ON(!dapm->card->instantiated);
for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) {
name = cs35l56_asp1_mux_control_names[i];
if (prefix) {
snprintf(full_name, sizeof(full_name), "%s %s", prefix, name);
name = full_name;
}
kcontrol = snd_soc_card_get_kcontrol(dapm->card, name);
if (!kcontrol) {
dev_warn(cs35l56->base.dev, "Could not find control %s\n", name);
continue;
}
e = (struct soc_enum *)kcontrol->private_value;
item = snd_soc_enum_val_to_item(e, val[i] & CS35L56_ASP_TXn_SRC_MASK);
snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
}
snd_soc_card_mutex_unlock(dapm->card);
}
static void cs35l56_mux_init_work(struct work_struct *work)
{
struct cs35l56_private *cs35l56 = container_of(work,
struct cs35l56_private,
mux_init_work);
cs35l56_mark_asp1_mixer_widgets_dirty(cs35l56);
}
static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
static const struct snd_kcontrol_new cs35l56_controls[] = {
@ -936,14 +934,6 @@ static void cs35l56_dsp_work(struct work_struct *work)
else
cs35l56_patch(cs35l56, firmware_missing);
/*
* Set starting value of ASP1 mux widgets. Updating a mux takes
* the DAPM mutex. Post this to a separate job so that DAPM
* power-up can wait for dsp_work to complete without deadlocking
* on the DAPM mutex.
*/
queue_work(cs35l56->dsp_wq, &cs35l56->mux_init_work);
err:
pm_runtime_mark_last_busy(cs35l56->base.dev);
pm_runtime_put_autosuspend(cs35l56->base.dev);
@ -989,6 +979,13 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);
/*
* The widgets for the ASP1TX mixer can't be initialized
* until the firmware has been downloaded and rebooted.
*/
regcache_drop_region(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX4_INPUT);
cs35l56->asp1_mixer_widgets_initialized = false;
queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
return 0;
@ -999,7 +996,6 @@ static void cs35l56_component_remove(struct snd_soc_component *component)
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
cancel_work_sync(&cs35l56->dsp_work);
cancel_work_sync(&cs35l56->mux_init_work);
if (cs35l56->dsp.cs_dsp.booted)
wm_adsp_power_down(&cs35l56->dsp);
@ -1070,10 +1066,8 @@ int cs35l56_system_suspend(struct device *dev)
dev_dbg(dev, "system_suspend\n");
if (cs35l56->component) {
if (cs35l56->component)
flush_work(&cs35l56->dsp_work);
cancel_work_sync(&cs35l56->mux_init_work);
}
/*
* The interrupt line is normally shared, but after we start suspending
@ -1224,7 +1218,6 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
return -ENOMEM;
INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work);
INIT_WORK(&cs35l56->mux_init_work, cs35l56_mux_init_work);
dsp = &cs35l56->dsp;
cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
@ -1269,6 +1262,94 @@ static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
return 0;
}
/*
* Some SoundWire laptops have a spk-id-gpios property but it points to
* the wrong ACPI Device node so can't be used to get the GPIO. Try to
* find the SDCA node containing the GpioIo resource and add a GPIO
* mapping to it.
*/
static const struct acpi_gpio_params cs35l56_af01_first_gpio = { 0, 0, false };
static const struct acpi_gpio_mapping cs35l56_af01_spkid_gpios_mapping[] = {
{ "spk-id-gpios", &cs35l56_af01_first_gpio, 1 },
{ }
};
static void cs35l56_acpi_dev_release_driver_gpios(void *adev)
{
acpi_dev_remove_driver_gpios(adev);
}
static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l56)
{
struct fwnode_handle *af01_fwnode;
const union acpi_object *obj;
struct gpio_desc *desc;
int ret;
/* Find the SDCA node containing the GpioIo */
af01_fwnode = device_get_named_child_node(cs35l56->base.dev, "AF01");
if (!af01_fwnode) {
dev_dbg(cs35l56->base.dev, "No AF01 node\n");
return -ENOENT;
}
ret = acpi_dev_get_property(ACPI_COMPANION(cs35l56->base.dev),
"spk-id-gpios", ACPI_TYPE_PACKAGE, &obj);
if (ret) {
dev_dbg(cs35l56->base.dev, "Could not get spk-id-gpios package: %d\n", ret);
return -ENOENT;
}
/* The broken properties we can handle are a 4-element package (one GPIO) */
if (obj->package.count != 4) {
dev_warn(cs35l56->base.dev, "Unexpected spk-id element count %d\n",
obj->package.count);
return -ENOENT;
}
/* Add a GPIO mapping if it doesn't already have one */
if (!fwnode_property_present(af01_fwnode, "spk-id-gpios")) {
struct acpi_device *adev = to_acpi_device_node(af01_fwnode);
/*
* Can't use devm_acpi_dev_add_driver_gpios() because the
* mapping isn't being added to the node pointed to by
* ACPI_COMPANION().
*/
ret = acpi_dev_add_driver_gpios(adev, cs35l56_af01_spkid_gpios_mapping);
if (ret) {
return dev_err_probe(cs35l56->base.dev, ret,
"Failed to add gpio mapping to AF01\n");
}
ret = devm_add_action_or_reset(cs35l56->base.dev,
cs35l56_acpi_dev_release_driver_gpios,
adev);
if (ret)
return ret;
dev_dbg(cs35l56->base.dev, "Added spk-id-gpios mapping to AF01\n");
}
desc = fwnode_gpiod_get_index(af01_fwnode, "spk-id", 0, GPIOD_IN, NULL);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
return dev_err_probe(cs35l56->base.dev, ret, "Get GPIO from AF01 failed\n");
}
ret = gpiod_get_value_cansleep(desc);
gpiod_put(desc);
if (ret < 0) {
dev_err_probe(cs35l56->base.dev, ret, "Error reading spk-id GPIO\n");
return ret;
}
dev_info(cs35l56->base.dev, "Got spk-id from AF01\n");
return ret;
}
int cs35l56_common_probe(struct cs35l56_private *cs35l56)
{
int ret;
@ -1313,6 +1394,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
}
ret = cs35l56_get_speaker_id(&cs35l56->base);
if (ACPI_COMPANION(cs35l56->base.dev) && cs35l56->sdw_peripheral && (ret == -ENOENT))
ret = cs35l56_try_get_broken_sdca_spkid_gpio(cs35l56);
if ((ret < 0) && (ret != -ENOENT))
goto err;

View file

@ -34,7 +34,6 @@ struct cs35l56_private {
struct wm_adsp dsp; /* must be first member */
struct cs35l56_base base;
struct work_struct dsp_work;
struct work_struct mux_init_work;
struct workqueue_struct *dsp_wq;
struct snd_soc_component *component;
struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES];
@ -52,6 +51,7 @@ struct cs35l56_private {
u8 asp_slot_count;
bool tdm_mode;
bool sysclk_set;
bool asp1_mixer_widgets_initialized;
u8 old_sdw_clock_scale;
};

View file

@ -2257,7 +2257,10 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(priv->dev);
pm_runtime_set_active(priv->dev);
pm_runtime_get_noresume(priv->dev);
devm_pm_runtime_enable(priv->dev);
ret = devm_pm_runtime_enable(priv->dev);
if (ret)
goto err_pm;
for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) {
ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name,
@ -2333,8 +2336,47 @@ static int cs42l43_codec_runtime_resume(struct device *dev)
return 0;
}
static DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL,
cs42l43_codec_runtime_resume, NULL);
static int cs42l43_codec_suspend(struct device *dev)
{
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
disable_irq(cs42l43->irq);
return 0;
}
static int cs42l43_codec_suspend_noirq(struct device *dev)
{
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
enable_irq(cs42l43->irq);
return 0;
}
static int cs42l43_codec_resume(struct device *dev)
{
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
enable_irq(cs42l43->irq);
return 0;
}
static int cs42l43_codec_resume_noirq(struct device *dev)
{
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
disable_irq(cs42l43->irq);
return 0;
}
static const struct dev_pm_ops cs42l43_codec_pm_ops = {
SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume)
NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend_noirq, cs42l43_codec_resume_noirq)
RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL)
};
static const struct platform_device_id cs42l43_codec_id_table[] = {
{ "cs42l43-codec", },

View file

@ -3317,6 +3317,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
report, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack,
report, SND_JACK_MICROPHONE);
mutex_unlock(&rt5645->jd_mutex);
return;
case 4:
val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020;
@ -3692,6 +3693,11 @@ static const struct rt5645_platform_data jd_mode3_monospk_platform_data = {
.mono_speaker = true,
};
static const struct rt5645_platform_data jd_mode3_inv_data = {
.jd_mode = 3,
.inv_jd1_1 = true,
};
static const struct rt5645_platform_data jd_mode3_platform_data = {
.jd_mode = 3,
};
@ -3837,6 +3843,16 @@ static const struct dmi_system_id dmi_platform_data[] = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
DMI_EXACT_MATCH(DMI_BOARD_VERSION, "Default string"),
/*
* Above strings are too generic, LattePanda BIOS versions for
* all 4 hw revisions are:
* DF-BI-7-S70CR100-*
* DF-BI-7-S70CR110-*
* DF-BI-7-S70CR200-*
* LP-BS-7-S70CR700-*
* Do a partial match for S70CR to avoid false positive matches.
*/
DMI_MATCH(DMI_BIOS_VERSION, "S70CR"),
},
.driver_data = (void *)&lattepanda_board_platform_data,
},
@ -3871,6 +3887,16 @@ static const struct dmi_system_id dmi_platform_data[] = {
},
.driver_data = (void *)&intel_braswell_platform_data,
},
{
.ident = "Meegopad T08",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
},
.driver_data = (void *)&jd_mode3_inv_data,
},
{ }
};

View file

@ -267,6 +267,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev)
EXPORT_SYMBOL_GPL(tas2781_reset);
int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
struct module *module,
void (*cont)(const struct firmware *fw, void *context))
{
int ret = 0;
@ -280,7 +281,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
tas_priv->dev_name, tas_priv->ndev);
crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
tas_priv->codec = codec;
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
cont);
if (ret)

View file

@ -566,7 +566,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec)
{
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
return tascodec_init(tas_priv, codec, tasdevice_fw_ready);
return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
}
static void tasdevice_deinit(void *context)

View file

@ -477,6 +477,9 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
return 0;
err_i915_init:
pci_free_irq(pci, 0, adev);
pci_free_irq(pci, 0, bus);
pci_free_irq_vectors(pci);
pci_clear_master(pci);
pci_set_drvdata(pci, NULL);
err_acquire_irq:

View file

@ -857,7 +857,7 @@ assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf
}
/* If topology sets value don't overwrite it */
if (cfg->copier.vindex.i2s.instance)
if (cfg->copier.vindex.val)
return;
mach = dev_get_platdata(comp->card->dev);

View file

@ -241,7 +241,8 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) {
if (!strcmp(byt_cht_cx2072x_dais[i].codecs->name,
if (byt_cht_cx2072x_dais[i].codecs->name &&
!strcmp(byt_cht_cx2072x_dais[i].codecs->name,
"i2c-14F10720:00")) {
dai_index = i;
break;

View file

@ -245,7 +245,8 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(dailink); i++) {
if (!strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) {
if (dailink[i].codecs->name &&
!strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) {
dai_index = i;
break;
}

View file

@ -546,7 +546,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) {
if (!strcmp(byt_cht_es8316_dais[i].codecs->name,
if (byt_cht_es8316_dais[i].codecs->name &&
!strcmp(byt_cht_es8316_dais[i].codecs->name,
"i2c-ESSX8316:00")) {
dai_index = i;
break;

View file

@ -1652,7 +1652,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) {
if (!strcmp(byt_rt5640_dais[i].codecs->name,
if (byt_rt5640_dais[i].codecs->name &&
!strcmp(byt_rt5640_dais[i].codecs->name,
"i2c-10EC5640:00")) {
dai_index = i;
break;

View file

@ -910,7 +910,8 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) {
if (!strcmp(byt_rt5651_dais[i].codecs->name,
if (byt_rt5651_dais[i].codecs->name &&
!strcmp(byt_rt5651_dais[i].codecs->name,
"i2c-10EC5651:00")) {
dai_index = i;
break;

View file

@ -605,7 +605,8 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
/* find index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_wm5102_dais); i++) {
if (!strcmp(byt_wm5102_dais[i].codecs->name,
if (byt_wm5102_dais[i].codecs->name &&
!strcmp(byt_wm5102_dais[i].codecs->name,
"wm5102-codec")) {
dai_index = i;
break;

View file

@ -40,7 +40,6 @@ struct cht_acpi_card {
struct cht_mc_private {
struct snd_soc_jack jack;
struct cht_acpi_card *acpi_card;
char codec_name[SND_ACPI_I2C_ID_LEN];
struct clk *mclk;
};
@ -567,14 +566,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
card->dev = &pdev->dev;
sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
/* set correct codec name */
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
if (!strcmp(card->dai_link[i].codecs->name,
if (cht_dailink[i].codecs->name &&
!strcmp(cht_dailink[i].codecs->name,
"i2c-10EC5645:00")) {
card->dai_link[i].codecs->name = drv->codec_name;
dai_index = i;
break;
}
/* fixup codec name based on HID */

View file

@ -466,7 +466,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* find index of codec dai */
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
if (!strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) {
if (cht_dailink[i].codecs->name &&
!strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) {
dai_index = i;
break;
}

View file

@ -123,7 +123,7 @@ static struct snd_pcm_hardware q6apm_dai_hardware_playback = {
.fifo_size = 0,
};
static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv)
static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv)
{
struct q6apm_dai_rtd *prtd = priv;
struct snd_pcm_substream *substream = prtd->substream;
@ -157,7 +157,7 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo
}
static void event_handler_compr(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
void *payload, void *priv)
{
struct q6apm_dai_rtd *prtd = priv;
struct snd_compr_stream *substream = prtd->cstream;
@ -352,7 +352,7 @@ static int q6apm_dai_open(struct snd_soc_component *component,
spin_lock_init(&prtd->lock);
prtd->substream = substream;
prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id);
prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id);
if (IS_ERR(prtd->graph)) {
dev_err(dev, "%s: Could not allocate memory\n", __func__);
ret = PTR_ERR(prtd->graph);
@ -496,7 +496,7 @@ static int q6apm_dai_compr_open(struct snd_soc_component *component,
return -ENOMEM;
prtd->cstream = stream;
prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler_compr, prtd, graph_id);
prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id);
if (IS_ERR(prtd->graph)) {
ret = PTR_ERR(prtd->graph);
kfree(prtd);

View file

@ -188,11 +188,13 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);
if (dsp_ack) {
spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */
acp_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, 0);
/* set the done bit */
acp_dsp_ipc_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
ipc_irq = true;
}

View file

@ -355,21 +355,20 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
unsigned int count = ACP_HW_SEM_RETRY_COUNT;
spin_lock_irq(&sdev->ipc_lock);
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
/* Wait until acquired HW Semaphore lock or timeout */
count--;
if (!count) {
dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
spin_unlock_irq(&sdev->ipc_lock);
return IRQ_NONE;
}
/* Wait until acquired HW Semaphore lock or timeout */
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset) && --count)
;
spin_unlock_irq(&sdev->ipc_lock);
if (!count) {
dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
return IRQ_NONE;
}
sof_ops(sdev)->irq_thread(irq, sdev);
/* Unlock or Release HW Semaphore */
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
spin_unlock_irq(&sdev->ipc_lock);
return IRQ_HANDLED;
};

View file

@ -36,7 +36,7 @@ static const struct sof_dev_desc lnl_desc = {
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/lnl",
},
.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-lnl.ri",

View file

@ -33,18 +33,18 @@ static const struct sof_dev_desc tgl_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/tgl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/tgl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-tgl.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-tgl.ri",
},
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops,
@ -66,18 +66,18 @@ static const struct sof_dev_desc tglh_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/tgl-h",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl-h",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/tgl-h",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl-h",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-tgl-h.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-tgl-h.ri",
},
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops,
@ -98,18 +98,18 @@ static const struct sof_dev_desc ehl_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/ehl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/ehl",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/ehl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/ehl",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-ehl.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-ehl.ri",
},
.nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
.ops = &sof_tgl_ops,
@ -131,18 +131,18 @@ static const struct sof_dev_desc adls_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/adl-s",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-s",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/adl-s",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-s",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-adl-s.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-adl-s.ri",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
@ -164,18 +164,18 @@ static const struct sof_dev_desc adl_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/adl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/adl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-adl.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-adl.ri",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
@ -197,18 +197,18 @@ static const struct sof_dev_desc adl_n_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/adl-n",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-n",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/adl-n",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-n",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-adl-n.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-adl-n.ri",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
@ -230,18 +230,18 @@ static const struct sof_dev_desc rpls_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/rpl-s",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl-s",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/rpl-s",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl-s",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-rpl-s.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-rpl-s.ri",
},
.nocodec_tplg_filename = "sof-rpl-nocodec.tplg",
.ops = &sof_tgl_ops,
@ -263,18 +263,18 @@ static const struct sof_dev_desc rpl_desc = {
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
[SOF_IPC_TYPE_3] = "intel/sof",
[SOF_IPC_TYPE_4] = "intel/avs/rpl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl",
},
.default_lib_path = {
[SOF_IPC_TYPE_4] = "intel/avs-lib/rpl",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl",
},
.default_tplg_path = {
[SOF_IPC_TYPE_3] = "intel/sof-tplg",
[SOF_IPC_TYPE_4] = "intel/avs-tplg",
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
[SOF_IPC_TYPE_3] = "sof-rpl.ri",
[SOF_IPC_TYPE_4] = "dsp_basefw.bin",
[SOF_IPC_TYPE_4] = "sof-rpl.ri",
},
.nocodec_tplg_filename = "sof-rpl-nocodec.tplg",
.ops = &sof_tgl_ops,

View file

@ -2360,6 +2360,44 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
return 0;
}
static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler,
bool *dyn_widgets, bool verify)
{
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
struct snd_sof_widget *swidget;
int ret;
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (swidget->dynamic_pipeline_widget) {
*dyn_widgets = true;
continue;
}
/* Do not free widgets for static pipelines with FW older than SOF2.2 */
if (!verify && !swidget->dynamic_pipeline_widget &&
SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) {
mutex_lock(&swidget->setup_mutex);
swidget->use_count = 0;
mutex_unlock(&swidget->setup_mutex);
if (swidget->spipe)
swidget->spipe->complete = 0;
continue;
}
if (include_scheduler && swidget->id != snd_soc_dapm_scheduler)
continue;
if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler)
continue;
ret = sof_widget_free(sdev, swidget);
if (ret < 0)
return ret;
}
return 0;
}
/*
* For older firmware, this function doesn't free widgets for static pipelines during suspend.
* It only resets use_count for all widgets.
@ -2376,29 +2414,18 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
* This function is called during suspend and for one-time topology verification during
* first boot. In both cases, there is no need to protect swidget->use_count and
* sroute->setup because during suspend all running streams are suspended and during
* topology loading the sound card unavailable to open PCMs.
* topology loading the sound card unavailable to open PCMs. Do not free the scheduler
* widgets yet so that the secondary cores do not get powered down before all the widgets
* associated with the scheduler are freed.
*/
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (swidget->dynamic_pipeline_widget) {
dyn_widgets = true;
continue;
}
ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify);
if (ret < 0)
return ret;
/* Do not free widgets for static pipelines with FW older than SOF2.2 */
if (!verify && !swidget->dynamic_pipeline_widget &&
SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) {
mutex_lock(&swidget->setup_mutex);
swidget->use_count = 0;
mutex_unlock(&swidget->setup_mutex);
if (swidget->spipe)
swidget->spipe->complete = 0;
continue;
}
ret = sof_widget_free(sdev, swidget);
if (ret < 0)
return ret;
}
/* free all the scheduler widgets now */
ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
if (ret < 0)
return ret;
/*
* Tear down all pipelines associated with PCMs that did not get suspended

View file

@ -1067,7 +1067,7 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
return;
}
if (hdr.size < sizeof(hdr)) {
if (hdr.size < sizeof(hdr) || hdr.size > SOF_IPC_MSG_MAX_SIZE) {
dev_err(sdev->dev, "The received message size is invalid\n");
return;
}

View file

@ -413,7 +413,18 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list);
if (ret < 0) {
dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state);
goto free;
/*
* workaround: if the firmware is crashed while setting the
* pipelines to reset state we must ignore the error code and
* reset it to 0.
* Since the firmware is crashed we will not send IPC messages
* and we are going to see errors printed, but the state of the
* widgets will be correct for the next boot.
*/
if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET)
goto free;
ret = 0;
}
/* update RUNNING/RESET state for all pipelines that were just triggered */