diff options
Diffstat (limited to 'sound/soc/generic/simple-card.c')
-rw-r--r-- | sound/soc/generic/simple-card.c | 272 |
1 files changed, 143 insertions, 129 deletions
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", |