aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
authorMark Brown <broonie@kernel.org>2026-05-25 13:37:18 +0100
committerMark Brown <broonie@kernel.org>2026-05-25 13:37:18 +0100
commitbb49a57c53b71d88f536ba2679a7b32fb17d9c44 (patch)
tree8e7cf4d8b749e5c325b2a31cff087855a5643934 /sound
parent3bd860dcf90213e59cb36cbed0b7d7870a248c9d (diff)
parent68bb9a7f557a504b9221717c708a0d14aa727815 (diff)
downloadlinux-next-history-bb49a57c53b71d88f536ba2679a7b32fb17d9c44.tar.gz
ASoC: soc-core: Add core support for ignoring suspend on selected DAPM widgets
Chancel Liu <chancel.liu@nxp.com> says: Some audio systems require specific DAPM widgets to remain powered during system suspend. Introduce a generic and reusable mechanism in the ASoC core to mark selected DAPM widgets as ignore_suspend. The unified mechanism consists of two parts: 1. Parse and store the name list of widgets to ignore suspend in struct snd_soc_card The list of widgets can be provided either by the machine driver or parsed from Device Tree. Different machines have different routing and power requirements. Each machine can specify its own widgets to ignore suspend through DT property. It enables flexible policy without hard code. A new helper, snd_soc_of_parse_ignore_suspend_widgets() is added for this purpose. 2. Apply ignore_suspend flags during snd_soc_bind_card() After all components have been probed and all DAPM widgets have been registered, snd_soc_bind_card() performs a unified lookup of the configured widget names across all DAPM contexts of the card and marks the matching widgets with ignore_suspend = 1. Switch to use core ignore-suspend-widgets support for imx-rpmsg driver. Chancel Liu (3): ASoC: dapm: Fix widget lookup with prefixed names across DAPM contexts ASoC: soc-core: Add core support for ignoring suspend on selected DAPM widgets ASoC: fsl: imx-rpmsg: Switch to core ignore-suspend-widgets support Link: https://patch.msgid.link/20260507013654.2945915-1-chancel.liu@nxp.com
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/fsl/imx-rpmsg.c26
-rw-r--r--sound/soc/soc-core.c43
-rw-r--r--sound/soc/soc-dapm.c79
3 files changed, 119 insertions, 29 deletions
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index 40e0043cfe15e..fd4624786b627 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -87,7 +87,6 @@ static int imx_rpmsg_late_probe(struct snd_soc_card *card)
int ret;
if (data->lpa) {
- struct snd_soc_component *codec_comp;
struct device_node *codec_np;
struct device_driver *codec_drv;
struct device *codec_dev = NULL;
@@ -107,22 +106,6 @@ static int imx_rpmsg_late_probe(struct snd_soc_card *card)
}
}
if (codec_dev) {
- codec_comp = snd_soc_lookup_component_nolocked(codec_dev, NULL);
- if (codec_comp) {
- int i, num_widgets;
- const char *widgets;
- struct snd_soc_dapm_context *dapm;
-
- num_widgets = of_property_count_strings(data->card.dev->of_node,
- "ignore-suspend-widgets");
- for (i = 0; i < num_widgets; i++) {
- of_property_read_string_index(data->card.dev->of_node,
- "ignore-suspend-widgets",
- i, &widgets);
- dapm = snd_soc_component_to_dapm(codec_comp);
- snd_soc_dapm_ignore_suspend(dapm, widgets);
- }
- }
codec_drv = codec_dev->driver;
if (codec_drv->pm) {
memcpy(&lpa_pm, codec_drv->pm, sizeof(lpa_pm));
@@ -274,6 +257,15 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
}
}
+ if (data->lpa && of_property_present(np, "ignore-suspend-widgets")) {
+ ret = snd_soc_of_parse_ignore_suspend_widgets(&data->card,
+ "ignore-suspend-widgets");
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse ignore-suspend-widgets: %d\n", ret);
+ goto fail;
+ }
+ }
+
platform_set_drvdata(pdev, &data->card);
snd_soc_card_set_drvdata(&data->card, data);
ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2c05299604b33..ec744b9d6fd1e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2289,6 +2289,10 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
if (ret < 0)
goto probe_end;
+ ret = snd_soc_dapm_ignore_suspend_widgets(card);
+ if (ret < 0)
+ goto probe_end;
+
snd_soc_dapm_new_widgets(card);
snd_soc_card_fixup_controls(card);
@@ -3279,6 +3283,45 @@ int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname)
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_aux_devs);
+int snd_soc_of_parse_ignore_suspend_widgets(struct snd_soc_card *card,
+ const char *propname)
+{
+ struct device_node *np = card->dev->of_node;
+ int num_widgets;
+ const char **widgets;
+ int i;
+
+ num_widgets = of_property_count_strings(np, propname);
+ if (num_widgets < 0) {
+ dev_err(card->dev,
+ "ASoC: Property '%s' does not exist\n", propname);
+ return -EINVAL;
+ }
+
+ widgets = devm_kcalloc(card->dev, num_widgets, sizeof(char *), GFP_KERNEL);
+ if (!widgets)
+ return -ENOMEM;
+
+ for (i = 0; i < num_widgets; i++) {
+ const char *name;
+ int ret = of_property_read_string_index(np, propname, i, &name);
+
+ if (ret) {
+ dev_err(card->dev,
+ "ASoC: Property '%s' could not be read: %d\n",
+ propname, ret);
+ return -EINVAL;
+ }
+ widgets[i] = name;
+ }
+
+ card->num_of_ignore_suspend_widgets = num_widgets;
+ card->of_ignore_suspend_widgets = widgets;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_ignore_suspend_widgets);
+
unsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt)
{
unsigned int inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 10f5fb771e301..4ad126bd4f705 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2912,20 +2912,18 @@ static struct snd_soc_dapm_widget *dapm_find_widget(
{
struct snd_soc_dapm_widget *w;
struct snd_soc_dapm_widget *fallback = NULL;
- char prefixed_pin[80];
- const char *pin_name;
- const char *prefix = dapm_prefix(dapm);
-
- if (prefix) {
- snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s",
- prefix, pin);
- pin_name = prefixed_pin;
- } else {
- pin_name = pin;
- }
+ bool pin_has_prefix = snd_soc_dapm_pin_has_prefix(dapm->card, pin);
+ bool match;
for_each_card_widgets(dapm->card, w) {
- if (!strcmp(w->name, pin_name)) {
+ match = false;
+
+ if (!strcmp(pin, w->name))
+ match = true;
+ else if (!pin_has_prefix && !snd_soc_dapm_widget_name_cmp(w, pin))
+ match = true;
+
+ if (match) {
if (w->dapm == dapm)
return w;
else
@@ -4612,6 +4610,36 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
}
}
+int snd_soc_dapm_ignore_suspend_widgets(struct snd_soc_card *card)
+{
+ struct snd_soc_dapm_widget *w;
+ int i;
+
+ for (i = 0; i < card->num_ignore_suspend_widgets; i++) {
+ w = dapm_find_widget(snd_soc_card_to_dapm(card),
+ card->ignore_suspend_widgets[i], true);
+ if (!w) {
+ dev_err(card->dev, "ASoC: DAPM unknown ignore suspend widget %s\n",
+ card->ignore_suspend_widgets[i]);
+ return -EINVAL;
+ }
+ w->ignore_suspend = 1;
+ }
+
+ for (i = 0; i < card->num_of_ignore_suspend_widgets; i++) {
+ w = dapm_find_widget(snd_soc_card_to_dapm(card),
+ card->of_ignore_suspend_widgets[i], true);
+ if (!w) {
+ dev_err(card->dev, "ASoC: DAPM unknown ignore suspend widget %s\n",
+ card->of_ignore_suspend_widgets[i]);
+ return -EINVAL;
+ }
+ w->ignore_suspend = 1;
+ }
+
+ return 0;
+}
+
static void dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event)
{
struct snd_soc_dai *dai;
@@ -4879,6 +4907,33 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
/**
+ * snd_soc_dapm_pin_has_prefix - check if given pin has a known prefix
+ * @card: card to be checked
+ * @pin: pin name
+ *
+ * Returns true if given pin has a known prefix
+ */
+bool snd_soc_dapm_pin_has_prefix(struct snd_soc_card *card, const char *pin)
+{
+ struct snd_soc_component *component;
+ const char *prefix;
+ size_t prefix_len;
+
+ for_each_card_components(card, component) {
+ prefix = component->name_prefix;
+ if (!prefix)
+ continue;
+
+ prefix_len = strlen(prefix);
+ if (!strncmp(pin, prefix, prefix_len) && pin[prefix_len] == ' ')
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_pin_has_prefix);
+
+/**
* snd_soc_dapm_free - free dapm resources
* @dapm: DAPM context
*