diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b8c9ddfc4490..ac9b2269c26e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2138,10 +2138,29 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) } } +static void snd_soc_remove_device_links(struct snd_soc_card *card, + struct snd_soc_component *stop_at) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (card->dev == component->dev) + continue; + + device_link_remove(card->dev, component->dev); + + if (component == stop_at) + return; + } +} + static void snd_soc_unbind_card(struct snd_soc_card *card) { if (snd_soc_card_is_instantiated(card)) { card->instantiated = false; + + snd_soc_remove_device_links(card, NULL); + soc_cleanup_card_resources(card); } } @@ -2151,6 +2170,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; struct snd_soc_component *component; struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); + struct snd_soc_component *last_devlinked_component = NULL; int ret; snd_soc_card_mutex_lock_root(card); @@ -2275,6 +2295,25 @@ static int snd_soc_bind_card(struct snd_soc_card *card) } } + /* + * Add device_link from card to component so that system_suspend + * will be done in the correct order. The card must suspend first + * to stop audio activity before the components suspend. + */ + for_each_card_components(card, component) { + if (card->dev == component->dev) + continue; + + if (!device_link_add(card->dev, component->dev, DL_FLAG_STATELESS)) { + dev_warn(card->dev, "Failed to create device link to %s\n", + dev_name(component->dev)); + ret = -EINVAL; + goto probe_end; + } + + last_devlinked_component = component; + } + ret = snd_soc_card_late_probe(card); if (ret < 0) goto probe_end; @@ -2303,8 +2342,13 @@ static int snd_soc_bind_card(struct snd_soc_card *card) pinctrl_pm_select_sleep_state(component->dev); probe_end: - if (ret < 0) + if (ret < 0) { + if (last_devlinked_component) + snd_soc_remove_device_links(card, last_devlinked_component); + soc_cleanup_card_resources(card); + } + if (ret == -EPROBE_DEFER) { list_add(&card->list, &unbind_card_list); ret = 0;