summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-core.c
diff options
context:
space:
mode:
authorMengdong Lin2015-12-02 07:11:22 +0100
committerMark Brown2015-12-08 19:05:09 +0100
commitf8f80361d07d503093940097e967a7edaa134ca2 (patch)
tree54806e1eff53dc701d9258ee204d04c67bd31177 /sound/soc/soc-core.c
parentASoC: Change 2nd argument of soc_bind_dai_link() to DAI link pointer (diff)
downloadkernel-qcow2-linux-f8f80361d07d503093940097e967a7edaa134ca2.tar.gz
kernel-qcow2-linux-f8f80361d07d503093940097e967a7edaa134ca2.tar.xz
kernel-qcow2-linux-f8f80361d07d503093940097e967a7edaa134ca2.zip
ASoC: Implement DAI links in a list & define API to add/remove a link
Implement a dai link list for the soc card. Add APIs to add/remove a DAI links dynamically, e.g. by topology. And a dobj is embedded into the struct snd_soc_dai_link. Topology can use the dobj to find the links created by it and remove them when the topology component is unloaded. The predefined DAI links are reserved to keep backward compatibility. And they will also be added to the list. Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r--sound/soc/soc-core.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 878a9fe92686..bf4bccfc4b91 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1120,6 +1120,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card)
{
int order;
struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai_link *link, *_link;
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
@@ -1132,6 +1133,15 @@ static void soc_remove_dai_links(struct snd_soc_card *card)
list_for_each_entry(rtd, &card->rtd_list, list)
soc_remove_link_components(card, rtd, order);
}
+
+ list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+ if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK)
+ dev_warn(card->dev, "Topology forgot to remove link %s?\n",
+ link->name);
+
+ list_del(&link->list);
+ card->num_dai_links--;
+ }
}
static int snd_soc_init_multicodec(struct snd_soc_card *card,
@@ -1228,6 +1238,68 @@ static int soc_init_dai_link(struct snd_soc_card *card,
return 0;
}
+/**
+ * snd_soc_add_dai_link - Add a DAI link dynamically
+ * @card: The ASoC card to which the DAI link is added
+ * @dai_link: The new DAI link to add
+ *
+ * This function adds a DAI link to the ASoC card's link list.
+ *
+ * Note: Topology can use this API to add DAI links when probing the
+ * topology component. And machine drivers can still define static
+ * DAI links in dai_link array.
+ */
+int snd_soc_add_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ if (dai_link->dobj.type
+ && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+ dev_err(card->dev, "Invalid dai link type %d\n",
+ dai_link->dobj.type);
+ return -EINVAL;
+ }
+
+ lockdep_assert_held(&client_mutex);
+ list_add_tail(&dai_link->list, &card->dai_link_list);
+ card->num_dai_links++;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_dai_link);
+
+/**
+ * snd_soc_remove_dai_link - Remove a DAI link from the list
+ * @card: The ASoC card that owns the link
+ * @dai_link: The DAI link to remove
+ *
+ * This function removes a DAI link from the ASoC card's link list.
+ *
+ * For DAI links previously added by topology, topology should
+ * remove them by using the dobj embedded in the link.
+ */
+void snd_soc_remove_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_dai_link *link, *_link;
+
+ if (dai_link->dobj.type
+ && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+ dev_err(card->dev, "Invalid dai link type %d\n",
+ dai_link->dobj.type);
+ return;
+ }
+
+ lockdep_assert_held(&client_mutex);
+ list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+ if (link == dai_link) {
+ list_del(&link->list);
+ card->num_dai_links--;
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
+
static void soc_set_name_prefix(struct snd_soc_card *card,
struct snd_soc_component *component)
{
@@ -1722,6 +1794,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
goto base_error;
}
+ /* add predefined DAI links to the list */
+ for (i = 0; i < card->num_links; i++)
+ snd_soc_add_dai_link(card, card->dai_link+i);
+
/* initialize the register cache for each available codec */
list_for_each_entry(codec, &codec_list, list) {
if (codec->cache_init)
@@ -2479,6 +2555,9 @@ int snd_soc_register_card(struct snd_soc_card *card)
snd_soc_initialize_card_lists(card);
+ INIT_LIST_HEAD(&card->dai_link_list);
+ card->num_dai_links = 0;
+
INIT_LIST_HEAD(&card->rtd_list);
card->num_rtd = 0;