summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2018-12-13 21:35:10 -0500
committerMark Brown <broonie@kernel.org>2018-12-14 06:48:12 -0500
commitda215354eb55c382d3d5c426ea0e9aa7ef7c10e1 (patch)
treea0b5c9a9c60298a8b33c15aed97e0c5ef796ff84 /sound
parentc4e8ebb9f2624da8302b6683ecb5ead7108ccb79 (diff)
ASoC: simple-card: merge simple-scu-card
simple-card and simple-scu-card are very similar driver, but the former is supporting normal sound card, the latter is supporting DPCM sound card. We couldn't use normal sound and DPCM sound in same time by one sound card. This patch merges both sound card into simple-card. Now we can use both feature on same driver. simple-card is now supporting .compatible = "simple-scu-audio-card". Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/generic/Kconfig1
-rw-r--r--sound/soc/generic/simple-card.c329
2 files changed, 284 insertions, 46 deletions
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index 5395782424b4..92c2cf06f40a 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD
6 select SND_SIMPLE_CARD_UTILS 6 select SND_SIMPLE_CARD_UTILS
7 help 7 help
8 This option enables generic simple sound card support 8 This option enables generic simple sound card support
9 It also support DPCM of multi CPU single Codec ststem.
9 10
10config SND_SIMPLE_SCU_CARD 11config SND_SIMPLE_SCU_CARD
11 tristate "ASoC Simple SCU sound card support" 12 tristate "ASoC Simple SCU sound card support"
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 93d68161f953..c93f2e7dec4b 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -22,6 +22,8 @@ struct simple_card_data {
22 struct asoc_simple_dai *codec_dai; 22 struct asoc_simple_dai *codec_dai;
23 struct snd_soc_dai_link_component codecs; /* single codec */ 23 struct snd_soc_dai_link_component codecs; /* single codec */
24 struct snd_soc_dai_link_component platform; 24 struct snd_soc_dai_link_component platform;
25 struct asoc_simple_card_data adata;
26 struct snd_soc_codec_conf *codec_conf;
25 unsigned int mclk_fs; 27 unsigned int mclk_fs;
26 } *dai_props; 28 } *dai_props;
27 unsigned int mclk_fs; 29 unsigned int mclk_fs;
@@ -29,6 +31,8 @@ struct simple_card_data {
29 struct asoc_simple_jack mic_jack; 31 struct asoc_simple_jack mic_jack;
30 struct snd_soc_dai_link *dai_link; 32 struct snd_soc_dai_link *dai_link;
31 struct asoc_simple_dai *dais; 33 struct asoc_simple_dai *dais;
34 struct asoc_simple_card_data adata;
35 struct snd_soc_codec_conf *codec_conf;
32}; 36};
33 37
34#define simple_priv_to_card(priv) (&(priv)->snd_card) 38#define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -74,6 +78,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
74static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, 78static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
75 unsigned long rate) 79 unsigned long rate)
76{ 80{
81 if (!simple_dai)
82 return 0;
83
77 if (!simple_dai->clk) 84 if (!simple_dai->clk)
78 return 0; 85 return 0;
79 86
@@ -151,6 +158,141 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
151 return 0; 158 return 0;
152} 159}
153 160
161static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
162 struct snd_pcm_hw_params *params)
163{
164 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
165 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
166
167 asoc_simple_card_convert_fixup(&dai_props->adata, params);
168
169 /* overwrite by top level adata if exist */
170 asoc_simple_card_convert_fixup(&priv->adata, params);
171
172 return 0;
173}
174
175static int asoc_simple_card_dai_link_of_dpcm(struct device_node *node,
176 struct device_node *np,
177 struct device_node *codec,
178 struct simple_card_data *priv,
179 int *dai_idx, int link_idx,
180 int *conf_idx, int is_fe,
181 bool is_top_level_node)
182{
183 struct device *dev = simple_priv_to_dev(priv);
184 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
185 struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
186 struct snd_soc_card *card = simple_priv_to_card(priv);
187 struct asoc_simple_dai *dai;
188 char *prefix = "";
189 int ret;
190
191 /* For single DAI link & old style of DT node */
192 if (is_top_level_node)
193 prefix = PREFIX;
194
195 if (is_fe) {
196 int is_single_links = 0;
197 struct snd_soc_dai_link_component *codecs;
198
199 /* BE is dummy */
200 codecs = dai_link->codecs;
201 codecs->of_node = NULL;
202 codecs->dai_name = "snd-soc-dummy-dai";
203 codecs->name = "snd-soc-dummy";
204
205 /* FE settings */
206 dai_link->dynamic = 1;
207 dai_link->dpcm_merged_format = 1;
208
209 dai =
210 dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
211
212 ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
213 &is_single_links);
214 if (ret)
215 return ret;
216
217 ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
218 if (ret < 0)
219 return ret;
220
221 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
222 "fe.%s",
223 dai_link->cpu_dai_name);
224 if (ret < 0)
225 return ret;
226
227 asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
228 } else {
229 struct snd_soc_codec_conf *cconf;
230
231 /* FE is dummy */
232 dai_link->cpu_of_node = NULL;
233 dai_link->cpu_dai_name = "snd-soc-dummy-dai";
234 dai_link->cpu_name = "snd-soc-dummy";
235
236 /* BE settings */
237 dai_link->no_pcm = 1;
238 dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
239
240 dai =
241 dai_props->codec_dai = &priv->dais[(*dai_idx)++];
242
243 cconf =
244 dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
245
246 ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
247 if (ret < 0)
248 return ret;
249
250 ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
251 if (ret < 0)
252 return ret;
253
254 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
255 "be.%s",
256 dai_link->codecs->dai_name);
257 if (ret < 0)
258 return ret;
259
260 /* check "prefix" from top node */
261 snd_soc_of_parse_audio_prefix(card, cconf,
262 dai_link->codecs->of_node,
263 PREFIX "prefix");
264 /* check "prefix" from each node if top doesn't have */
265 if (!cconf->of_node)
266 snd_soc_of_parse_node_prefix(np, cconf,
267 dai_link->codecs->of_node,
268 "prefix");
269 }
270
271 asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
272
273 ret = asoc_simple_card_of_parse_tdm(np, dai);
274 if (ret)
275 return ret;
276
277 ret = asoc_simple_card_canonicalize_dailink(dai_link);
278 if (ret < 0)
279 return ret;
280
281 of_property_read_u32(np, "mclk-fs", &dai_props->mclk_fs);
282
283 ret = asoc_simple_card_parse_daifmt(dev, node, codec,
284 prefix, &dai_link->dai_fmt);
285 if (ret < 0)
286 return ret;
287
288 dai_link->dpcm_playback = 1;
289 dai_link->dpcm_capture = 1;
290 dai_link->ops = &asoc_simple_card_ops;
291 dai_link->init = asoc_simple_card_dai_init;
292
293 return 0;
294}
295
154static int asoc_simple_card_dai_link_of(struct device_node *node, 296static int asoc_simple_card_dai_link_of(struct device_node *node,
155 struct simple_card_data *priv, 297 struct simple_card_data *priv,
156 int *dai_idx, int link_idx, 298 int *dai_idx, int link_idx,
@@ -291,63 +433,153 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
291static int asoc_simple_card_parse_of(struct simple_card_data *priv) 433static int asoc_simple_card_parse_of(struct simple_card_data *priv)
292{ 434{
293 struct device *dev = simple_priv_to_dev(priv); 435 struct device *dev = simple_priv_to_dev(priv);
436 struct device_node *top = dev->of_node;
294 struct snd_soc_card *card = simple_priv_to_card(priv); 437 struct snd_soc_card *card = simple_priv_to_card(priv);
295 struct device_node *dai_link; 438 struct device_node *node;
296 struct device_node *node = dev->of_node; 439 struct device_node *np;
297 int ret; 440 struct device_node *codec;
298 int link_idx, dai_idx; 441 bool is_fe;
299 442 int ret, loop;
300 if (!node) 443 int dai_idx, link_idx, conf_idx;
444
445 if (!top)
301 return -EINVAL; 446 return -EINVAL;
302 447
303 dai_link = of_get_child_by_name(node, PREFIX "dai-link");
304
305 ret = asoc_simple_card_of_parse_widgets(card, PREFIX); 448 ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
306 if (ret < 0) 449 if (ret < 0)
307 goto card_parse_end; 450 return ret;
308 451
309 ret = asoc_simple_card_of_parse_routing(card, PREFIX); 452 ret = asoc_simple_card_of_parse_routing(card, PREFIX);
310 if (ret < 0) 453 if (ret < 0)
311 goto card_parse_end; 454 return ret;
312 455
313 /* Factor to mclk, used in hw_params() */ 456 /* Factor to mclk, used in hw_params() */
314 of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); 457 of_property_read_u32(top, PREFIX "mclk-fs", &priv->mclk_fs);
458
459 asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
315 460
316 /* Single/Muti DAI link(s) & New style of DT node */ 461 /* Single/Muti DAI link(s) & New style of DT node */
317 link_idx = 0; 462 loop = 1;
318 dai_idx = 0; 463 link_idx = 0;
319 if (dai_link) { 464 dai_idx = 0;
320 struct device_node *np = NULL; 465 conf_idx = 0;
321 466 node = of_get_child_by_name(top, PREFIX "dai-link");
322 for_each_child_of_node(node, np) { 467 if (!node) {
323 dev_dbg(dev, "\tlink %d:\n", link_idx); 468 node = dev->of_node;
324 ret = asoc_simple_card_dai_link_of(np, priv, 469 loop = 0;
325 &dai_idx, link_idx++, false); 470 }
326 if (ret < 0) { 471
327 of_node_put(np); 472 do {
328 goto card_parse_end; 473 /* DPCM */
474 if (of_get_child_count(node) > 2) {
475 for_each_child_of_node(node, np) {
476 codec = of_get_child_by_name(node,
477 loop ? "codec" :
478 PREFIX "codec");
479 if (!codec)
480 return -ENODEV;
481
482 is_fe = (np != codec);
483
484 ret = asoc_simple_card_dai_link_of_dpcm(
485 node, np, codec, priv,
486 &dai_idx, link_idx++, &conf_idx,
487 is_fe, !loop);
329 } 488 }
489 } else {
490 ret = asoc_simple_card_dai_link_of(
491 node, priv,
492 &dai_idx, link_idx++, !loop);
330 } 493 }
331 } else {
332 /* For single DAI link & old style of DT node */
333 ret = asoc_simple_card_dai_link_of(node, priv,
334 &dai_idx, link_idx++, true);
335 if (ret < 0) 494 if (ret < 0)
336 goto card_parse_end; 495 return ret;
337 } 496
497 node = of_get_next_child(top, node);
498 } while (loop && node);
338 499
339 ret = asoc_simple_card_parse_card_name(card, PREFIX); 500 ret = asoc_simple_card_parse_card_name(card, PREFIX);
340 if (ret < 0) 501 if (ret < 0)
341 goto card_parse_end; 502 return ret;
342
343 ret = asoc_simple_card_parse_aux_devs(node, priv);
344 503
345card_parse_end: 504 ret = asoc_simple_card_parse_aux_devs(top, priv);
346 of_node_put(dai_link);
347 505
348 return ret; 506 return ret;
349} 507}
350 508
509static void asoc_simple_card_get_dais_count(struct device *dev,
510 int *link_num,
511 int *dais_num,
512 int *ccnf_num)
513{
514 struct device_node *top = dev->of_node;
515 struct device_node *node;
516 int loop;
517 int num;
518
519 /*
520 * link_num : number of links.
521 * CPU-Codec / CPU-dummy / dummy-Codec
522 * dais_num : number of DAIs
523 * ccnf_num : number of codec_conf
524 * same number for "dummy-Codec"
525 *
526 * ex1)
527 * CPU0 --- Codec0 link : 5
528 * CPU1 --- Codec1 dais : 7
529 * CPU2 -/ ccnf : 1
530 * CPU3 --- Codec2
531 *
532 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
533 * => 7 DAIs = 4xCPU + 3xCodec
534 * => 1 ccnf = 1xdummy-Codec
535 *
536 * ex2)
537 * CPU0 --- Codec0 link : 5
538 * CPU1 --- Codec1 dais : 6
539 * CPU2 -/ ccnf : 1
540 * CPU3 -/
541 *
542 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
543 * => 6 DAIs = 4xCPU + 2xCodec
544 * => 1 ccnf = 1xdummy-Codec
545 *
546 * ex3)
547 * CPU0 --- Codec0 link : 6
548 * CPU1 -/ dais : 6
549 * CPU2 --- Codec1 ccnf : 2
550 * CPU3 -/
551 *
552 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
553 * => 6 DAIs = 4xCPU + 2xCodec
554 * => 2 ccnf = 2xdummy-Codec
555 */
556 if (!top) {
557 (*link_num) = 1;
558 (*dais_num) = 2;
559 (*ccnf_num) = 0;
560 return;
561 }
562
563 loop = 1;
564 node = of_get_child_by_name(top, PREFIX "dai-link");
565 if (!node) {
566 node = top;
567 loop = 0;
568 }
569
570 do {
571 num = of_get_child_count(node);
572 (*dais_num) += num;
573 if (num > 2) {
574 (*link_num) += num;
575 (*ccnf_num)++;
576 } else {
577 (*link_num)++;
578 }
579 node = of_get_next_child(top, node);
580 } while (loop && node);
581}
582
351static int asoc_simple_soc_card_probe(struct snd_soc_card *card) 583static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
352{ 584{
353 struct simple_card_data *priv = snd_soc_card_get_drvdata(card); 585 struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
@@ -373,22 +605,23 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
373 struct device *dev = &pdev->dev; 605 struct device *dev = &pdev->dev;
374 struct device_node *np = dev->of_node; 606 struct device_node *np = dev->of_node;
375 struct snd_soc_card *card; 607 struct snd_soc_card *card;
376 int num, ret, i; 608 struct snd_soc_codec_conf *cconf;
377 609 int lnum = 0, dnum = 0, cnum = 0;
378 /* Get the number of DAI links */ 610 int ret, i;
379 if (np && of_get_child_by_name(np, PREFIX "dai-link"))
380 num = of_get_child_count(np);
381 else
382 num = 1;
383 611
384 /* Allocate the private data and the DAI link array */ 612 /* Allocate the private data and the DAI link array */
385 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 613 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
386 if (!priv) 614 if (!priv)
387 return -ENOMEM; 615 return -ENOMEM;
388 616
389 dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); 617 asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
390 dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); 618 if (!lnum || !dnum)
391 dais = devm_kcalloc(dev, num * 2, sizeof(*dais), GFP_KERNEL); 619 return -EINVAL;
620
621 dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
622 dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
623 dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
624 cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
392 if (!dai_props || !dai_link || !dais) 625 if (!dai_props || !dai_link || !dais)
393 return -ENOMEM; 626 return -ENOMEM;
394 627
@@ -398,7 +631,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
398 * see 631 * see
399 * soc-core.c :: snd_soc_init_multicodec() 632 * soc-core.c :: snd_soc_init_multicodec()
400 */ 633 */
401 for (i = 0; i < num; i++) { 634 for (i = 0; i < lnum; i++) {
402 dai_link[i].codecs = &dai_props[i].codecs; 635 dai_link[i].codecs = &dai_props[i].codecs;
403 dai_link[i].num_codecs = 1; 636 dai_link[i].num_codecs = 1;
404 dai_link[i].platform = &dai_props[i].platform; 637 dai_link[i].platform = &dai_props[i].platform;
@@ -407,13 +640,16 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
407 priv->dai_props = dai_props; 640 priv->dai_props = dai_props;
408 priv->dai_link = dai_link; 641 priv->dai_link = dai_link;
409 priv->dais = dais; 642 priv->dais = dais;
643 priv->codec_conf = cconf;
410 644
411 /* Init snd_soc_card */ 645 /* Init snd_soc_card */
412 card = simple_priv_to_card(priv); 646 card = simple_priv_to_card(priv);
413 card->owner = THIS_MODULE; 647 card->owner = THIS_MODULE;
414 card->dev = dev; 648 card->dev = dev;
415 card->dai_link = priv->dai_link; 649 card->dai_link = priv->dai_link;
416 card->num_links = num; 650 card->num_links = lnum;
651 card->codec_conf = cconf;
652 card->num_configs = cnum;
417 card->probe = asoc_simple_soc_card_probe; 653 card->probe = asoc_simple_soc_card_probe;
418 654
419 if (np && of_device_is_available(np)) { 655 if (np && of_device_is_available(np)) {
@@ -490,6 +726,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
490 726
491static const struct of_device_id asoc_simple_of_match[] = { 727static const struct of_device_id asoc_simple_of_match[] = {
492 { .compatible = "simple-audio-card", }, 728 { .compatible = "simple-audio-card", },
729 { .compatible = "simple-scu-audio-card", },
493 {}, 730 {},
494}; 731};
495MODULE_DEVICE_TABLE(of, asoc_simple_of_match); 732MODULE_DEVICE_TABLE(of, asoc_simple_of_match);