summaryrefslogtreecommitdiff
path: root/sound/soc/generic
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/generic')
-rw-r--r--sound/soc/generic/audio-graph-card.c422
-rw-r--r--sound/soc/generic/simple-card-utils.c299
-rw-r--r--sound/soc/generic/simple-card.c272
3 files changed, 544 insertions, 449 deletions
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 8c5cdcdc8713..2c8a2fcb7922 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -22,8 +22,6 @@
#define DPCM_SELECTABLE 1
-#define PREFIX "audio-graph-card,"
-
static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -180,11 +178,11 @@ static void graph_parse_convert(struct device *dev,
struct device_node *ports = of_get_parent(port);
struct device_node *node = of_graph_get_port_parent(ep);
- asoc_simple_parse_convert(dev, top, NULL, adata);
- asoc_simple_parse_convert(dev, node, PREFIX, adata);
- asoc_simple_parse_convert(dev, ports, NULL, adata);
- asoc_simple_parse_convert(dev, port, NULL, adata);
- asoc_simple_parse_convert(dev, ep, NULL, adata);
+ asoc_simple_parse_convert(top, NULL, adata);
+ if (of_node_name_eq(ports, "ports"))
+ asoc_simple_parse_convert(ports, NULL, adata);
+ asoc_simple_parse_convert(port, NULL, adata);
+ asoc_simple_parse_convert(ep, NULL, adata);
of_node_put(port);
of_node_put(ports);
@@ -197,23 +195,85 @@ static void graph_parse_mclk_fs(struct device_node *top,
{
struct device_node *port = of_get_parent(ep);
struct device_node *ports = of_get_parent(port);
- struct device_node *node = of_graph_get_port_parent(ep);
of_property_read_u32(top, "mclk-fs", &props->mclk_fs);
- of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
+ if (of_node_name_eq(ports, "ports"))
+ of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
of_property_read_u32(port, "mclk-fs", &props->mclk_fs);
of_property_read_u32(ep, "mclk-fs", &props->mclk_fs);
of_node_put(port);
of_node_put(ports);
- of_node_put(node);
+}
+
+static int graph_parse_node(struct asoc_simple_priv *priv,
+ struct device_node *ep,
+ struct link_info *li,
+ int is_cpu)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *top = dev->of_node;
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
+ struct snd_soc_dai_link_component *dlc;
+ struct asoc_simple_dai *dai;
+ int ret, single = 0;
+
+ if (is_cpu) {
+ dlc = asoc_link_to_cpu(dai_link, 0);
+ dai = simple_props_to_dai_cpu(dai_props, 0);
+ } else {
+ dlc = asoc_link_to_codec(dai_link, 0);
+ dai = simple_props_to_dai_codec(dai_props, 0);
+ }
+
+ graph_parse_mclk_fs(top, ep, dai_props);
+
+ ret = asoc_simple_parse_dai(ep, dlc, &single);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_parse_tdm(ep, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_parse_clk(dev, ep, dai, dlc);
+ if (ret < 0)
+ return ret;
+
+ if (is_cpu)
+ asoc_simple_canonicalize_cpu(dlc, single);
+
+ return 0;
+}
+
+static int graph_link_init(struct asoc_simple_priv *priv,
+ struct device_node *cpu_ep,
+ struct device_node *codec_ep,
+ struct link_info *li,
+ char *name)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
+ int ret;
+
+ ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
+ NULL, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
+
+ dai_link->init = asoc_simple_dai_init;
+ dai_link->ops = &graph_ops;
+ if (priv->ops)
+ dai_link->ops = priv->ops;
+
+ return asoc_simple_set_dailink_name(dev, dai_link, name);
}
static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
- struct link_info *li,
- int dup_codec)
+ struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_card *card = simple_priv_to_card(priv);
@@ -223,62 +283,29 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
struct device_node *ep = li->cpu ? cpu_ep : codec_ep;
struct device_node *port;
struct device_node *ports;
- struct device_node *node;
- struct asoc_simple_dai *dai;
- struct snd_soc_dai_link_component *cpus = dai_link->cpus;
- struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+ struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
+ struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
+ char dai_name[64];
int ret;
- /*
- * Codec endpoint can be NULL for pluggable audio HW.
- * Platform DT can populate the Codec endpoint depending on the
- * plugged HW.
- */
- if (!li->cpu && !codec_ep)
- return 0;
-
- /* Do it all CPU endpoint, and 1st Codec endpoint */
- if (!li->cpu && dup_codec)
- return 0;
-
port = of_get_parent(ep);
ports = of_get_parent(port);
- node = of_graph_get_port_parent(ep);
-
- li->link++;
dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
if (li->cpu) {
- int is_single_links = 0;
-
/* Codec is dummy */
- codecs->of_node = NULL;
- codecs->dai_name = "snd-soc-dummy-dai";
- codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
- dai =
- dai_props->cpu_dai = &priv->dais[li->dais++];
-
- ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links);
+ ret = graph_parse_node(priv, cpu_ep, li, 1);
if (ret)
goto out_put_node;
- ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai);
- if (ret < 0)
- goto out_put_node;
-
- ret = asoc_simple_set_dailink_name(dev, dai_link,
- "fe.%pOFP.%s",
- cpus->of_node,
- cpus->dai_name);
- if (ret < 0)
- goto out_put_node;
-
+ snprintf(dai_name, sizeof(dai_name),
+ "fe.%pOFP.%s", cpus->of_node, cpus->dai_name);
/*
* In BE<->BE connections it is not required to create
* PCM devices at CPU end of the dai link and thus 'no_pcm'
@@ -291,81 +318,44 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
*/
if (card->component_chaining && !soc_component_is_pcm(cpus))
dai_link->no_pcm = 1;
-
- /* card->num_links includes Codec */
- asoc_simple_canonicalize_cpu(dai_link, is_single_links);
} else {
struct snd_soc_codec_conf *cconf;
/* CPU is dummy */
- cpus->of_node = NULL;
- cpus->dai_name = "snd-soc-dummy-dai";
- cpus->name = "snd-soc-dummy";
/* BE settings */
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
- dai =
- dai_props->codec_dai = &priv->dais[li->dais++];
-
- cconf =
- dai_props->codec_conf = &priv->codec_conf[li->conf++];
+ cconf = simple_props_to_codec_conf(dai_props, 0);
- ret = asoc_simple_parse_codec(ep, dai_link);
+ ret = graph_parse_node(priv, codec_ep, li, 0);
if (ret < 0)
goto out_put_node;
- ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai);
- if (ret < 0)
- goto out_put_node;
-
- ret = asoc_simple_set_dailink_name(dev, dai_link,
- "be.%pOFP.%s",
- codecs->of_node,
- codecs->dai_name);
- if (ret < 0)
- goto out_put_node;
+ snprintf(dai_name, sizeof(dai_name),
+ "be.%pOFP.%s", codecs->of_node, codecs->dai_name);
/* check "prefix" from top node */
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
"prefix");
- snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
- PREFIX "prefix");
- snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
- "prefix");
+ if (of_node_name_eq(ports, "ports"))
+ snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix");
snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
"prefix");
}
graph_parse_convert(dev, ep, &dai_props->adata);
- graph_parse_mclk_fs(top, ep, dai_props);
-
- asoc_simple_canonicalize_platform(dai_link);
-
- ret = asoc_simple_parse_tdm(ep, dai);
- if (ret)
- goto out_put_node;
-
- ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
- NULL, &dai_link->dai_fmt);
- if (ret < 0)
- goto out_put_node;
snd_soc_dai_link_set_capabilities(dai_link);
- dai_link->ops = &graph_ops;
-
- /* Use custom snd_soc_ops callbacks if available */
- if (priv->ops)
- dai_link->ops = priv->ops;
-
- dai_link->init = asoc_simple_dai_init;
+ ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
out_put_node:
+ li->link++;
+
of_node_put(ports);
of_node_put(port);
- of_node_put(node);
return ret;
}
@@ -376,70 +366,28 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv,
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
- struct device_node *top = dev->of_node;
- struct asoc_simple_dai *cpu_dai;
- struct asoc_simple_dai *codec_dai;
- int ret, single_cpu;
-
- /* Do it only CPU turn */
- if (!li->cpu)
- return 0;
+ struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
+ struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
+ char dai_name[64];
+ int ret;
dev_dbg(dev, "link_of (%pOF)\n", cpu_ep);
- li->link++;
-
- cpu_dai =
- dai_props->cpu_dai = &priv->dais[li->dais++];
- codec_dai =
- dai_props->codec_dai = &priv->dais[li->dais++];
-
- /* Factor to mclk, used in hw_params() */
- graph_parse_mclk_fs(top, cpu_ep, dai_props);
- graph_parse_mclk_fs(top, codec_ep, dai_props);
-
- ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
- NULL, &dai_link->dai_fmt);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_parse_cpu(cpu_ep, dai_link, &single_cpu);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_parse_codec(codec_ep, dai_link);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_parse_tdm(cpu_ep, cpu_dai);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_parse_tdm(codec_ep, codec_dai);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
+ ret = graph_parse_node(priv, cpu_ep, li, 1);
if (ret < 0)
return ret;
- ret = asoc_simple_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
+ ret = graph_parse_node(priv, codec_ep, li, 0);
if (ret < 0)
return ret;
- ret = asoc_simple_set_dailink_name(dev, dai_link,
- "%s-%s",
- dai_link->cpus->dai_name,
- dai_link->codecs->dai_name);
+ snprintf(dai_name, sizeof(dai_name),
+ "%s-%s", cpus->dai_name, codecs->dai_name);
+ ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
if (ret < 0)
return ret;
- dai_link->ops = &graph_ops;
- dai_link->init = asoc_simple_dai_init;
-
- asoc_simple_canonicalize_cpu(dai_link, single_cpu);
- asoc_simple_canonicalize_platform(dai_link);
+ li->link++;
return 0;
}
@@ -466,7 +414,7 @@ static inline bool parse_as_dpcm_link(struct asoc_simple_priv *priv,
return false;
}
-static int graph_for_each_link(struct asoc_simple_priv *priv,
+static int __graph_for_each_link(struct asoc_simple_priv *priv,
struct link_info *li,
int (*func_noml)(struct asoc_simple_priv *priv,
struct device_node *cpu_ep,
@@ -475,7 +423,7 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
int (*func_dpcm)(struct asoc_simple_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
- struct link_info *li, int dup_codec))
+ struct link_info *li))
{
struct of_phandle_iterator it;
struct device *dev = simple_priv_to_dev(priv);
@@ -486,7 +434,7 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
struct device_node *codec_port;
struct device_node *codec_port_old = NULL;
struct asoc_simple_data adata;
- int rc, ret;
+ int rc, ret = 0;
/* loop for all listed CPU port */
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
@@ -509,12 +457,21 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
graph_parse_convert(dev, cpu_ep, &adata);
/* check if link requires DPCM parsing */
- if (parse_as_dpcm_link(priv, codec_port, &adata))
- ret = func_dpcm(priv, cpu_ep, codec_ep, li,
- (codec_port_old == codec_port));
+ if (parse_as_dpcm_link(priv, codec_port, &adata)) {
+ /*
+ * Codec endpoint can be NULL for pluggable audio HW.
+ * Platform DT can populate the Codec endpoint depending on the
+ * plugged HW.
+ */
+ /* Do it all CPU endpoint, and 1st Codec endpoint */
+ if (li->cpu ||
+ ((codec_port_old != codec_port) && codec_ep))
+ ret = func_dpcm(priv, cpu_ep, codec_ep, li);
/* else normal sound */
- else
- ret = func_noml(priv, cpu_ep, codec_ep, li);
+ } else {
+ if (li->cpu)
+ ret = func_noml(priv, cpu_ep, codec_ep, li);
+ }
of_node_put(codec_ep);
of_node_put(codec_port);
@@ -529,24 +486,63 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
return 0;
}
-static void graph_get_dais_count(struct asoc_simple_priv *priv,
- struct link_info *li);
+static int graph_for_each_link(struct asoc_simple_priv *priv,
+ struct link_info *li,
+ int (*func_noml)(struct asoc_simple_priv *priv,
+ struct device_node *cpu_ep,
+ struct device_node *codec_ep,
+ struct link_info *li),
+ int (*func_dpcm)(struct asoc_simple_priv *priv,
+ struct device_node *cpu_ep,
+ struct device_node *codec_ep,
+ struct link_info *li))
+{
+ int ret;
+ /*
+ * Detect all CPU first, and Detect all Codec 2nd.
+ *
+ * In Normal sound case, all DAIs are detected
+ * as "CPU-Codec".
+ *
+ * In DPCM sound case,
+ * all CPUs are detected as "CPU-dummy", and
+ * all Codecs are detected as "dummy-Codec".
+ * To avoid random sub-device numbering,
+ * detect "dummy-Codec" in last;
+ */
+ for (li->cpu = 1; li->cpu >= 0; li->cpu--) {
+ ret = __graph_for_each_link(priv, li, func_noml, func_dpcm);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int graph_get_dais_count(struct asoc_simple_priv *priv,
+ struct link_info *li);
int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct link_info li;
+ struct link_info *li;
int ret;
+ li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+ if (!li)
+ return -ENOMEM;
+
card->owner = THIS_MODULE;
card->dev = dev;
- memset(&li, 0, sizeof(li));
- graph_get_dais_count(priv, &li);
- if (!li.link || !li.dais)
+ ret = graph_get_dais_count(priv, li);
+ if (ret < 0)
+ return ret;
+
+ if (!li->link)
return -EINVAL;
- ret = asoc_simple_init_priv(priv, &li);
+ ret = asoc_simple_init_priv(priv, li);
if (ret < 0)
return ret;
@@ -565,26 +561,12 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
if (ret < 0)
return ret;
- memset(&li, 0, sizeof(li));
- for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
- /*
- * Detect all CPU first, and Detect all Codec 2nd.
- *
- * In Normal sound case, all DAIs are detected
- * as "CPU-Codec".
- *
- * In DPCM sound case,
- * all CPUs are detected as "CPU-dummy", and
- * all Codecs are detected as "dummy-Codec".
- * To avoid random sub-device numbering,
- * detect "dummy-Codec" in last;
- */
- ret = graph_for_each_link(priv, &li,
- graph_dai_link_of,
- graph_dai_link_of_dpcm);
- if (ret < 0)
- goto err;
- }
+ memset(li, 0, sizeof(*li));
+ ret = graph_for_each_link(priv, li,
+ graph_dai_link_of,
+ graph_dai_link_of_dpcm);
+ if (ret < 0)
+ goto err;
ret = asoc_simple_parse_card_name(card, NULL);
if (ret < 0)
@@ -598,6 +580,7 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
if (ret < 0)
goto err;
+ devm_kfree(dev, li);
return 0;
err:
@@ -617,8 +600,15 @@ static int graph_count_noml(struct asoc_simple_priv *priv,
{
struct device *dev = simple_priv_to_dev(priv);
+ if (li->link >= SNDRV_MAX_LINKS) {
+ dev_err(dev, "too many links\n");
+ return -EINVAL;
+ }
+
+ li->num[li->link].cpus = 1;
+ li->num[li->link].codecs = 1;
+
li->link += 1; /* 1xCPU-Codec */
- li->dais += 2; /* 1xCPU + 1xCodec */
dev_dbg(dev, "Count As Normal\n");
@@ -628,18 +618,23 @@ static int graph_count_noml(struct asoc_simple_priv *priv,
static int graph_count_dpcm(struct asoc_simple_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
- struct link_info *li,
- int dup_codec)
+ struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
- li->link++; /* 1xCPU-dummy */
- li->dais++; /* 1xCPU */
+ if (li->link >= SNDRV_MAX_LINKS) {
+ dev_err(dev, "too many links\n");
+ return -EINVAL;
+ }
+
+ if (li->cpu) {
+ li->num[li->link].cpus = 1;
+
+ li->link++; /* 1xCPU-dummy */
+ } else {
+ li->num[li->link].codecs = 1;
- if (!dup_codec && codec_ep) {
li->link++; /* 1xdummy-Codec */
- li->conf++; /* 1xdummy-Codec */
- li->dais++; /* 1xCodec */
}
dev_dbg(dev, "Count As DPCM\n");
@@ -647,11 +642,9 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv,
return 0;
}
-static void graph_get_dais_count(struct asoc_simple_priv *priv,
- struct link_info *li)
+static int graph_get_dais_count(struct asoc_simple_priv *priv,
+ struct link_info *li)
{
- struct device *dev = simple_priv_to_dev(priv);
-
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
@@ -698,30 +691,11 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv,
* => 4 DAIs = 2xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*/
- graph_for_each_link(priv, li,
- graph_count_noml,
- graph_count_dpcm);
- dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
- li->link, li->dais, li->conf);
+ return graph_for_each_link(priv, li,
+ graph_count_noml,
+ graph_count_dpcm);
}
-int audio_graph_card_probe(struct snd_soc_card *card)
-{
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
- int ret;
-
- ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(audio_graph_card_probe);
-
static int graph_probe(struct platform_device *pdev)
{
struct asoc_simple_priv *priv;
@@ -736,7 +710,7 @@ static int graph_probe(struct platform_device *pdev)
card = simple_priv_to_card(priv);
card->dapm_widgets = graph_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets);
- card->probe = audio_graph_card_probe;
+ card->probe = asoc_graph_card_probe;
if (of_device_get_match_data(dev))
priv->dpcm_selectable = 1;
@@ -744,14 +718,6 @@ static int graph_probe(struct platform_device *pdev)
return audio_graph_parse_of(priv, dev);
}
-int audio_graph_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- return asoc_simple_clean_reference(card);
-}
-EXPORT_SYMBOL_GPL(audio_graph_remove);
-
static const struct of_device_id graph_of_match[] = {
{ .compatible = "audio-graph-card", },
{ .compatible = "audio-graph-scu-card",
@@ -767,7 +733,7 @@ static struct platform_driver graph_card = {
.of_match_table = graph_of_match,
},
.probe = graph_probe,
- .remove = audio_graph_remove,
+ .remove = asoc_simple_remove,
};
module_platform_driver(graph_card);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 6cada4c1e283..fa1247f0dda1 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -32,8 +32,7 @@ void asoc_simple_convert_fixup(struct asoc_simple_data *data,
}
EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
-void asoc_simple_parse_convert(struct device *dev,
- struct device_node *np,
+void asoc_simple_parse_convert(struct device_node *np,
char *prefix,
struct asoc_simple_data *data)
{
@@ -195,17 +194,37 @@ int asoc_simple_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+ struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
+ struct asoc_simple_dai *dai;
+ int i1, i2, i;
int ret;
- ret = asoc_simple_clk_enable(dai_props->cpu_dai);
- if (ret)
- return ret;
+ for_each_prop_dai_cpu(props, i1, dai) {
+ ret = asoc_simple_clk_enable(dai);
+ if (ret)
+ goto cpu_err;
+ }
- ret = asoc_simple_clk_enable(dai_props->codec_dai);
- if (ret)
- asoc_simple_clk_disable(dai_props->cpu_dai);
+ for_each_prop_dai_codec(props, i2, dai) {
+ ret = asoc_simple_clk_enable(dai);
+ if (ret)
+ goto codec_err;
+ }
+
+ return 0;
+codec_err:
+ for_each_prop_dai_codec(props, i, dai) {
+ if (i >= i2)
+ break;
+ asoc_simple_clk_disable(dai);
+ }
+cpu_err:
+ for_each_prop_dai_cpu(props, i, dai) {
+ if (i >= i1)
+ break;
+ asoc_simple_clk_disable(dai);
+ }
return ret;
}
EXPORT_SYMBOL_GPL(asoc_simple_startup);
@@ -216,17 +235,19 @@ void asoc_simple_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *dai_props =
- simple_priv_to_props(priv, rtd->num);
+ struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
+ struct asoc_simple_dai *dai;
+ int i;
- if (dai_props->mclk_fs) {
+ if (props->mclk_fs) {
snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN);
snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT);
}
- asoc_simple_clk_disable(dai_props->cpu_dai);
-
- asoc_simple_clk_disable(dai_props->codec_dai);
+ for_each_prop_dai_cpu(props, i, dai)
+ asoc_simple_clk_disable(dai);
+ for_each_prop_dai_codec(props, i, dai)
+ asoc_simple_clk_disable(dai);
}
EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
@@ -249,41 +270,41 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct asoc_simple_dai *pdai;
+ struct snd_soc_dai *sdai;
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *dai_props =
- simple_priv_to_props(priv, rtd->num);
+ struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
unsigned int mclk, mclk_fs = 0;
- int ret = 0;
+ int i, ret;
- if (dai_props->mclk_fs)
- mclk_fs = dai_props->mclk_fs;
+ if (props->mclk_fs)
+ mclk_fs = props->mclk_fs;
if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;
- ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
- if (ret && ret != -ENOTSUPP)
- goto err;
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
- SND_SOC_CLOCK_OUT);
- if (ret && ret != -ENOTSUPP)
- goto err;
+ for_each_prop_dai_codec(props, i, pdai) {
+ ret = asoc_simple_set_clk_rate(pdai, mclk);
+ if (ret < 0)
+ return ret;
+ }
+ for_each_prop_dai_cpu(props, i, pdai) {
+ ret = asoc_simple_set_clk_rate(pdai, mclk);
+ if (ret < 0)
+ return ret;
+ }
+ for_each_rtd_codec_dais(rtd, i, sdai) {
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+ for_each_rtd_cpu_dais(rtd, i, sdai) {
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
}
return 0;
-err:
- return ret;
}
EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
@@ -378,20 +399,22 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd,
int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
- int ret;
-
- ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, 0),
- dai_props->codec_dai);
- if (ret < 0)
- return ret;
+ struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
+ struct asoc_simple_dai *dai;
+ int i, ret;
- ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, 0),
- dai_props->cpu_dai);
- if (ret < 0)
- return ret;
+ for_each_prop_dai_codec(props, i, dai) {
+ ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
+ if (ret < 0)
+ return ret;
+ }
+ for_each_prop_dai_cpu(props, i, dai) {
+ ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
+ if (ret < 0)
+ return ret;
+ }
- ret = asoc_simple_init_dai_link_params(rtd, dai_props);
+ ret = asoc_simple_init_dai_link_params(rtd, props);
if (ret < 0)
return ret;
@@ -399,22 +422,16 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
}
EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
-void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link)
+void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
+ struct snd_soc_dai_link_component *cpus)
{
/* Assumes platform == cpu */
- if (!dai_link->platforms->of_node)
- dai_link->platforms->of_node = dai_link->cpus->of_node;
-
- /*
- * DPCM BE can be no platform.
- * Alloced memory will be waste, but not leak.
- */
- if (!dai_link->platforms->of_node)
- dai_link->num_platforms = 0;
+ if (!platforms->of_node)
+ platforms->of_node = cpus->of_node;
}
EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
-void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
+void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
int is_single_links)
{
/*
@@ -427,18 +444,22 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
* fmt_multiple_name()
*/
if (is_single_links)
- dai_link->cpus->dai_name = NULL;
+ cpus->dai_name = NULL;
}
EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
int asoc_simple_clean_reference(struct snd_soc_card *card)
{
struct snd_soc_dai_link *dai_link;
- int i;
+ struct snd_soc_dai_link_component *cpu;
+ struct snd_soc_dai_link_component *codec;
+ int i, j;
for_each_card_prelinks(card, i, dai_link) {
- of_node_put(dai_link->cpus->of_node);
- of_node_put(dai_link->codecs->of_node);
+ for_each_link_cpus(dai_link, j, cpu)
+ of_node_put(cpu->of_node);
+ for_each_link_codecs(dai_link, j, codec)
+ of_node_put(codec->of_node);
}
return 0;
}
@@ -602,54 +623,148 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
struct asoc_simple_dai *dais;
+ struct snd_soc_dai_link_component *dlcs;
struct snd_soc_codec_conf *cconf = NULL;
- int i;
+ int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL);
- dais = devm_kcalloc(dev, li->dais, sizeof(*dais), GFP_KERNEL);
- if (!dai_props || !dai_link || !dais)
+ if (!dai_props || !dai_link)
return -ENOMEM;
- if (li->conf) {
- cconf = devm_kcalloc(dev, li->conf, sizeof(*cconf), GFP_KERNEL);
- if (!cconf)
- return -ENOMEM;
- }
-
/*
- * Use snd_soc_dai_link_component instead of legacy style
- * It is codec only. but cpu/platform will be supported in the future.
- * see
- * soc-core.c :: snd_soc_init_multicodec()
- *
- * "platform" might be removed
- * see
- * simple-card-utils.c :: asoc_simple_canonicalize_platform()
+ * dais (= CPU+Codec)
+ * dlcs (= CPU+Codec+Platform)
*/
for (i = 0; i < li->link; i++) {
- dai_link[i].cpus = &dai_props[i].cpus;
- dai_link[i].num_cpus = 1;
- dai_link[i].codecs = &dai_props[i].codecs;
- dai_link[i].num_codecs = 1;
- dai_link[i].platforms = &dai_props[i].platforms;
- dai_link[i].num_platforms = 1;
+ int cc = li->num[i].cpus + li->num[i].codecs;
+
+ dai_num += cc;
+ dlc_num += cc + li->num[i].platforms;
+
+ if (!li->num[i].cpus)
+ cnf_num += li->num[i].codecs;
}
+ dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
+ dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dai_props), GFP_KERNEL);
+ if (!dais || !dlcs)
+ return -ENOMEM;
+
+ if (cnf_num) {
+ cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
+ if (!cconf)
+ return -ENOMEM;
+ }
+
+ dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
+ li->link, dai_num, cnf_num);
+
+ /* dummy CPU/Codec */
+ priv->dummy.of_node = NULL;
+ priv->dummy.dai_name = "snd-soc-dummy-dai";
+ priv->dummy.name = "snd-soc-dummy";
+
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
+ priv->dlcs = dlcs;
priv->codec_conf = cconf;
card->dai_link = priv->dai_link;
card->num_links = li->link;
card->codec_conf = cconf;
- card->num_configs = li->conf;
+ card->num_configs = cnf_num;
+
+ for (i = 0; i < li->link; i++) {
+ if (li->num[i].cpus) {
+ /* Normal CPU */
+ dai_props[i].cpus =
+ dai_link[i].cpus = dlcs;
+ dai_props[i].num.cpus =
+ dai_link[i].num_cpus = li->num[i].cpus;
+ dai_props[i].cpu_dai = dais;
+
+ dlcs += li->num[i].cpus;
+ dais += li->num[i].cpus;
+ } else {
+ /* DPCM Be's CPU = dummy */
+ dai_props[i].cpus =
+ dai_link[i].cpus = &priv->dummy;
+ dai_props[i].num.cpus =
+ dai_link[i].num_cpus = 1;
+ }
+
+ if (li->num[i].codecs) {
+ /* Normal Codec */
+ dai_props[i].codecs =
+ dai_link[i].codecs = dlcs;
+ dai_props[i].num.codecs =
+ dai_link[i].num_codecs = li->num[i].codecs;
+ dai_props[i].codec_dai = dais;
+
+ dlcs += li->num[i].codecs;
+ dais += li->num[i].codecs;
+
+ if (!li->num[i].cpus) {
+ /* DPCM Be's Codec */
+ dai_props[i].codec_conf = cconf;
+ cconf += li->num[i].codecs;
+ }
+ } else {
+ /* DPCM Fe's Codec = dummy */
+ dai_props[i].codecs =
+ dai_link[i].codecs = &priv->dummy;
+ dai_props[i].num.codecs =
+ dai_link[i].num_codecs = 1;
+ }
+
+ if (li->num[i].platforms) {
+ /* Have Platform */
+ dai_props[i].platforms =
+ dai_link[i].platforms = dlcs;
+ dai_props[i].num.platforms =
+ dai_link[i].num_platforms = li->num[i].platforms;
+
+ dlcs += li->num[i].platforms;
+ } else {
+ /* Doesn't have Platform */
+ dai_props[i].platforms =
+ dai_link[i].platforms = NULL;
+ dai_props[i].num.platforms =
+ dai_link[i].num_platforms = 0;
+ }
+ }
return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
+int asoc_simple_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ return asoc_simple_clean_reference(card);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_remove);
+
+int asoc_graph_card_probe(struct snd_soc_card *card)
+{
+ struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
+
/* Module information */
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 75365c7bb393..a1373be4558f 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -84,10 +84,10 @@ static void simple_parse_convert(struct device *dev,
struct device_node *top = dev->of_node;
struct device_node *node = of_get_parent(np);
- asoc_simple_parse_convert(dev, top, PREFIX, adata);
- asoc_simple_parse_convert(dev, node, PREFIX, adata);
- asoc_simple_parse_convert(dev, node, NULL, adata);
- asoc_simple_parse_convert(dev, np, NULL, adata);
+ asoc_simple_parse_convert(top, PREFIX, adata);
+ asoc_simple_parse_convert(node, PREFIX, adata);
+ asoc_simple_parse_convert(node, NULL, adata);
+ asoc_simple_parse_convert(np, NULL, adata);
of_node_put(node);
}
@@ -122,22 +122,14 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
struct asoc_simple_dai *dai;
- struct snd_soc_dai_link_component *cpus = dai_link->cpus;
- struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+ struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
+ struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
+ struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
struct device_node *top = dev->of_node;
struct device_node *node = of_get_parent(np);
char *prefix = "";
int ret;
- /*
- * |CPU |Codec : turn
- * CPU |Pass |return
- * Codec |return|Pass
- * np
- */
- if (li->cpu == (np == codec))
- return 0;
-
dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
li->link++;
@@ -150,22 +142,18 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
int is_single_links = 0;
/* Codec is dummy */
- codecs->of_node = NULL;
- codecs->dai_name = "snd-soc-dummy-dai";
- codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
- dai =
- dai_props->cpu_dai = &priv->dais[li->dais++];
+ dai = simple_props_to_dai_cpu(dai_props, 0);
- ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links);
+ ret = asoc_simple_parse_dai(np, cpus, &is_single_links);
if (ret)
goto out_put_node;
- ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
+ ret = asoc_simple_parse_clk(dev, np, dai, cpus);
if (ret < 0)
goto out_put_node;
@@ -175,30 +163,25 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
if (ret < 0)
goto out_put_node;
- asoc_simple_canonicalize_cpu(dai_link, is_single_links);
+ asoc_simple_canonicalize_cpu(cpus, is_single_links);
+ asoc_simple_canonicalize_platform(platforms, cpus);
} else {
struct snd_soc_codec_conf *cconf;
/* CPU is dummy */
- cpus->of_node = NULL;
- cpus->dai_name = "snd-soc-dummy-dai";
- cpus->name = "snd-soc-dummy";
/* BE settings */
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
- dai =
- dai_props->codec_dai = &priv->dais[li->dais++];
+ dai = simple_props_to_dai_codec(dai_props, 0);
+ cconf = simple_props_to_codec_conf(dai_props, 0);
- cconf =
- dai_props->codec_conf = &priv->codec_conf[li->conf++];
-
- ret = asoc_simple_parse_codec(np, dai_link);
+ ret = asoc_simple_parse_dai(np, codecs, NULL);
if (ret < 0)
goto out_put_node;
- ret = asoc_simple_parse_clk_codec(dev, np, dai_link, dai);
+ ret = asoc_simple_parse_clk(dev, np, dai, codecs);
if (ret < 0)
goto out_put_node;
@@ -220,8 +203,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
simple_parse_convert(dev, np, &dai_props->adata);
simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
- asoc_simple_canonicalize_platform(dai_link);
-
ret = asoc_simple_parse_tdm(np, dai);
if (ret)
goto out_put_node;
@@ -250,24 +231,18 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
- struct asoc_simple_dai *cpu_dai;
- struct asoc_simple_dai *codec_dai;
+ struct asoc_simple_dai *cpu_dai = simple_props_to_dai_cpu(dai_props, 0);
+ struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0);
+ struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
+ struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
+ struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
struct device_node *top = dev->of_node;
struct device_node *cpu = NULL;
struct device_node *node = NULL;
struct device_node *plat = NULL;
char prop[128];
char *prefix = "";
- int ret, single_cpu;
-
- /*
- * |CPU |Codec : turn
- * CPU |Pass |return
- * Codec |return|return
- * np
- */
- if (!li->cpu || np == codec)
- return 0;
+ int ret, single_cpu = 0;
cpu = np;
node = of_get_parent(np);
@@ -282,11 +257,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
snprintf(prop, sizeof(prop), "%splat", prefix);
plat = of_get_child_by_name(node, prop);
- cpu_dai =
- dai_props->cpu_dai = &priv->dais[li->dais++];
- codec_dai =
- dai_props->codec_dai = &priv->dais[li->dais++];
-
ret = asoc_simple_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
@@ -294,15 +264,15 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix);
- ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
+ ret = asoc_simple_parse_dai(cpu, cpus, &single_cpu);
if (ret < 0)
goto dai_link_of_err;
- ret = asoc_simple_parse_codec(codec, dai_link);
+ ret = asoc_simple_parse_dai(codec, codecs, NULL);
if (ret < 0)
goto dai_link_of_err;
- ret = asoc_simple_parse_platform(plat, dai_link);
+ ret = asoc_simple_parse_dai(plat, platforms, NULL);
if (ret < 0)
goto dai_link_of_err;
@@ -314,26 +284,26 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
if (ret < 0)
goto dai_link_of_err;
- ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
+ ret = asoc_simple_parse_clk(dev, cpu, cpu_dai, cpus);
if (ret < 0)
goto dai_link_of_err;
- ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
+ ret = asoc_simple_parse_clk(dev, codec, codec_dai, codecs);
if (ret < 0)
goto dai_link_of_err;
ret = asoc_simple_set_dailink_name(dev, dai_link,
"%s-%s",
- dai_link->cpus->dai_name,
- dai_link->codecs->dai_name);
+ cpus->dai_name,
+ codecs->dai_name);
if (ret < 0)
goto dai_link_of_err;
dai_link->ops = &simple_ops;
dai_link->init = asoc_simple_dai_init;
- asoc_simple_canonicalize_cpu(dai_link, single_cpu);
- asoc_simple_canonicalize_platform(dai_link);
+ asoc_simple_canonicalize_cpu(cpus, single_cpu);
+ asoc_simple_canonicalize_platform(platforms, cpus);
dai_link_of_err:
of_node_put(plat);
@@ -342,7 +312,7 @@ dai_link_of_err:
return ret;
}
-static int simple_for_each_link(struct asoc_simple_priv *priv,
+static int __simple_for_each_link(struct asoc_simple_priv *priv,
struct link_info *li,
int (*func_noml)(struct asoc_simple_priv *priv,
struct device_node *np,
@@ -402,11 +372,26 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
*/
if (dpcm_selectable &&
(num > 2 ||
- adata.convert_rate || adata.convert_channels))
- ret = func_dpcm(priv, np, codec, li, is_top);
+ adata.convert_rate || adata.convert_channels)) {
+ /*
+ * np
+ * |1(CPU)|0(Codec) li->cpu
+ * CPU |Pass |return
+ * Codec |return|Pass
+ */
+ if (li->cpu != (np == codec))
+ ret = func_dpcm(priv, np, codec, li, is_top);
/* else normal sound */
- else
- ret = func_noml(priv, np, codec, li, is_top);
+ } else {
+ /*
+ * np
+ * |1(CPU)|0(Codec) li->cpu
+ * CPU |Pass |return
+ * Codec |return|return
+ */
+ if (li->cpu && (np != codec))
+ ret = func_noml(priv, np, codec, li, is_top);
+ }
if (ret < 0) {
of_node_put(codec);
@@ -424,16 +409,43 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
return ret;
}
-static int simple_parse_of(struct asoc_simple_priv *priv)
+static int simple_for_each_link(struct asoc_simple_priv *priv,
+ struct link_info *li,
+ int (*func_noml)(struct asoc_simple_priv *priv,
+ struct device_node *np,
+ struct device_node *codec,
+ struct link_info *li, bool is_top),
+ int (*func_dpcm)(struct asoc_simple_priv *priv,
+ struct device_node *np,
+ struct device_node *codec,
+ struct link_info *li, bool is_top))
{
- struct device *dev = simple_priv_to_dev(priv);
- struct device_node *top = dev->of_node;
- struct snd_soc_card *card = simple_priv_to_card(priv);
- struct link_info li;
int ret;
+ /*
+ * Detect all CPU first, and Detect all Codec 2nd.
+ *
+ * In Normal sound case, all DAIs are detected
+ * as "CPU-Codec".
+ *
+ * In DPCM sound case,
+ * all CPUs are detected as "CPU-dummy", and
+ * all Codecs are detected as "dummy-Codec".
+ * To avoid random sub-device numbering,
+ * detect "dummy-Codec" in last;
+ */
+ for (li->cpu = 1; li->cpu >= 0; li->cpu--) {
+ ret = __simple_for_each_link(priv, li, func_noml, func_dpcm);
+ if (ret < 0)
+ break;
+ }
- if (!top)
- return -EINVAL;
+ return ret;
+}
+
+static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
+{
+ struct snd_soc_card *card = simple_priv_to_card(priv);
+ int ret;
ret = asoc_simple_parse_widgets(card, PREFIX);
if (ret < 0)
@@ -448,26 +460,12 @@ static int simple_parse_of(struct asoc_simple_priv *priv)
return ret;
/* Single/Muti DAI link(s) & New style of DT node */
- memset(&li, 0, sizeof(li));
- for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
- /*
- * Detect all CPU first, and Detect all Codec 2nd.
- *
- * In Normal sound case, all DAIs are detected
- * as "CPU-Codec".
- *
- * In DPCM sound case,
- * all CPUs are detected as "CPU-dummy", and
- * all Codecs are detected as "dummy-Codec".
- * To avoid random sub-device numbering,
- * detect "dummy-Codec" in last;
- */
- ret = simple_for_each_link(priv, &li,
- simple_dai_link_of,
- simple_dai_link_of_dpcm);
- if (ret < 0)
- return ret;
- }
+ memset(li, 0, sizeof(*li));
+ ret = simple_for_each_link(priv, li,
+ simple_dai_link_of,
+ simple_dai_link_of_dpcm);
+ if (ret < 0)
+ return ret;
ret = asoc_simple_parse_card_name(card, PREFIX);
if (ret < 0)
@@ -483,9 +481,18 @@ static int simple_count_noml(struct asoc_simple_priv *priv,
struct device_node *codec,
struct link_info *li, bool is_top)
{
- li->dais++; /* CPU or Codec */
- if (np != codec)
- li->link++; /* CPU-Codec */
+ if (li->link >= SNDRV_MAX_LINKS) {
+ struct device *dev = simple_priv_to_dev(priv);
+
+ dev_err(dev, "too many links\n");
+ return -EINVAL;
+ }
+
+ li->num[li->link].cpus = 1;
+ li->num[li->link].codecs = 1;
+ li->num[li->link].platforms = 1;
+
+ li->link += 1;
return 0;
}
@@ -495,16 +502,29 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv,
struct device_node *codec,
struct link_info *li, bool is_top)
{
- li->dais++; /* CPU or Codec */
- li->link++; /* CPU-dummy or dummy-Codec */
- if (np == codec)
- li->conf++;
+ if (li->link >= SNDRV_MAX_LINKS) {
+ struct device *dev = simple_priv_to_dev(priv);
+
+ dev_err(dev, "too many links\n");
+ return -EINVAL;
+ }
+
+ if (li->cpu) {
+ li->num[li->link].cpus = 1;
+ li->num[li->link].platforms = 1;
+
+ li->link++; /* CPU-dummy */
+ } else {
+ li->num[li->link].codecs = 1;
+
+ li->link++; /* dummy-Codec */
+ }
return 0;
}
-static void simple_get_dais_count(struct asoc_simple_priv *priv,
- struct link_info *li)
+static int simple_get_dais_count(struct asoc_simple_priv *priv,
+ struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
@@ -556,18 +576,17 @@ static void simple_get_dais_count(struct asoc_simple_priv *priv,
* => 1 ccnf = 1xdummy-Codec
*/
if (!top) {
+ li->num[0].cpus = 1;
+ li->num[0].codecs = 1;
+ li->num[0].platforms = 1;
+
li->link = 1;
- li->dais = 2;
- li->conf = 0;
- return;
+ return 0;
}
- simple_for_each_link(priv, li,
- simple_count_noml,
- simple_count_dpcm);
-
- dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
- li->link, li->dais, li->conf);
+ return simple_for_each_link(priv, li,
+ simple_count_noml,
+ simple_count_dpcm);
}
static int simple_soc_probe(struct snd_soc_card *card)
@@ -592,7 +611,7 @@ static int asoc_simple_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct snd_soc_card *card;
- struct link_info li;
+ struct link_info *li;
int ret;
/* Allocate the private data and the DAI link array */
@@ -605,18 +624,24 @@ static int asoc_simple_probe(struct platform_device *pdev)
card->dev = dev;
card->probe = simple_soc_probe;
- memset(&li, 0, sizeof(li));
- simple_get_dais_count(priv, &li);
- if (!li.link || !li.dais)
+ li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+ if (!li)
+ return -ENOMEM;
+
+ ret = simple_get_dais_count(priv, li);
+ if (ret < 0)
+ return ret;
+
+ if (!li->link)
return -EINVAL;
- ret = asoc_simple_init_priv(priv, &li);
+ ret = asoc_simple_init_priv(priv, li);
if (ret < 0)
return ret;
if (np && of_device_is_available(np)) {
- ret = simple_parse_of(priv);
+ ret = simple_parse_of(priv, li);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "parse error %d\n", ret);
@@ -631,8 +656,6 @@ static int asoc_simple_probe(struct platform_device *pdev)
struct snd_soc_dai_link *dai_link = priv->dai_link;
struct simple_dai_props *dai_props = priv->dai_props;
- int dai_idx = 0;
-
cinfo = dev->platform_data;
if (!cinfo) {
dev_err(dev, "no info for asoc-simple-card\n");
@@ -648,9 +671,6 @@ static int asoc_simple_probe(struct platform_device *pdev)
return -EINVAL;
}
- dai_props->cpu_dai = &priv->dais[dai_idx++];
- dai_props->codec_dai = &priv->dais[dai_idx++];
-
cpus = dai_link->cpus;
cpus->dai_name = cinfo->cpu_dai.name;
@@ -680,6 +700,7 @@ static int asoc_simple_probe(struct platform_device *pdev)
if (ret < 0)
goto err;
+ devm_kfree(dev, li);
return 0;
err:
asoc_simple_clean_reference(card);
@@ -687,13 +708,6 @@ err:
return ret;
}
-static int asoc_simple_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- return asoc_simple_clean_reference(card);
-}
-
static const struct of_device_id simple_of_match[] = {
{ .compatible = "simple-audio-card", },
{ .compatible = "simple-scu-audio-card",