Commit 4da4a746 authored by Mark Brown's avatar Mark Brown

ASoC: add multi Component support

Merge series from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>:

On below HW case, we would like to use it as "2 Cards",
but unfortunately it is impossible in intuitive way,
or possible but not intuitive way.
In reality, it is handled as "1 big Card" today.

	+-- basic board --------+
	|+--------+             |
	|| CPU ch0| <--> CodecA |
	||     ch1| <-+         |
	|+--------+   |         |
	+-------------|---------+
	+-- expansion board ----+
	|             |         |
	|             +-> CodecB|
	+-----------------------+

To handling it as intuitive "2 Cards", this patch-set
adds multi Component support.

To enable this patch-set, I included [01/15] patch into this patch-set
which is posted but not yet accepted.
parents c1325a2d 970dc991
......@@ -192,9 +192,8 @@ int asoc_simple_remove(struct platform_device *pdev);
int asoc_graph_card_probe(struct snd_soc_card *card);
int asoc_graph_is_ports0(struct device_node *port);
int asoc_graph_parse_dai(struct device_node *ep,
struct snd_soc_dai_link_component *dlc,
int *is_single_link);
int asoc_graph_parse_dai(struct device *dev, struct device_node *ep,
struct snd_soc_dai_link_component *dlc, int *is_single_link);
#ifdef DEBUG
static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
......
......@@ -271,6 +271,8 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
struct snd_compr_stream *cstream,
struct snd_compr_metadata *metadata);
const char *snd_soc_dai_name_get(struct snd_soc_dai *dai);
struct snd_soc_dai_ops {
/*
* DAI clocking configuration, all optional.
......@@ -397,6 +399,7 @@ struct snd_soc_dai_driver {
unsigned int id;
unsigned int base;
struct snd_soc_dobj dobj;
struct of_phandle_args *dai_args;
/* DAI driver callbacks */
int (*probe)(struct snd_soc_dai *dai);
......
......@@ -651,6 +651,7 @@ struct snd_soc_dai_link_component {
const char *name;
struct device_node *of_node;
const char *dai_name;
struct of_phandle_args *dai_args;
};
struct snd_soc_dai_link_codec_ch_map {
......@@ -1335,6 +1336,11 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card,
void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd);
void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
struct snd_soc_dai_link_component *cpus);
struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
struct of_phandle_args *args);
struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args);
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
bool legacy_dai_naming);
......
......@@ -126,7 +126,7 @@ static int graph_parse_node(struct asoc_simple_priv *priv,
graph_parse_mclk_fs(top, ep, dai_props);
ret = asoc_graph_parse_dai(ep, dlc, cpu);
ret = asoc_graph_parse_dai(dev, ep, dlc, cpu);
if (ret < 0)
return ret;
......
......@@ -407,7 +407,7 @@ static int __graph_parse_node(struct asoc_simple_priv *priv,
graph_parse_mclk_fs(ep, dai_props);
ret = asoc_graph_parse_dai(ep, dlc, &is_single_links);
ret = asoc_graph_parse_dai(dev, ep, dlc, &is_single_links);
if (ret < 0)
return ret;
......
......@@ -649,7 +649,7 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo
* simple-card.c :: simple_count_noml()
*/
if (!platforms->of_node)
platforms->of_node = cpus->of_node;
snd_soc_dlc_use_cpu_as_platform(platforms, cpus);
}
EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
......@@ -1066,12 +1066,12 @@ static int graph_get_dai_id(struct device_node *ep)
return id;
}
int asoc_graph_parse_dai(struct device_node *ep,
struct snd_soc_dai_link_component *dlc,
int *is_single_link)
int asoc_graph_parse_dai(struct device *dev, struct device_node *ep,
struct snd_soc_dai_link_component *dlc, int *is_single_link)
{
struct device_node *node;
struct of_phandle_args args = {};
struct snd_soc_dai *dai;
int ret;
if (!ep)
......@@ -1079,6 +1079,20 @@ int asoc_graph_parse_dai(struct device_node *ep,
node = of_graph_get_port_parent(ep);
/*
* Try to find from DAI node
*/
args.np = ep;
dai = snd_soc_get_dai_via_args(&args);
if (dai) {
dlc->dai_name = snd_soc_dai_name_get(dai);
dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
if (!dlc->dai_args)
return -ENOMEM;
goto parse_dai_end;
}
/* Get dai->name */
args.np = node;
args.args[0] = graph_get_dai_id(ep);
......@@ -1109,6 +1123,7 @@ int asoc_graph_parse_dai(struct device_node *ep,
return ret;
}
parse_dai_end:
if (is_single_link)
*is_single_link = of_graph_get_endpoint_count(node) == 1;
......
......@@ -52,11 +52,13 @@ static int asoc_simple_parse_platform(struct device_node *node,
return 0;
}
static int asoc_simple_parse_dai(struct device_node *node,
static int asoc_simple_parse_dai(struct device *dev,
struct device_node *node,
struct snd_soc_dai_link_component *dlc,
int *is_single_link)
{
struct of_phandle_args args;
struct snd_soc_dai *dai;
int ret;
if (!node)
......@@ -70,6 +72,19 @@ static int asoc_simple_parse_dai(struct device_node *node,
if (ret)
return ret;
/*
* Try to find from DAI args
*/
dai = snd_soc_get_dai_via_args(&args);
if (dai) {
dlc->dai_name = snd_soc_dai_name_get(dai);
dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
if (!dlc->dai_args)
return -ENOMEM;
goto parse_dai_end;
}
/*
* FIXME
*
......@@ -93,6 +108,7 @@ static int asoc_simple_parse_dai(struct device_node *node,
if (ret < 0)
return ret;
parse_dai_end:
if (is_single_link)
*is_single_link = !args.args_count;
......@@ -156,7 +172,7 @@ static int simple_parse_node(struct asoc_simple_priv *priv,
simple_parse_mclk_fs(top, np, dai_props, prefix);
ret = asoc_simple_parse_dai(np, dlc, cpu);
ret = asoc_simple_parse_dai(dev, np, dlc, cpu);
if (ret)
return ret;
......
......@@ -238,9 +238,25 @@ 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->name || dlc->of_node);
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)
......@@ -250,8 +266,52 @@ static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_compo
static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc)
{
return !dlc->dai_name;
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)
......@@ -749,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)
......@@ -758,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)
......@@ -810,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;
}
......@@ -2943,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,
......@@ -3316,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
......@@ -3386,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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment