summaryrefslogtreecommitdiff
path: root/sound/soc/generic
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/generic')
-rw-r--r--sound/soc/generic/simple-card.c210
1 files changed, 137 insertions, 73 deletions
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 3820ad719059..4987db667165 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -187,32 +187,43 @@ static void asoc_simple_card_get_conversion(struct device *dev,
of_node_put(node);
}
-static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
- struct device_node *node,
+static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv,
struct device_node *np,
struct device_node *codec,
- struct simple_card_data *priv,
struct link_info *li,
- bool is_top_level_node)
+ bool is_top)
{
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 *dai;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+ struct device_node *top = dev->of_node;
+ struct device_node *node = of_get_parent(np);
char prop[128];
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++;
+ of_node_put(node);
+
/* For single DAI link & old style of DT node */
- if (is_top_level_node)
+ if (is_top)
prefix = PREFIX;
- if (np != codec) {
+ if (li->cpu) {
int is_single_links = 0;
/* BE is dummy */
@@ -312,53 +323,47 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
return 0;
}
-static int asoc_simple_card_dai_link_of(struct device_node *top,
- struct device_node *node,
- struct simple_card_data *priv,
+static int asoc_simple_card_dai_link_of(struct simple_card_data *priv,
+ struct device_node *np,
+ struct device_node *codec,
struct link_info *li,
- bool is_top_level_node)
+ bool is_top)
{
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 device_node *top = dev->of_node;
struct device_node *cpu = NULL;
+ struct device_node *node = NULL;
struct device_node *plat = NULL;
- struct device_node *codec = 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;
+
+ cpu = np;
+ node = of_get_parent(np);
li->link++;
dev_dbg(dev, "link_of (%pOF)\n", node);
/* For single DAI link & old style of DT node */
- if (is_top_level_node)
+ if (is_top)
prefix = PREFIX;
- snprintf(prop, sizeof(prop), "%scpu", prefix);
- cpu = of_get_child_by_name(node, prop);
-
- if (!cpu) {
- ret = -EINVAL;
- dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
- goto dai_link_of_err;
- }
-
snprintf(prop, sizeof(prop), "%splat", prefix);
plat = of_get_child_by_name(node, prop);
- snprintf(prop, sizeof(prop), "%scodec", prefix);
- codec = of_get_child_by_name(node, prop);
-
- if (!codec) {
- ret = -EINVAL;
- dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
- goto dai_link_of_err;
- }
-
cpu_dai =
dai_props->cpu_dai = &priv->dais[li->dais++];
codec_dai =
@@ -421,8 +426,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *top,
asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
dai_link_of_err:
- of_node_put(cpu);
- of_node_put(codec);
+ of_node_put(node);
return ret;
}
@@ -464,9 +468,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
struct device_node *top = dev->of_node;
struct snd_soc_card *card = simple_priv_to_card(priv);
struct device_node *node;
- struct device_node *np;
- struct device_node *codec;
- struct asoc_simple_card_data adata;
struct link_info li;
int ret, loop;
@@ -483,6 +484,10 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
/* Single/Muti DAI link(s) & New style of DT node */
memset(&li, 0, sizeof(li));
+
+ /* FIXME */
+ li.cpu = 1;
+parse_loop:
loop = 1;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
@@ -491,37 +496,59 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
}
do {
+ struct asoc_simple_card_data adata;
+ struct device_node *codec;
+ struct device_node *np;
+ int num = of_get_child_count(node);
+ int ret;
+
+ codec = of_get_child_by_name(node, !loop ?
+ PREFIX "codec" : "codec");
+ if (!codec)
+ return -ENODEV;
+
+ of_node_put(codec);
+
memset(&adata, 0, sizeof(adata));
for_each_child_of_node(node, np)
asoc_simple_card_get_conversion(dev, np, &adata);
- /* DPCM */
- if (of_get_child_count(node) > 2 ||
- adata.convert_rate || adata.convert_channels) {
- for_each_child_of_node(node, np) {
- codec = of_get_child_by_name(node,
- loop ? "codec" :
- PREFIX "codec");
- if (!codec)
- return -ENODEV;
-
+ /*
+ * 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;
+ */
+
+ /* loop for all CPU/Codec node */
+ for_each_child_of_node(node, np) {
+ if (num > 2 ||
+ adata.convert_rate || adata.convert_channels) {
ret = asoc_simple_card_dai_link_of_dpcm(
- top, node, np, codec, priv,
- &li, !loop);
+ priv, np, codec, &li, !loop);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = asoc_simple_card_dai_link_of(
+ priv, np, codec, &li, !loop);
if (ret < 0)
return ret;
}
- } else {
- ret = asoc_simple_card_dai_link_of(
- top, node, priv,
- &li, !loop);
- if (ret < 0)
- return ret;
}
-
node = of_get_next_child(top, node);
} while (loop && node);
+ /* FIXME */
+ li.cpu--;
+ if (li.cpu >= 0)
+ goto parse_loop;
+
ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
return ret;
@@ -531,12 +558,39 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
return ret;
}
-static void asoc_simple_card_get_dais_count(struct device *dev,
+static int asoc_simple_card_count_noml(struct simple_card_data *priv,
+ struct device_node *np,
+ struct device_node *codec,
+ struct link_info *li, bool is_top)
+{
+ li->dais++; /* CPU or Codec */
+ if (np != codec)
+ li->link++; /* CPU-Codec */
+
+ return 0;
+}
+
+static int asoc_simple_card_count_dpcm(struct simple_card_data *priv,
+ struct device_node *np,
+ 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++;
+
+ return 0;
+}
+
+static void asoc_simple_card_get_dais_count(struct simple_card_data *priv,
struct link_info *li)
{
+ struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct device_node *node;
struct device_node *np;
+ struct device_node *codec;
struct asoc_simple_card_data adata;
int loop;
int num;
@@ -602,18 +656,28 @@ static void asoc_simple_card_get_dais_count(struct device *dev,
}
do {
+ num = of_get_child_count(node);
+
+ codec = of_get_child_by_name(node, !loop ?
+ PREFIX "codec" : "codec");
+ if (!codec)
+ return;
+
+ of_node_put(codec);
+
memset(&adata, 0, sizeof(adata));
for_each_child_of_node(node, np)
asoc_simple_card_get_conversion(dev, np, &adata);
- num = of_get_child_count(node);
- li->dais += num;
- if (num > 2 ||
- adata.convert_rate || adata.convert_channels) {
- li->link += num;
- li->conf++;
- } else {
- li->link++;
+ for_each_child_of_node(node, np) {
+ if (num > 2 ||
+ adata.convert_rate || adata.convert_channels) {
+ asoc_simple_card_count_dpcm(priv, np, codec,
+ li, !loop);
+ } else {
+ asoc_simple_card_count_noml(priv, np, codec,
+ li, !loop);
+ }
}
node = of_get_next_child(top, node);
} while (loop && node);
@@ -653,8 +717,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ card = simple_priv_to_card(priv);
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+ card->probe = asoc_simple_soc_card_probe;
+
memset(&li, 0, sizeof(li));
- asoc_simple_card_get_dais_count(dev, &li);
+ asoc_simple_card_get_dais_count(priv, &li);
if (!li.link || !li.dais)
return -EINVAL;
@@ -677,20 +746,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
dai_link[i].platform = &dai_props[i].platform;
}
- priv->dai_props = dai_props;
- priv->dai_link = dai_link;
- priv->dais = dais;
- priv->codec_conf = cconf;
+ priv->dai_props = dai_props;
+ priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
- /* Init snd_soc_card */
- card = simple_priv_to_card(priv);
- card->owner = THIS_MODULE;
- card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = li.link;
card->codec_conf = cconf;
card->num_configs = li.conf;
- card->probe = asoc_simple_soc_card_probe;
if (np && of_device_is_available(np)) {