summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-core.c
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2018-09-12 11:15:00 +0200
committerMark Brown <broonie@kernel.org>2018-09-12 12:09:04 +0200
commite894efef9ac7c10b7727798dcc711cccf07569f9 (patch)
tree6d729a5ab1e1224afe4eb77ca06964be60cb85c6 /sound/soc/soc-core.c
parentASoC: remove unneeded static set .owner field in platform_driver (diff)
downloadlinux-e894efef9ac7c10b7727798dcc711cccf07569f9.tar.xz
linux-e894efef9ac7c10b7727798dcc711cccf07569f9.zip
ASoC: core: add support to card rebind
Current behaviour of ASoC core w.r.t to component removal is that it unregisters dependent sound card totally. There is no support to rebind the card if the component comes back. Typical use case is DSP restart or kernel modules itself. With this patch, core now maintains list of cards that are unbind due to any of its depended components are removed and card not unregistered yet. This list is cleared when the card is rebind successfully or when the card is unregistered from machine driver. This list of unbind cards are tried to bind once again after every new component is successfully added, giving a fair chance for card bind to be successful. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r--sound/soc/soc-core.c85
1 files changed, 58 insertions, 27 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 7e18937c2214..807f112fad80 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -52,6 +52,7 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
static DEFINE_MUTEX(client_mutex);
static LIST_HEAD(component_list);
+static LIST_HEAD(unbind_card_list);
/*
* This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -2679,6 +2680,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
}
EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
+static int snd_soc_bind_card(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ int ret;
+
+ ret = snd_soc_instantiate_card(card);
+ if (ret != 0)
+ return ret;
+
+ /* deactivate pins to sleep state */
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai;
+ int j;
+
+ for_each_rtd_codec_dai(rtd, j, codec_dai) {
+ if (!codec_dai->active)
+ pinctrl_pm_select_sleep_state(codec_dai->dev);
+ }
+
+ if (!cpu_dai->active)
+ pinctrl_pm_select_sleep_state(cpu_dai->dev);
+ }
+
+ return ret;
+}
+
/**
* snd_soc_register_card - Register a card with the ASoC core
*
@@ -2688,7 +2716,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
int snd_soc_register_card(struct snd_soc_card *card)
{
int i, ret;
- struct snd_soc_pcm_runtime *rtd;
if (!card->name || !card->dev)
return -EINVAL;
@@ -2719,28 +2746,23 @@ int snd_soc_register_card(struct snd_soc_card *card)
mutex_init(&card->mutex);
mutex_init(&card->dapm_mutex);
- ret = snd_soc_instantiate_card(card);
- if (ret != 0)
- return ret;
-
- /* deactivate pins to sleep state */
- list_for_each_entry(rtd, &card->rtd_list, list) {
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai;
- int j;
-
- for_each_rtd_codec_dai(rtd, j, codec_dai) {
- if (!codec_dai->active)
- pinctrl_pm_select_sleep_state(codec_dai->dev);
- }
+ return snd_soc_bind_card(card);
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_card);
- if (!cpu_dai->active)
- pinctrl_pm_select_sleep_state(cpu_dai->dev);
+static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
+{
+ if (card->instantiated) {
+ card->instantiated = false;
+ snd_soc_dapm_shutdown(card);
+ soc_cleanup_card_resources(card);
+ if (!unregister)
+ list_add(&card->list, &unbind_card_list);
+ } else {
+ if (unregister)
+ list_del(&card->list);
}
-
- return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_register_card);
/**
* snd_soc_unregister_card - Unregister a card with the ASoC core
@@ -2750,12 +2772,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
*/
int snd_soc_unregister_card(struct snd_soc_card *card)
{
- if (card->instantiated) {
- card->instantiated = false;
- snd_soc_dapm_shutdown(card);
- soc_cleanup_card_resources(card);
- dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
- }
+ snd_soc_unbind_card(card, true);
+ dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
return 0;
}
@@ -3099,7 +3117,7 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
struct snd_soc_card *card = component->card;
if (card)
- snd_soc_unregister_card(card);
+ snd_soc_unbind_card(card, false);
list_del(&component->list);
}
@@ -3139,6 +3157,18 @@ static void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
stream->formats |= endianness_format_map[i];
}
+static void snd_soc_try_rebind_card(void)
+{
+ struct snd_soc_card *card, *c;
+
+ if (!list_empty(&unbind_card_list)) {
+ list_for_each_entry_safe(card, c, &unbind_card_list, list) {
+ if (!snd_soc_bind_card(card))
+ list_del(&card->list);
+ }
+ }
+}
+
int snd_soc_add_component(struct device *dev,
struct snd_soc_component *component,
const struct snd_soc_component_driver *component_driver,
@@ -3166,6 +3196,7 @@ int snd_soc_add_component(struct device *dev,
}
snd_soc_component_add(component);
+ snd_soc_try_rebind_card();
return 0;