Commit 3db9d4b3 authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'asoc-fix-v6.8-rc4' of...

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.
parents 852d432a 0db0c177
......@@ -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:
......
......@@ -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);
......
......@@ -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;
......
......@@ -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 = {
......
......@@ -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 },
......
......@@ -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,63 +70,7 @@ static const char * const cs35l56_asp1_mux_control_names[] = {
"ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source"
};
static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int index = e->shift_l;
unsigned int addr, val;
int ret;
/* Wait for mux to be initialized */
cs35l56_wait_dsp_ready(cs35l56);
flush_work(&cs35l56->mux_init_work);
addr = cs35l56_asp1_mixer_regs[index];
ret = regmap_read(cs35l56->base.regmap, addr, &val);
if (ret)
return ret;
val &= CS35L56_ASP_TXn_SRC_MASK;
ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
return 0;
}
static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int item = ucontrol->value.enumerated.item[0];
int index = e->shift_l;
unsigned int addr, val;
bool changed;
int ret;
/* Wait for mux to be initialized */
cs35l56_wait_dsp_ready(cs35l56);
flush_work(&cs35l56->mux_init_work);
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)
return ret;
if (changed)
snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
return changed;
}
static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l56)
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;
......@@ -135,13 +81,19 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5
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;
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));
......@@ -151,12 +103,9 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5
if (ret) {
dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret);
return;
return ret;
}
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];
......@@ -176,16 +125,65 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5
snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
}
snd_soc_card_mutex_unlock(dapm->card);
cs35l56->asp1_mixer_widgets_initialized = true;
return 0;
}
static void cs35l56_mux_init_work(struct work_struct *work)
static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct cs35l56_private *cs35l56 = container_of(work,
struct cs35l56_private,
mux_init_work);
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int index = e->shift_l;
unsigned int addr, val;
int ret;
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);
if (ret)
return ret;
cs35l56_mark_asp1_mixer_widgets_dirty(cs35l56);
val &= CS35L56_ASP_TXn_SRC_MASK;
ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
return 0;
}
static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int item = ucontrol->value.enumerated.item[0];
int index = e->shift_l;
unsigned int addr, val;
bool changed;
int ret;
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)
return ret;
if (changed)
snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
return changed;
}
static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
......@@ -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;
......
......@@ -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;
};
......
......@@ -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", },
......
......@@ -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,
},
{ }
};
......
......@@ -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)
......
......@@ -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)
......
......@@ -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:
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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--;
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__);
spin_unlock_irq(&sdev->ipc_lock);
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;
};
......
......@@ -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",
......
......@@ -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,
......
......@@ -2360,27 +2360,16 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
return 0;
}
/*
* For older firmware, this function doesn't free widgets for static pipelines during suspend.
* It only resets use_count for all widgets.
*/
static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
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;
struct snd_sof_route *sroute;
bool dyn_widgets = false;
int ret;
/*
* 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.
*/
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (swidget->dynamic_pipeline_widget) {
dyn_widgets = true;
*dyn_widgets = true;
continue;
}
......@@ -2395,11 +2384,49 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
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.
*/
static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
{
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
bool dyn_widgets = false;
int ret;
/*
* 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. 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.
*/
ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify);
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
* and unset the prepare flag so that they can be set up again during resume.
......
......@@ -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;
}
......
......@@ -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);
/*
* 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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment