1
2
3
4
5
6#include <linux/module.h>
7#include <linux/of_platform.h>
8#include <sound/soc.h>
9#include <sound/soc-dai.h>
10
11#include "axg-tdm.h"
12
13struct axg_card {
14 struct snd_soc_card card;
15 void **link_data;
16};
17
18struct axg_dai_link_tdm_mask {
19 u32 tx;
20 u32 rx;
21};
22
23struct axg_dai_link_tdm_data {
24 unsigned int mclk_fs;
25 unsigned int slots;
26 unsigned int slot_width;
27 u32 *tx_mask;
28 u32 *rx_mask;
29 struct axg_dai_link_tdm_mask *codec_masks;
30};
31
32
33
34
35
36static const struct snd_soc_pcm_stream codec_params = {
37 .formats = SNDRV_PCM_FMTBIT_S24_LE,
38 .rate_min = 5525,
39 .rate_max = 192000,
40 .channels_min = 1,
41 .channels_max = 8,
42};
43
44#define PREFIX "amlogic,"
45
46static int axg_card_reallocate_links(struct axg_card *priv,
47 unsigned int num_links)
48{
49 struct snd_soc_dai_link *links;
50 void **ldata;
51
52 links = krealloc(priv->card.dai_link,
53 num_links * sizeof(*priv->card.dai_link),
54 GFP_KERNEL | __GFP_ZERO);
55 ldata = krealloc(priv->link_data,
56 num_links * sizeof(*priv->link_data),
57 GFP_KERNEL | __GFP_ZERO);
58
59 if (!links || !ldata) {
60 dev_err(priv->card.dev, "failed to allocate links\n");
61 return -ENOMEM;
62 }
63
64 priv->card.dai_link = links;
65 priv->link_data = ldata;
66 priv->card.num_links = num_links;
67 return 0;
68}
69
70static int axg_card_parse_dai(struct snd_soc_card *card,
71 struct device_node *node,
72 struct device_node **dai_of_node,
73 const char **dai_name)
74{
75 struct of_phandle_args args;
76 int ret;
77
78 if (!dai_name || !dai_of_node || !node)
79 return -EINVAL;
80
81 ret = of_parse_phandle_with_args(node, "sound-dai",
82 "#sound-dai-cells", 0, &args);
83 if (ret) {
84 if (ret != -EPROBE_DEFER)
85 dev_err(card->dev, "can't parse dai %d\n", ret);
86 return ret;
87 }
88 *dai_of_node = args.np;
89
90 return snd_soc_get_dai_name(&args, dai_name);
91}
92
93static int axg_card_set_link_name(struct snd_soc_card *card,
94 struct snd_soc_dai_link *link,
95 struct device_node *node,
96 const char *prefix)
97{
98 char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
99 prefix, node->full_name);
100 if (!name)
101 return -ENOMEM;
102
103 link->name = name;
104 link->stream_name = name;
105
106 return 0;
107}
108
109static void axg_card_clean_references(struct axg_card *priv)
110{
111 struct snd_soc_card *card = &priv->card;
112 struct snd_soc_dai_link *link;
113 struct snd_soc_dai_link_component *codec;
114 int i, j;
115
116 if (card->dai_link) {
117 for_each_card_prelinks(card, i, link) {
118 if (link->cpus)
119 of_node_put(link->cpus->of_node);
120 for_each_link_codecs(link, j, codec)
121 of_node_put(codec->of_node);
122 }
123 }
124
125 if (card->aux_dev) {
126 for (i = 0; i < card->num_aux_devs; i++)
127 of_node_put(card->aux_dev[i].codec_of_node);
128 }
129
130 kfree(card->dai_link);
131 kfree(priv->link_data);
132}
133
134static int axg_card_add_aux_devices(struct snd_soc_card *card)
135{
136 struct device_node *node = card->dev->of_node;
137 struct snd_soc_aux_dev *aux;
138 int num, i;
139
140 num = of_count_phandle_with_args(node, "audio-aux-devs", NULL);
141 if (num == -ENOENT) {
142
143
144
145
146 dev_warn(card->dev, "card has no auxiliary devices\n");
147 return 0;
148 } else if (num < 0) {
149 dev_err(card->dev, "error getting auxiliary devices: %d\n",
150 num);
151 return num;
152 }
153
154 aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL);
155 if (!aux)
156 return -ENOMEM;
157 card->aux_dev = aux;
158 card->num_aux_devs = num;
159
160 for (i = 0; i < card->num_aux_devs; i++, aux++) {
161 aux->codec_of_node =
162 of_parse_phandle(node, "audio-aux-devs", i);
163 if (!aux->codec_of_node)
164 return -EINVAL;
165 }
166
167 return 0;
168}
169
170static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream,
171 struct snd_pcm_hw_params *params)
172{
173 struct snd_soc_pcm_runtime *rtd = substream->private_data;
174 struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
175 struct axg_dai_link_tdm_data *be =
176 (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
177 struct snd_soc_dai *codec_dai;
178 unsigned int mclk;
179 int ret, i;
180
181 if (be->mclk_fs) {
182 mclk = params_rate(params) * be->mclk_fs;
183
184 for_each_rtd_codec_dai(rtd, i, codec_dai) {
185 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
186 SND_SOC_CLOCK_IN);
187 if (ret && ret != -ENOTSUPP)
188 return ret;
189 }
190
191 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk,
192 SND_SOC_CLOCK_OUT);
193 if (ret && ret != -ENOTSUPP)
194 return ret;
195 }
196
197 return 0;
198}
199
200static const struct snd_soc_ops axg_card_tdm_be_ops = {
201 .hw_params = axg_card_tdm_be_hw_params,
202};
203
204static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
205{
206 struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
207 struct axg_dai_link_tdm_data *be =
208 (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
209 struct snd_soc_dai *codec_dai;
210 int ret, i;
211
212 for_each_rtd_codec_dai(rtd, i, codec_dai) {
213 ret = snd_soc_dai_set_tdm_slot(codec_dai,
214 be->codec_masks[i].tx,
215 be->codec_masks[i].rx,
216 be->slots, be->slot_width);
217 if (ret && ret != -ENOTSUPP) {
218 dev_err(codec_dai->dev,
219 "setting tdm link slots failed\n");
220 return ret;
221 }
222 }
223
224 ret = axg_tdm_set_tdm_slots(rtd->cpu_dai, be->tx_mask, be->rx_mask,
225 be->slots, be->slot_width);
226 if (ret) {
227 dev_err(rtd->cpu_dai->dev, "setting tdm link slots failed\n");
228 return ret;
229 }
230
231 return 0;
232}
233
234static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd)
235{
236 struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
237 struct axg_dai_link_tdm_data *be =
238 (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
239 int ret;
240
241
242 ret = axg_tdm_set_tdm_slots(rtd->cpu_dai, NULL, be->tx_mask,
243 be->slots, be->slot_width);
244 if (ret) {
245 dev_err(rtd->cpu_dai->dev, "setting tdm link slots failed\n");
246 return ret;
247 }
248
249 return 0;
250}
251
252static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
253 int *index)
254{
255 struct axg_card *priv = snd_soc_card_get_drvdata(card);
256 struct snd_soc_dai_link *pad = &card->dai_link[*index];
257 struct snd_soc_dai_link *lb;
258 struct snd_soc_dai_link_component *dlc;
259 int ret;
260
261
262 ret = axg_card_reallocate_links(priv, card->num_links + 1);
263 if (ret)
264 return ret;
265
266 lb = &card->dai_link[*index + 1];
267
268 lb->name = kasprintf(GFP_KERNEL, "%s-lb", pad->name);
269 if (!lb->name)
270 return -ENOMEM;
271
272 dlc = devm_kzalloc(card->dev, 2 * sizeof(*dlc), GFP_KERNEL);
273 if (!dlc)
274 return -ENOMEM;
275
276 lb->cpus = &dlc[0];
277 lb->codecs = &dlc[1];
278 lb->num_cpus = 1;
279 lb->num_codecs = 1;
280
281 lb->stream_name = lb->name;
282 lb->cpus->of_node = pad->cpus->of_node;
283 lb->cpus->dai_name = "TDM Loopback";
284 lb->codecs->name = "snd-soc-dummy";
285 lb->codecs->dai_name = "snd-soc-dummy-dai";
286 lb->dpcm_capture = 1;
287 lb->no_pcm = 1;
288 lb->ops = &axg_card_tdm_be_ops;
289 lb->init = axg_card_tdm_dai_lb_init;
290
291
292 priv->link_data[*index + 1] = priv->link_data[*index];
293
294
295
296
297
298 of_node_get(lb->cpus->of_node);
299
300
301 *index += 1;
302
303 return 0;
304}
305
306static unsigned int axg_card_parse_daifmt(struct device_node *node,
307 struct device_node *cpu_node)
308{
309 struct device_node *bitclkmaster = NULL;
310 struct device_node *framemaster = NULL;
311 unsigned int daifmt;
312
313 daifmt = snd_soc_of_parse_daifmt(node, PREFIX,
314 &bitclkmaster, &framemaster);
315 daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
316
317
318 if (!bitclkmaster || bitclkmaster == cpu_node) {
319 daifmt |= (!framemaster || framemaster == cpu_node) ?
320 SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
321 } else {
322 daifmt |= (!framemaster || framemaster == cpu_node) ?
323 SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
324 }
325
326 of_node_put(bitclkmaster);
327 of_node_put(framemaster);
328
329 return daifmt;
330}
331
332static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
333 struct snd_soc_dai_link *link,
334 struct device_node *node,
335 struct axg_dai_link_tdm_data *be)
336{
337 char propname[32];
338 u32 tx, rx;
339 int i;
340
341 be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
342 sizeof(*be->tx_mask), GFP_KERNEL);
343 be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
344 sizeof(*be->rx_mask), GFP_KERNEL);
345 if (!be->tx_mask || !be->rx_mask)
346 return -ENOMEM;
347
348 for (i = 0, tx = 0; i < AXG_TDM_NUM_LANES; i++) {
349 snprintf(propname, 32, "dai-tdm-slot-tx-mask-%d", i);
350 snd_soc_of_get_slot_mask(node, propname, &be->tx_mask[i]);
351 tx = max(tx, be->tx_mask[i]);
352 }
353
354
355 if (!tx)
356 link->dpcm_playback = 0;
357
358 for (i = 0, rx = 0; i < AXG_TDM_NUM_LANES; i++) {
359 snprintf(propname, 32, "dai-tdm-slot-rx-mask-%d", i);
360 snd_soc_of_get_slot_mask(node, propname, &be->rx_mask[i]);
361 rx = max(rx, be->rx_mask[i]);
362 }
363
364
365 if (!rx)
366 link->dpcm_capture = 0;
367
368
369 if (!tx && !rx) {
370 dev_err(card->dev, "tdm link has no cpu slots\n");
371 return -EINVAL;
372 }
373
374 of_property_read_u32(node, "dai-tdm-slot-num", &be->slots);
375 if (!be->slots) {
376
377
378
379
380 be->slots = fls(max(tx, rx));
381 } else if (be->slots < fls(max(tx, rx)) || be->slots > 32) {
382
383
384
385
386 dev_err(card->dev, "bad slot number\n");
387 return -EINVAL;
388 }
389
390 of_property_read_u32(node, "dai-tdm-slot-width", &be->slot_width);
391
392 return 0;
393}
394
395static int axg_card_parse_codecs_masks(struct snd_soc_card *card,
396 struct snd_soc_dai_link *link,
397 struct device_node *node,
398 struct axg_dai_link_tdm_data *be)
399{
400 struct axg_dai_link_tdm_mask *codec_mask;
401 struct device_node *np;
402
403 codec_mask = devm_kcalloc(card->dev, link->num_codecs,
404 sizeof(*codec_mask), GFP_KERNEL);
405 if (!codec_mask)
406 return -ENOMEM;
407
408 be->codec_masks = codec_mask;
409
410 for_each_child_of_node(node, np) {
411 snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask",
412 &codec_mask->rx);
413 snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask",
414 &codec_mask->tx);
415
416 codec_mask++;
417 }
418
419 return 0;
420}
421
422static int axg_card_parse_tdm(struct snd_soc_card *card,
423 struct device_node *node,
424 int *index)
425{
426 struct axg_card *priv = snd_soc_card_get_drvdata(card);
427 struct snd_soc_dai_link *link = &card->dai_link[*index];
428 struct axg_dai_link_tdm_data *be;
429 int ret;
430
431
432 be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
433 if (!be)
434 return -ENOMEM;
435 priv->link_data[*index] = be;
436
437
438 link->ops = &axg_card_tdm_be_ops;
439 link->init = axg_card_tdm_dai_init;
440 link->dai_fmt = axg_card_parse_daifmt(node, link->cpus->of_node);
441
442 of_property_read_u32(node, "mclk-fs", &be->mclk_fs);
443
444 ret = axg_card_parse_cpu_tdm_slots(card, link, node, be);
445 if (ret) {
446 dev_err(card->dev, "error parsing tdm link slots\n");
447 return ret;
448 }
449
450 ret = axg_card_parse_codecs_masks(card, link, node, be);
451 if (ret)
452 return ret;
453
454
455 if (link->dpcm_playback) {
456 ret = axg_card_add_tdm_loopback(card, index);
457 if (ret)
458 return ret;
459 }
460
461 return 0;
462}
463
464static int axg_card_set_be_link(struct snd_soc_card *card,
465 struct snd_soc_dai_link *link,
466 struct device_node *node)
467{
468 struct snd_soc_dai_link_component *codec;
469 struct device_node *np;
470 int ret, num_codecs;
471
472 link->no_pcm = 1;
473 link->dpcm_playback = 1;
474 link->dpcm_capture = 1;
475
476 num_codecs = of_get_child_count(node);
477 if (!num_codecs) {
478 dev_err(card->dev, "be link %s has no codec\n",
479 node->full_name);
480 return -EINVAL;
481 }
482
483 codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
484 if (!codec)
485 return -ENOMEM;
486
487 link->codecs = codec;
488 link->num_codecs = num_codecs;
489
490 for_each_child_of_node(node, np) {
491 ret = axg_card_parse_dai(card, np, &codec->of_node,
492 &codec->dai_name);
493 if (ret) {
494 of_node_put(np);
495 return ret;
496 }
497
498 codec++;
499 }
500
501 ret = axg_card_set_link_name(card, link, node, "be");
502 if (ret)
503 dev_err(card->dev, "error setting %pOFn link name\n", np);
504
505 return ret;
506}
507
508static int axg_card_set_fe_link(struct snd_soc_card *card,
509 struct snd_soc_dai_link *link,
510 struct device_node *node,
511 bool is_playback)
512{
513 struct snd_soc_dai_link_component *codec;
514
515 codec = devm_kzalloc(card->dev, sizeof(*codec), GFP_KERNEL);
516 if (!codec)
517 return -ENOMEM;
518
519 link->codecs = codec;
520 link->num_codecs = 1;
521
522 link->dynamic = 1;
523 link->dpcm_merged_format = 1;
524 link->dpcm_merged_chan = 1;
525 link->dpcm_merged_rate = 1;
526 link->codecs->dai_name = "snd-soc-dummy-dai";
527 link->codecs->name = "snd-soc-dummy";
528
529 if (is_playback)
530 link->dpcm_playback = 1;
531 else
532 link->dpcm_capture = 1;
533
534 return axg_card_set_link_name(card, link, node, "fe");
535}
536
537static int axg_card_cpu_is_capture_fe(struct device_node *np)
538{
539 return of_device_is_compatible(np, PREFIX "axg-toddr");
540}
541
542static int axg_card_cpu_is_playback_fe(struct device_node *np)
543{
544 return of_device_is_compatible(np, PREFIX "axg-frddr");
545}
546
547static int axg_card_cpu_is_tdm_iface(struct device_node *np)
548{
549 return of_device_is_compatible(np, PREFIX "axg-tdm-iface");
550}
551
552static int axg_card_cpu_is_codec(struct device_node *np)
553{
554 return of_device_is_compatible(np, PREFIX "g12a-tohdmitx");
555}
556
557static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
558 int *index)
559{
560 struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
561 struct snd_soc_dai_link_component *cpu;
562 int ret;
563
564 cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL);
565 if (!cpu)
566 return -ENOMEM;
567
568 dai_link->cpus = cpu;
569 dai_link->num_cpus = 1;
570
571 ret = axg_card_parse_dai(card, np, &dai_link->cpus->of_node,
572 &dai_link->cpus->dai_name);
573 if (ret)
574 return ret;
575
576 if (axg_card_cpu_is_playback_fe(dai_link->cpus->of_node))
577 ret = axg_card_set_fe_link(card, dai_link, np, true);
578 else if (axg_card_cpu_is_capture_fe(dai_link->cpus->of_node))
579 ret = axg_card_set_fe_link(card, dai_link, np, false);
580 else
581 ret = axg_card_set_be_link(card, dai_link, np);
582
583 if (ret)
584 return ret;
585
586 if (axg_card_cpu_is_tdm_iface(dai_link->cpus->of_node))
587 ret = axg_card_parse_tdm(card, np, index);
588 else if (axg_card_cpu_is_codec(dai_link->cpus->of_node))
589 dai_link->params = &codec_params;
590
591 return ret;
592}
593
594static int axg_card_add_links(struct snd_soc_card *card)
595{
596 struct axg_card *priv = snd_soc_card_get_drvdata(card);
597 struct device_node *node = card->dev->of_node;
598 struct device_node *np;
599 int num, i, ret;
600
601 num = of_get_child_count(node);
602 if (!num) {
603 dev_err(card->dev, "card has no links\n");
604 return -EINVAL;
605 }
606
607 ret = axg_card_reallocate_links(priv, num);
608 if (ret)
609 return ret;
610
611 i = 0;
612 for_each_child_of_node(node, np) {
613 ret = axg_card_add_link(card, np, &i);
614 if (ret) {
615 of_node_put(np);
616 return ret;
617 }
618
619 i++;
620 }
621
622 return 0;
623}
624
625static int axg_card_parse_of_optional(struct snd_soc_card *card,
626 const char *propname,
627 int (*func)(struct snd_soc_card *c,
628 const char *p))
629{
630
631 if (!of_property_read_bool(card->dev->of_node, propname))
632 return 0;
633
634
635 return func(card, propname);
636}
637
638static const struct of_device_id axg_card_of_match[] = {
639 { .compatible = "amlogic,axg-sound-card", },
640 {}
641};
642MODULE_DEVICE_TABLE(of, axg_card_of_match);
643
644static int axg_card_probe(struct platform_device *pdev)
645{
646 struct device *dev = &pdev->dev;
647 struct axg_card *priv;
648 int ret;
649
650 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
651 if (!priv)
652 return -ENOMEM;
653
654 platform_set_drvdata(pdev, priv);
655 snd_soc_card_set_drvdata(&priv->card, priv);
656
657 priv->card.owner = THIS_MODULE;
658 priv->card.dev = dev;
659
660 ret = snd_soc_of_parse_card_name(&priv->card, "model");
661 if (ret < 0)
662 return ret;
663
664 ret = axg_card_parse_of_optional(&priv->card, "audio-routing",
665 snd_soc_of_parse_audio_routing);
666 if (ret) {
667 dev_err(dev, "error while parsing routing\n");
668 return ret;
669 }
670
671 ret = axg_card_parse_of_optional(&priv->card, "audio-widgets",
672 snd_soc_of_parse_audio_simple_widgets);
673 if (ret) {
674 dev_err(dev, "error while parsing widgets\n");
675 return ret;
676 }
677
678 ret = axg_card_add_links(&priv->card);
679 if (ret)
680 goto out_err;
681
682 ret = axg_card_add_aux_devices(&priv->card);
683 if (ret)
684 goto out_err;
685
686 ret = devm_snd_soc_register_card(dev, &priv->card);
687 if (ret)
688 goto out_err;
689
690 return 0;
691
692out_err:
693 axg_card_clean_references(priv);
694 return ret;
695}
696
697static int axg_card_remove(struct platform_device *pdev)
698{
699 struct axg_card *priv = platform_get_drvdata(pdev);
700
701 axg_card_clean_references(priv);
702
703 return 0;
704}
705
706static struct platform_driver axg_card_pdrv = {
707 .probe = axg_card_probe,
708 .remove = axg_card_remove,
709 .driver = {
710 .name = "axg-sound-card",
711 .of_match_table = axg_card_of_match,
712 },
713};
714module_platform_driver(axg_card_pdrv);
715
716MODULE_DESCRIPTION("Amlogic AXG ALSA machine driver");
717MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
718MODULE_LICENSE("GPL v2");
719