From: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". Becuse it needs to parse each links, the code is very mysterious. Mystery code will be trouble in the future. This patch cleanup the code by using asoc_simple_card_for_each_link() which judges normal link / DPCM link. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> --- sound/soc/generic/simple-card.c | 354 +++++++++++++++++++++++----------------- 1 file changed, 201 insertions(+), 153 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b156514..b7e1520 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -33,6 +33,13 @@ struct simple_card_data { struct snd_soc_codec_conf *codec_conf; }; +struct link_dpcm { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* CPU / Codec */ +}; + #define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) @@ -180,30 +187,42 @@ 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, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe, - bool is_top_level_node) + struct link_dpcm *ld, int is_top) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, ld->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, ld->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 (ld->cpu == (np == codec)) + return 0; + + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); + + ld->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 (is_fe) { + if (ld->cpu) { int is_single_links = 0; /* BE is dummy */ @@ -216,7 +235,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->dpcm_merged_format = 1; dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[ld->dais++]; ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, &is_single_links); @@ -247,10 +266,10 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[ld->dais++]; cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; + dai_props->codec_conf = &priv->codec_conf[ld->conf++]; ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); if (ret < 0) @@ -303,53 +322,50 @@ 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, - int *dai_idx, int link_idx, - bool is_top_level_node) +static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_dpcm *ld, int is_top) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, ld->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, ld->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; - /* For single DAI link & old style of DT node */ - if (is_top_level_node) - prefix = PREFIX; + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|return + * np + */ + if (!ld->cpu || np == codec) + return 0; - snprintf(prop, sizeof(prop), "%scpu", prefix); - cpu = of_get_child_by_name(node, prop); + cpu = np; + node = of_get_parent(np); + ld->link++; - if (!cpu) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } + dev_dbg(dev, "link_of (%pOF)\n", node); + + /* For single DAI link & old style of DT node */ + if (is_top) + prefix = PREFIX; 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[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[ld->dais++]; codec_dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[ld->dais++]; ret = asoc_simple_card_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); @@ -408,7 +424,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(node); of_node_put(codec); return ret; @@ -445,18 +461,79 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, return 0; } +static int asoc_simple_card_for_each_link(struct simple_card_data *priv, + struct link_dpcm *ld, + int (*func_noml)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_dpcm *ld, int is_top), + int (*func_dpcm)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_dpcm *ld, int is_top)) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct device_node *node; + int is_top = 0; + + /* Check if it has dai-link */ + node = of_get_child_by_name(top, PREFIX "dai-link"); + if (!node) { + node = top; + is_top = 1; + } + + /* loop for all dai-link */ + do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + /* get codec */ + codec = of_get_child_by_name(node, is_top ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + /* + * It is DPCM + * if it has many CPUs, + * or has convert-xxx property + */ + if (num > 2 || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, np, codec, ld, is_top); + /* else normal sound */ + else + ret = func_noml(priv, np, codec, ld, is_top); + + if (ret < 0) + return ret; + } + + node = of_get_next_child(top, node); + } while (!is_top && node); + + return 0; +} + static int asoc_simple_card_parse_of(struct simple_card_data *priv) { 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 device_node *node; - struct device_node *np; - struct device_node *codec; - struct asoc_simple_card_data adata; - bool is_fe; - int ret, loop; - int dai_idx, link_idx, conf_idx; + struct link_dpcm ld; + int ret; if (!top) return -EINVAL; @@ -470,51 +547,27 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) return ret; /* Single/Muti DAI link(s) & New style of DT node */ - loop = 1; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = dev->of_node; - loop = 0; + memset(&ld, 0, sizeof(ld)); + for (ld.cpu = 1; ld.cpu >= 0; ld.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 = asoc_simple_card_for_each_link(priv, &ld, + asoc_simple_card_dai_link_of, + asoc_simple_card_dai_link_of_dpcm); + if (ret < 0) + return ret; } - do { - 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; - - is_fe = (np != codec); - - ret = asoc_simple_card_dai_link_of_dpcm( - top, node, np, codec, priv, - &dai_idx, link_idx++, &conf_idx, - is_fe, !loop); - if (ret < 0) - return ret; - } - } else { - ret = asoc_simple_card_dai_link_of( - top, node, priv, - &dai_idx, link_idx++, !loop); - if (ret < 0) - return ret; - } - - node = of_get_next_child(top, node); - } while (loop && node); - ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) return ret; @@ -524,17 +577,35 @@ 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, - int *link_num, - int *dais_num, - int *ccnf_num) +static int asoc_simple_card_count_noml(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_dpcm *ld, int is_top) { - struct device_node *top = dev->of_node; - struct device_node *node; - struct device_node *np; - struct asoc_simple_card_data adata; - int loop; - int num; + ld->dais++; /* CPU or Codec */ + if (np != codec) + ld->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_dpcm *ld, int is_top) +{ + ld->dais++; /* CPU or Codec */ + ld->link++; /* CPU-dummy or dummy-Codec */ + if (np == codec) + ld->conf++; + + return 0; +} + +static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, + struct link_dpcm *ld) +{ + struct device *dev = simple_priv_to_dev(priv); /* * link_num : number of links. @@ -582,36 +653,12 @@ static void asoc_simple_card_get_dais_count(struct device *dev, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - if (!top) { - (*link_num) = 1; - (*dais_num) = 2; - (*ccnf_num) = 0; - return; - } - - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = top; - loop = 0; - } - - do { - memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); + asoc_simple_card_for_each_link(priv, ld, + asoc_simple_card_count_noml, + asoc_simple_card_count_dpcm); - num = of_get_child_count(node); - (*dais_num) += num; - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - (*link_num) += num; - (*ccnf_num)++; - } else { - (*link_num)++; - } - node = of_get_next_child(top, node); - } while (loop && node); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + ld->link, ld->dais, ld->conf); } static int asoc_simple_soc_card_probe(struct snd_soc_card *card) @@ -640,7 +687,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct snd_soc_card *card; struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; + struct link_dpcm ld; int ret, i; /* Allocate the private data and the DAI link array */ @@ -648,14 +695,20 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) + card = simple_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->probe = asoc_simple_soc_card_probe; + + memset(&ld, 0, sizeof(ld)); + asoc_simple_card_get_dais_count(priv, &ld); + if (!ld.link || !ld.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); + dai_props = devm_kcalloc(dev, ld.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, ld.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, ld.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, ld.conf, sizeof(*cconf), GFP_KERNEL); if (!dai_props || !dai_link || !dais) return -ENOMEM; @@ -665,26 +718,21 @@ static int asoc_simple_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < lnum; i++) { + for (i = 0; i < ld.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; 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 = lnum; + card->dai_link = dai_link; + card->num_links = ld.link; card->codec_conf = cconf; - card->num_configs = cnum; - card->probe = asoc_simple_soc_card_probe; + card->num_configs = ld.conf; if (np && of_device_is_available(np)) { -- 2.7.4 _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel