summaryrefslogtreecommitdiff
path: root/sound/soc/soc-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r--sound/soc/soc-core.c273
1 files changed, 194 insertions, 79 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1a0bde23f5e6..cc442c52cdea 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -238,6 +238,81 @@ static inline void snd_soc_debugfs_exit(void) { }
#endif
+static int snd_soc_is_match_dai_args(struct of_phandle_args *args1,
+ struct of_phandle_args *args2)
+{
+ if (!args1 || !args2)
+ return 0;
+
+ if (args1->np != args2->np)
+ return 0;
+
+ for (int i = 0; i < args1->args_count; i++)
+ if (args1->args[i] != args2->args[i])
+ return 0;
+
+ return 1;
+}
+
+static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+ return !(dlc->dai_args || dlc->name || dlc->of_node);
+}
+
+static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc)
+{
+ return (dlc->name && dlc->of_node);
+}
+
+static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+ return !(dlc->dai_args || dlc->dai_name);
+}
+
+static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc,
+ struct snd_soc_dai *dai)
+{
+ if (!dlc)
+ return 0;
+
+ if (dlc->dai_args)
+ return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args);
+
+ if (!dlc->dai_name)
+ return 1;
+
+ /* see snd_soc_dai_name_get() */
+
+ if (strcmp(dlc->dai_name, dai->name) == 0)
+ return 1;
+
+ if (dai->driver->name &&
+ strcmp(dai->driver->name, dlc->dai_name) == 0)
+ return 1;
+
+ if (dai->component->name &&
+ strcmp(dlc->dai_name, dai->component->name) == 0)
+ return 1;
+
+ return 0;
+}
+
+const char *snd_soc_dai_name_get(struct snd_soc_dai *dai)
+{
+ /* see snd_soc_is_matching_dai() */
+ if (dai->name)
+ return dai->name;
+
+ if (dai->driver->name)
+ return dai->driver->name;
+
+ if (dai->component->name)
+ return dai->component->name;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_name_get);
+
static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_component *component)
{
@@ -734,6 +809,19 @@ static struct device_node
return of_node;
}
+struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, struct of_phandle_args *args)
+{
+ struct of_phandle_args *ret = devm_kzalloc(dev, sizeof(*ret), GFP_KERNEL);
+
+ if (!ret)
+ return NULL;
+
+ *ret = *args;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_copy_dai_args);
+
static int snd_soc_is_matching_component(
const struct snd_soc_dai_link_component *dlc,
struct snd_soc_component *component)
@@ -743,6 +831,15 @@ static int snd_soc_is_matching_component(
if (!dlc)
return 0;
+ if (dlc->dai_args) {
+ struct snd_soc_dai *dai;
+
+ for_each_component_dais(component, dai)
+ if (snd_soc_is_matching_dai(dlc, dai))
+ return 1;
+ return 0;
+ }
+
component_of_node = soc_component_to_node(component);
if (dlc->of_node && component_of_node != dlc->of_node)
@@ -795,18 +892,11 @@ struct snd_soc_dai *snd_soc_find_dai(
lockdep_assert_held(&client_mutex);
/* Find CPU DAI from registered DAIs */
- for_each_component(component) {
- if (!snd_soc_is_matching_component(dlc, component))
- continue;
- for_each_component_dais(component, dai) {
- if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
- && (!dai->driver->name
- || strcmp(dai->driver->name, dlc->dai_name)))
- continue;
-
- return dai;
- }
- }
+ for_each_component(component)
+ if (snd_soc_is_matching_component(dlc, component))
+ for_each_component_dais(component, dai)
+ if (snd_soc_is_matching_dai(dlc, dai))
+ return dai;
return NULL;
}
@@ -829,102 +919,100 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
struct snd_soc_dai_link *link)
{
int i;
- struct snd_soc_dai_link_component *cpu, *codec, *platform;
+ struct snd_soc_dai_link_component *dlc;
- for_each_link_codecs(link, i, codec) {
+ /* Codec check */
+ for_each_link_codecs(link, i, dlc) {
/*
* Codec must be specified by 1 of name or OF node,
* not both or neither.
*/
- if (!!codec->name == !!codec->of_node) {
- dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
+
+ if (snd_soc_dlc_component_is_empty(dlc))
+ goto component_empty;
/* Codec DAI name must be specified */
- if (!codec->dai_name) {
- dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_dai_is_empty(dlc))
+ goto dai_empty;
/*
* Defer card registration if codec component is not added to
* component list.
*/
- if (!soc_find_component(codec)) {
- dev_dbg(card->dev,
- "ASoC: codec component %s not found for link %s\n",
- codec->name, link->name);
- return -EPROBE_DEFER;
- }
+ if (!soc_find_component(dlc))
+ goto component_not_found;
}
- for_each_link_platforms(link, i, platform) {
+ /* Platform check */
+ for_each_link_platforms(link, i, dlc) {
/*
* Platform may be specified by either name or OF node, but it
* can be left unspecified, then no components will be inserted
* in the rtdcom list
*/
- if (!!platform->name == !!platform->of_node) {
- dev_err(card->dev,
- "ASoC: Neither/both platform name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
+
+ if (snd_soc_dlc_component_is_empty(dlc))
+ goto component_empty;
/*
* Defer card registration if platform component is not added to
* component list.
*/
- if (!soc_find_component(platform)) {
- dev_dbg(card->dev,
- "ASoC: platform component %s not found for link %s\n",
- platform->name, link->name);
- return -EPROBE_DEFER;
- }
+ if (!soc_find_component(dlc))
+ goto component_not_found;
}
- for_each_link_cpus(link, i, cpu) {
+ /* CPU check */
+ for_each_link_cpus(link, i, dlc) {
/*
* CPU device may be specified by either name or OF node, but
* can be left unspecified, and will be matched based on DAI
* name alone..
*/
- if (cpu->name && cpu->of_node) {
- dev_err(card->dev,
- "ASoC: Neither/both cpu name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
- /*
- * Defer card registration if cpu dai component is not added to
- * component list.
- */
- if ((cpu->of_node || cpu->name) &&
- !soc_find_component(cpu)) {
- dev_dbg(card->dev,
- "ASoC: cpu component %s not found for link %s\n",
- cpu->name, link->name);
- return -EPROBE_DEFER;
- }
- /*
- * At least one of CPU DAI name or CPU device name/node must be
- * specified
- */
- if (!cpu->dai_name &&
- !(cpu->name || cpu->of_node)) {
- dev_err(card->dev,
- "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
+ if (snd_soc_dlc_component_is_empty(dlc)) {
+ /*
+ * At least one of CPU DAI name or CPU device name/node must be specified
+ */
+ if (snd_soc_dlc_dai_is_empty(dlc))
+ goto component_dai_empty;
+ } else {
+ /*
+ * Defer card registration if Component is not added
+ */
+ if (!soc_find_component(dlc))
+ goto component_not_found;
}
}
return 0;
+
+component_invalid:
+ dev_err(card->dev, "ASoC: Both Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
+
+component_empty:
+ dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
+
+component_not_found:
+ dev_dbg(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name);
+ return -EPROBE_DEFER;
+
+dai_empty:
+ dev_err(card->dev, "ASoC: DAI name is not set for %s\n", link->name);
+ return -EINVAL;
+
+component_dai_empty:
+ dev_err(card->dev, "ASoC: Neither DAI/Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
}
/**
@@ -2930,6 +3018,14 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
+void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
+ struct snd_soc_dai_link_component *cpus)
+{
+ platforms->of_node = cpus->of_node;
+ platforms->dai_args = cpus->dai_args;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dlc_use_cpu_as_platform);
+
void snd_soc_of_parse_node_prefix(struct device_node *np,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
@@ -3235,11 +3331,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu);
int snd_soc_get_dai_id(struct device_node *ep)
{
struct snd_soc_component *component;
- struct snd_soc_dai_link_component dlc;
+ struct snd_soc_dai_link_component dlc = {
+ .of_node = of_graph_get_port_parent(ep),
+ };
int ret;
- dlc.of_node = of_graph_get_port_parent(ep);
- dlc.name = NULL;
+
/*
* For example HDMI case, HDMI has video/sound port,
* but ALSA SoC needs sound port number only.
@@ -3264,8 +3361,6 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
struct snd_soc_component *pos;
int ret = -EPROBE_DEFER;
- dlc->of_node = args->np;
-
mutex_lock(&client_mutex);
for_each_component(pos) {
struct device_node *component_of_node = soc_component_to_node(pos);
@@ -3304,9 +3399,7 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
id--;
}
- dlc->dai_name = dai->driver->name;
- if (!dlc->dai_name)
- dlc->dai_name = pos->name;
+ dlc->dai_name = snd_soc_dai_name_get(dai);
} else if (ret) {
/*
* if another error than ENOTSUPP is returned go on and
@@ -3319,6 +3412,10 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
break;
}
+
+ if (ret == 0)
+ dlc->of_node = args->np;
+
mutex_unlock(&client_mutex);
return ret;
}
@@ -3370,6 +3467,24 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
}
EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
+struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args)
+{
+ struct snd_soc_dai *dai;
+ struct snd_soc_component *component;
+
+ mutex_lock(&client_mutex);
+ for_each_component(component) {
+ for_each_component_dais(component, dai)
+ if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args))
+ goto found;
+ }
+ dai = NULL;
+found:
+ mutex_unlock(&client_mutex);
+ return dai;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args);
+
static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component)
{
if (component->of_node) {