ASoC: Fixes for v7.0

Quite a large pull request, but nothing too concerning here - everything
is fairly small.  We've got a couple of smaller core fixes for races on
card teardown from Matteo Cotifava, a fix for handling dodgy DMI
information generated by u-boot, some driver specific fixes and some new
device IDs for Tegra.
This commit is contained in:
Takashi Iwai
2026-03-12 12:59:28 +01:00
10 changed files with 70 additions and 20 deletions

View File

@@ -1610,11 +1610,17 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
region_name); region_name);
if (reg) { if (reg) {
/*
* Although we expect the underlying bus does not require
* physically-contiguous buffers, we pessimistically use
* a temporary buffer instead of trusting that the
* alignment of region->data is ok.
*/
region_len = le32_to_cpu(region->len); region_len = le32_to_cpu(region->len);
if (region_len > buf_len) { if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE); buf_len = round_up(region_len, PAGE_SIZE);
kfree(buf); vfree(buf);
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA); buf = vmalloc(buf_len);
if (!buf) { if (!buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_fw; goto out_fw;
@@ -1643,7 +1649,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
ret = 0; ret = 0;
out_fw: out_fw:
kfree(buf); vfree(buf);
if (ret == -EOVERFLOW) if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file); cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
@@ -2331,11 +2337,17 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
} }
if (reg) { if (reg) {
/*
* Although we expect the underlying bus does not require
* physically-contiguous buffers, we pessimistically use
* a temporary buffer instead of trusting that the
* alignment of blk->data is ok.
*/
region_len = le32_to_cpu(blk->len); region_len = le32_to_cpu(blk->len);
if (region_len > buf_len) { if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE); buf_len = round_up(region_len, PAGE_SIZE);
kfree(buf); vfree(buf);
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA); buf = vmalloc(buf_len);
if (!buf) { if (!buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_fw; goto out_fw;
@@ -2366,7 +2378,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
ret = 0; ret = 0;
out_fw: out_fw:
kfree(buf); vfree(buf);
if (ret == -EOVERFLOW) if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file); cs_dsp_err(dsp, "%s: file content overflows file data\n", file);

View File

@@ -127,8 +127,13 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != RT5682) if (drvdata->hs_codec_id != RT5682)
return -EINVAL; return -EINVAL;
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); drvdata->wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); if (IS_ERR(drvdata->wclk))
return PTR_ERR(drvdata->wclk);
drvdata->bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
if (IS_ERR(drvdata->bclk))
return PTR_ERR(drvdata->bclk);
ret = snd_soc_dapm_new_controls(dapm, rt5682_widgets, ret = snd_soc_dapm_new_controls(dapm, rt5682_widgets,
ARRAY_SIZE(rt5682_widgets)); ARRAY_SIZE(rt5682_widgets));
@@ -370,8 +375,13 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return -EINVAL; return -EINVAL;
if (!drvdata->soc_mclk) { if (!drvdata->soc_mclk) {
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); drvdata->wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); if (IS_ERR(drvdata->wclk))
return PTR_ERR(drvdata->wclk);
drvdata->bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
if (IS_ERR(drvdata->bclk))
return PTR_ERR(drvdata->bclk);
} }
ret = snd_soc_dapm_new_controls(dapm, rt5682s_widgets, ret = snd_soc_dapm_new_controls(dapm, rt5682s_widgets,

View File

@@ -94,8 +94,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
} }
rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk"); rt5682_dai_wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); if (IS_ERR(rt5682_dai_wclk))
return PTR_ERR(rt5682_dai_wclk);
rt5682_dai_bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
if (IS_ERR(rt5682_dai_bclk))
return PTR_ERR(rt5682_dai_bclk);
ret = snd_soc_card_jack_new_pins(card, "Headset Jack", ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_HEADSET |

View File

@@ -1047,7 +1047,7 @@ static int rt1011_recv_spk_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt1011_priv *rt1011 = struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component); snd_soc_component_get_drvdata(component);

View File

@@ -1038,11 +1038,15 @@ int graph_util_is_ports0(struct device_node *np)
else else
port = np; port = np;
struct device_node *ports __free(device_node) = of_get_parent(port); struct device_node *ports __free(device_node) = of_get_parent(port);
struct device_node *top __free(device_node) = of_get_parent(ports); const char *at = strchr(kbasename(ports->full_name), '@');
struct device_node *ports0 __free(device_node) = of_get_child_by_name(top, "ports");
return ports0 == ports; /*
* Since child iteration order may differ
* between a base DT and DT overlays,
* string match "ports" or "ports@0" in the node name instead.
*/
return !at || !strcmp(at, "@0");
} }
EXPORT_SYMBOL_GPL(graph_util_is_ports0); EXPORT_SYMBOL_GPL(graph_util_is_ports0);

View File

@@ -838,6 +838,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = {
.ack = q6apm_dai_ack, .ack = q6apm_dai_ack,
.compress_ops = &q6apm_dai_compress_ops, .compress_ops = &q6apm_dai_compress_ops,
.use_dai_pcm_id = true, .use_dai_pcm_id = true,
.remove_order = SND_SOC_COMP_ORDER_EARLY,
}; };
static int q6apm_dai_probe(struct platform_device *pdev) static int q6apm_dai_probe(struct platform_device *pdev)

View File

@@ -278,6 +278,7 @@ static const struct snd_soc_component_driver q6apm_lpass_dai_component = {
.of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name, .of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name,
.be_pcm_base = AUDIOREACH_BE_PCM_BASE, .be_pcm_base = AUDIOREACH_BE_PCM_BASE,
.use_dai_pcm_id = true, .use_dai_pcm_id = true,
.remove_order = SND_SOC_COMP_ORDER_FIRST,
}; };
static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev) static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev)

View File

@@ -715,6 +715,7 @@ static const struct snd_soc_component_driver q6apm_audio_component = {
.name = APM_AUDIO_DRV_NAME, .name = APM_AUDIO_DRV_NAME,
.probe = q6apm_audio_probe, .probe = q6apm_audio_probe,
.remove = q6apm_audio_remove, .remove = q6apm_audio_remove,
.remove_order = SND_SOC_COMP_ORDER_LAST,
}; };
static int apm_probe(gpr_device_t *gdev) static int apm_probe(gpr_device_t *gdev)

View File

@@ -462,8 +462,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
list_del(&rtd->list); list_del(&rtd->list);
if (delayed_work_pending(&rtd->delayed_work)) flush_delayed_work(&rtd->delayed_work);
flush_delayed_work(&rtd->delayed_work);
snd_soc_pcm_component_free(rtd); snd_soc_pcm_component_free(rtd);
/* /*
@@ -1864,12 +1863,15 @@ static void cleanup_dmi_name(char *name)
/* /*
* Check if a DMI field is valid, i.e. not containing any string * Check if a DMI field is valid, i.e. not containing any string
* in the black list. * in the black list and not the empty string.
*/ */
static int is_dmi_valid(const char *field) static int is_dmi_valid(const char *field)
{ {
int i = 0; int i = 0;
if (!field[0])
return 0;
while (dmi_blacklist[i]) { while (dmi_blacklist[i]) {
if (strstr(field, dmi_blacklist[i])) if (strstr(field, dmi_blacklist[i]))
return 0; return 0;
@@ -2122,6 +2124,9 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
for_each_card_rtds(card, rtd) for_each_card_rtds(card, rtd)
if (rtd->initialized) if (rtd->initialized)
snd_soc_link_exit(rtd); snd_soc_link_exit(rtd);
/* flush delayed work before removing DAIs and DAPM widgets */
snd_soc_flush_all_delayed_work(card);
/* remove and free each DAI */ /* remove and free each DAI */
soc_remove_link_dais(card); soc_remove_link_dais(card);
soc_remove_link_components(card); soc_remove_link_components(card);

View File

@@ -231,6 +231,15 @@ static const struct tegra_audio_cdata tegra186_data = {
.plla_out0_rates[x11_RATE] = 45158400, .plla_out0_rates[x11_RATE] = 45158400,
}; };
static const struct tegra_audio_cdata tegra238_data = {
/* PLLA */
.plla_rates[x8_RATE] = 1277952000,
.plla_rates[x11_RATE] = 1264435200,
/* PLLA_OUT0 */
.plla_out0_rates[x8_RATE] = 49152000,
.plla_out0_rates[x11_RATE] = 45158400,
};
static const struct tegra_audio_cdata tegra264_data = { static const struct tegra_audio_cdata tegra264_data = {
/* PLLA1 */ /* PLLA1 */
.plla_rates[x8_RATE] = 983040000, .plla_rates[x8_RATE] = 983040000,
@@ -245,6 +254,8 @@ static const struct of_device_id graph_of_tegra_match[] = {
.data = &tegra210_data }, .data = &tegra210_data },
{ .compatible = "nvidia,tegra186-audio-graph-card", { .compatible = "nvidia,tegra186-audio-graph-card",
.data = &tegra186_data }, .data = &tegra186_data },
{ .compatible = "nvidia,tegra238-audio-graph-card",
.data = &tegra238_data },
{ .compatible = "nvidia,tegra264-audio-graph-card", { .compatible = "nvidia,tegra264-audio-graph-card",
.data = &tegra264_data }, .data = &tegra264_data },
{}, {},