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