audio-graph-card2.c (28777B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// ASoC Audio Graph Card2 support 4// 5// Copyright (C) 2020 Renesas Electronics Corp. 6// Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7// 8// based on ${LINUX}/sound/soc/generic/audio-graph-card.c 9#include <linux/clk.h> 10#include <linux/device.h> 11#include <linux/gpio.h> 12#include <linux/gpio/consumer.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/of_device.h> 16#include <linux/of_gpio.h> 17#include <linux/of_graph.h> 18#include <linux/platform_device.h> 19#include <linux/string.h> 20#include <sound/graph_card.h> 21 22/************************************ 23 daifmt 24 ************************************ 25 ports { 26 format = "left_j"; 27 port@0 { 28 bitclock-master; 29 sample0: endpoint@0 { 30 frame-master; 31 }; 32 sample1: endpoint@1 { 33 format = "i2s"; 34 }; 35 }; 36 ... 37 }; 38 39 You can set daifmt at ports/port/endpoint. 40 It uses *latest* format, and *share* master settings. 41 In above case, 42 sample0: left_j, bitclock-master, frame-master 43 sample1: i2s, bitclock-master 44 45 If there was no settings, *Codec* will be 46 bitclock/frame provider as default. 47 see 48 graph_parse_daifmt(). 49 50 ************************************ 51 Normal Audio-Graph 52 ************************************ 53 54 CPU <---> Codec 55 56 sound { 57 compatible = "audio-graph-card2"; 58 links = <&cpu>; 59 }; 60 61 CPU { 62 cpu: port { 63 bitclock-master; 64 frame-master; 65 cpu_ep: endpoint { remote-endpoint = <&codec_ep>; }; }; 66 }; 67 68 Codec { 69 port { codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; }; 70 }; 71 72 ************************************ 73 Multi-CPU/Codec 74 ************************************ 75 76It has connection part (= X) and list part (= y). 77links indicates connection part of CPU side (= A). 78 79 +-+ (A) +-+ 80 CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1 81 CPU2 --(y) | | | | (y)-- Codec2 82 +-+ +-+ 83 84 sound { 85 compatible = "audio-graph-card2"; 86 87(A) links = <&mcpu>; 88 89 multi { 90 ports@0 { 91(X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; 92(y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; 93(y) port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; 94 }; 95 ports@1 { 96(X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; 97(y) port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; 98(y) port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; 99 }; 100 }; 101 }; 102 103 CPU { 104 ports { 105 bitclock-master; 106 frame-master; 107 port@0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; 108 port@1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; 109 }; 110 }; 111 112 Codec { 113 ports { 114 port@0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; 115 port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; 116 }; 117 }; 118 119 ************************************ 120 DPCM 121 ************************************ 122 123 DSP 124 ************ 125 PCM0 <--> * fe0 be0 * <--> DAI0: Codec Headset 126 PCM1 <--> * fe1 be1 * <--> DAI1: Codec Speakers 127 PCM2 <--> * fe2 be2 * <--> DAI2: MODEM 128 PCM3 <--> * fe3 be3 * <--> DAI3: BT 129 * be4 * <--> DAI4: DMIC 130 * be5 * <--> DAI5: FM 131 ************ 132 133 sound { 134 compatible = "audio-graph-card2"; 135 136 // indicate routing 137 routing = "xxx Playback", "xxx Playback", 138 "xxx Playback", "xxx Playback", 139 "xxx Playback", "xxx Playback"; 140 141 // indicate all Front-End, Back-End 142 links = <&fe0, &fe1, ..., 143 &be0, &be1, ...>; 144 145 dpcm { 146 // Front-End 147 ports@0 { 148 fe0: port@0 { fe0_ep: endpoint { remote-endpoint = <&pcm0_ep>; }; }; 149 fe1: port@1 { fe1_ep: endpoint { remote-endpoint = <&pcm1_ep>; }; }; 150 ... 151 }; 152 // Back-End 153 ports@1 { 154 be0: port@0 { be0_ep: endpoint { remote-endpoint = <&dai0_ep>; }; }; 155 be1: port@1 { be1_ep: endpoint { remote-endpoint = <&dai1_ep>; }; }; 156 ... 157 }; 158 }; 159 }; 160 161 CPU { 162 ports { 163 bitclock-master; 164 frame-master; 165 port@0 { pcm0_ep: endpoint { remote-endpoint = <&fe0_ep>; }; }; 166 port@1 { pcm1_ep: endpoint { remote-endpoint = <&fe1_ep>; }; }; 167 ... 168 }; 169 }; 170 171 Codec { 172 ports { 173 port@0 { dai0_ep: endpoint { remote-endpoint = <&be0_ep>; }; }; 174 port@1 { dai1_ep: endpoint { remote-endpoint = <&be1_ep>; }; }; 175 ... 176 }; 177 }; 178 179 ************************************ 180 Codec to Codec 181 ************************************ 182 183 +--+ 184 | |<-- Codec0 <- IN 185 | |--> Codec1 -> OUT 186 +--+ 187 188 sound { 189 compatible = "audio-graph-card2"; 190 191 routing = "OUT" ,"DAI1 Playback", 192 "DAI0 Capture", "IN"; 193 194 links = <&c2c>; 195 196 codec2codec { 197 ports { 198 rate = <48000>; 199 c2c: port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; 200 port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; 201 }; 202 }; 203 204 Codec { 205 ports { 206 port@0 { 207 bitclock-master; 208 frame-master; 209 codec0_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; }; 210 port@1 { codec1_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; }; 211 }; 212 }; 213 214*/ 215 216enum graph_type { 217 GRAPH_NORMAL, 218 GRAPH_DPCM, 219 GRAPH_C2C, 220 221 GRAPH_MULTI, /* don't use ! Use this only in __graph_get_type() */ 222}; 223 224#define GRAPH_NODENAME_MULTI "multi" 225#define GRAPH_NODENAME_DPCM "dpcm" 226#define GRAPH_NODENAME_C2C "codec2codec" 227 228#define port_to_endpoint(port) of_get_child_by_name(port, "endpoint") 229 230static enum graph_type __graph_get_type(struct device_node *lnk) 231{ 232 struct device_node *np; 233 234 /* 235 * target { 236 * ports { 237 * => lnk: port@0 { ... }; 238 * port@1 { ... }; 239 * }; 240 * }; 241 */ 242 np = of_get_parent(lnk); 243 if (of_node_name_eq(np, "ports")) 244 np = of_get_parent(np); 245 246 if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) 247 return GRAPH_MULTI; 248 249 if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) 250 return GRAPH_DPCM; 251 252 if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) 253 return GRAPH_C2C; 254 255 return GRAPH_NORMAL; 256} 257 258static enum graph_type graph_get_type(struct asoc_simple_priv *priv, 259 struct device_node *lnk) 260{ 261 enum graph_type type = __graph_get_type(lnk); 262 263 /* GRAPH_MULTI here means GRAPH_NORMAL */ 264 if (type == GRAPH_MULTI) 265 type = GRAPH_NORMAL; 266 267#ifdef DEBUG 268 { 269 struct device *dev = simple_priv_to_dev(priv); 270 const char *str = "Normal"; 271 272 switch (type) { 273 case GRAPH_DPCM: 274 if (asoc_graph_is_ports0(lnk)) 275 str = "DPCM Front-End"; 276 else 277 str = "DPCM Back-End"; 278 break; 279 case GRAPH_C2C: 280 str = "Codec2Codec"; 281 break; 282 default: 283 break; 284 } 285 286 dev_dbg(dev, "%pOF (%s)", lnk, str); 287 } 288#endif 289 return type; 290} 291 292static int graph_lnk_is_multi(struct device_node *lnk) 293{ 294 return __graph_get_type(lnk) == GRAPH_MULTI; 295} 296 297static struct device_node *graph_get_next_multi_ep(struct device_node **port) 298{ 299 struct device_node *ports = of_get_parent(*port); 300 struct device_node *ep = NULL; 301 struct device_node *rep = NULL; 302 303 /* 304 * multi { 305 * ports { 306 * => lnk: port@0 { ... }; 307 * port@1 { ep { ... = rep0 } }; 308 * port@2 { ep { ... = rep1 } }; 309 * ... 310 * }; 311 * }; 312 * 313 * xxx { 314 * port@0 { rep0 }; 315 * port@1 { rep1 }; 316 * }; 317 */ 318 do { 319 *port = of_get_next_child(ports, *port); 320 if (!*port) 321 break; 322 } while (!of_node_name_eq(*port, "port")); 323 324 if (*port) { 325 ep = port_to_endpoint(*port); 326 rep = of_graph_get_remote_endpoint(ep); 327 } 328 329 of_node_put(ep); 330 of_node_put(ports); 331 332 return rep; 333} 334 335static const struct snd_soc_ops graph_ops = { 336 .startup = asoc_simple_startup, 337 .shutdown = asoc_simple_shutdown, 338 .hw_params = asoc_simple_hw_params, 339}; 340 341static int graph_get_dai_id(struct device_node *ep) 342{ 343 struct device_node *node; 344 struct device_node *endpoint; 345 struct of_endpoint info; 346 int i, id; 347 const u32 *reg; 348 int ret; 349 350 /* use driver specified DAI ID if exist */ 351 ret = snd_soc_get_dai_id(ep); 352 if (ret != -ENOTSUPP) 353 return ret; 354 355 /* use endpoint/port reg if exist */ 356 ret = of_graph_parse_endpoint(ep, &info); 357 if (ret == 0) { 358 /* 359 * Because it will count port/endpoint if it doesn't have "reg". 360 * But, we can't judge whether it has "no reg", or "reg = <0>" 361 * only of_graph_parse_endpoint(). 362 * We need to check "reg" property 363 */ 364 if (of_get_property(ep, "reg", NULL)) 365 return info.id; 366 367 node = of_get_parent(ep); 368 reg = of_get_property(node, "reg", NULL); 369 of_node_put(node); 370 if (reg) 371 return info.port; 372 } 373 node = of_graph_get_port_parent(ep); 374 375 /* 376 * Non HDMI sound case, counting port/endpoint on its DT 377 * is enough. Let's count it. 378 */ 379 i = 0; 380 id = -1; 381 for_each_endpoint_of_node(node, endpoint) { 382 if (endpoint == ep) 383 id = i; 384 i++; 385 } 386 387 of_node_put(node); 388 389 if (id < 0) 390 return -ENODEV; 391 392 return id; 393} 394 395static int asoc_simple_parse_dai(struct device_node *ep, 396 struct snd_soc_dai_link_component *dlc, 397 int *is_single_link) 398{ 399 struct device_node *node; 400 struct of_phandle_args args; 401 int ret; 402 403 if (!ep) 404 return 0; 405 406 node = of_graph_get_port_parent(ep); 407 408 /* Get dai->name */ 409 args.np = node; 410 args.args[0] = graph_get_dai_id(ep); 411 args.args_count = (of_graph_get_endpoint_count(node) > 1); 412 413 /* 414 * FIXME 415 * 416 * Here, dlc->dai_name is pointer to CPU/Codec DAI name. 417 * If user unbinded CPU or Codec driver, but not for Sound Card, 418 * dlc->dai_name is keeping unbinded CPU or Codec 419 * driver's pointer. 420 * 421 * If user re-bind CPU or Codec driver again, ALSA SoC will try 422 * to rebind Card via snd_soc_try_rebind_card(), but because of 423 * above reason, it might can't bind Sound Card. 424 * Because Sound Card is pointing to released dai_name pointer. 425 * 426 * To avoid this rebind Card issue, 427 * 1) It needs to alloc memory to keep dai_name eventhough 428 * CPU or Codec driver was unbinded, or 429 * 2) user need to rebind Sound Card everytime 430 * if he unbinded CPU or Codec. 431 */ 432 ret = snd_soc_get_dai_name(&args, &dlc->dai_name); 433 if (ret < 0) 434 return ret; 435 436 dlc->of_node = node; 437 438 if (is_single_link) 439 *is_single_link = of_graph_get_endpoint_count(node) == 1; 440 441 return 0; 442} 443 444static void graph_parse_convert(struct device_node *ep, 445 struct simple_dai_props *props) 446{ 447 struct device_node *port = of_get_parent(ep); 448 struct device_node *ports = of_get_parent(port); 449 struct asoc_simple_data *adata = &props->adata; 450 451 if (of_node_name_eq(ports, "ports")) 452 asoc_simple_parse_convert(ports, NULL, adata); 453 asoc_simple_parse_convert(port, NULL, adata); 454 asoc_simple_parse_convert(ep, NULL, adata); 455 456 of_node_put(port); 457 of_node_put(ports); 458} 459 460static void graph_parse_mclk_fs(struct device_node *ep, 461 struct simple_dai_props *props) 462{ 463 struct device_node *port = of_get_parent(ep); 464 struct device_node *ports = of_get_parent(port); 465 466 if (of_node_name_eq(ports, "ports")) 467 of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); 468 of_property_read_u32(port, "mclk-fs", &props->mclk_fs); 469 of_property_read_u32(ep, "mclk-fs", &props->mclk_fs); 470 471 of_node_put(port); 472 of_node_put(ports); 473} 474 475static int __graph_parse_node(struct asoc_simple_priv *priv, 476 enum graph_type gtype, 477 struct device_node *ep, 478 struct link_info *li, 479 int is_cpu, int idx) 480{ 481 struct device *dev = simple_priv_to_dev(priv); 482 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 483 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); 484 struct snd_soc_dai_link_component *dlc; 485 struct asoc_simple_dai *dai; 486 int ret, is_single_links = 0; 487 488 if (is_cpu) { 489 dlc = asoc_link_to_cpu(dai_link, idx); 490 dai = simple_props_to_dai_cpu(dai_props, idx); 491 } else { 492 dlc = asoc_link_to_codec(dai_link, idx); 493 dai = simple_props_to_dai_codec(dai_props, idx); 494 } 495 496 graph_parse_mclk_fs(ep, dai_props); 497 498 ret = asoc_simple_parse_dai(ep, dlc, &is_single_links); 499 if (ret < 0) 500 return ret; 501 502 ret = asoc_simple_parse_tdm(ep, dai); 503 if (ret < 0) 504 return ret; 505 506 ret = asoc_simple_parse_tdm_width_map(dev, ep, dai); 507 if (ret < 0) 508 return ret; 509 510 ret = asoc_simple_parse_clk(dev, ep, dai, dlc); 511 if (ret < 0) 512 return ret; 513 514 /* 515 * set DAI Name 516 */ 517 if (!dai_link->name) { 518 struct snd_soc_dai_link_component *cpus = dlc; 519 struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, idx); 520 char *cpu_multi = ""; 521 char *codec_multi = ""; 522 523 if (dai_link->num_cpus > 1) 524 cpu_multi = "_multi"; 525 if (dai_link->num_codecs > 1) 526 codec_multi = "_multi"; 527 528 switch (gtype) { 529 case GRAPH_NORMAL: 530 /* run is_cpu only. see audio_graph2_link_normal() */ 531 if (is_cpu) 532 asoc_simple_set_dailink_name(dev, dai_link, "%s%s-%s%s", 533 cpus->dai_name, cpu_multi, 534 codecs->dai_name, codec_multi); 535 break; 536 case GRAPH_DPCM: 537 if (is_cpu) 538 asoc_simple_set_dailink_name(dev, dai_link, "fe.%pOFP.%s%s", 539 cpus->of_node, cpus->dai_name, cpu_multi); 540 else 541 asoc_simple_set_dailink_name(dev, dai_link, "be.%pOFP.%s%s", 542 codecs->of_node, codecs->dai_name, codec_multi); 543 break; 544 case GRAPH_C2C: 545 /* run is_cpu only. see audio_graph2_link_c2c() */ 546 if (is_cpu) 547 asoc_simple_set_dailink_name(dev, dai_link, "c2c.%s%s-%s%s", 548 cpus->dai_name, cpu_multi, 549 codecs->dai_name, codec_multi); 550 break; 551 default: 552 break; 553 } 554 } 555 556 /* 557 * Check "prefix" from top node 558 * if DPCM-BE case 559 */ 560 if (!is_cpu && gtype == GRAPH_DPCM) { 561 struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, idx); 562 struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, idx); 563 struct device_node *rport = of_get_parent(ep); 564 struct device_node *rports = of_get_parent(rport); 565 566 if (of_node_name_eq(rports, "ports")) 567 snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix"); 568 snd_soc_of_parse_node_prefix(rport, cconf, codecs->of_node, "prefix"); 569 570 of_node_put(rport); 571 of_node_put(rports); 572 } 573 574 if (is_cpu) { 575 struct snd_soc_dai_link_component *cpus = dlc; 576 struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, idx); 577 578 asoc_simple_canonicalize_cpu(cpus, is_single_links); 579 asoc_simple_canonicalize_platform(platforms, cpus); 580 } 581 582 return 0; 583} 584 585static int graph_parse_node(struct asoc_simple_priv *priv, 586 enum graph_type gtype, 587 struct device_node *port, 588 struct link_info *li, int is_cpu) 589{ 590 struct device_node *ep; 591 int ret = 0; 592 593 if (graph_lnk_is_multi(port)) { 594 int idx; 595 596 of_node_get(port); 597 598 for (idx = 0;; idx++) { 599 ep = graph_get_next_multi_ep(&port); 600 if (!ep) 601 break; 602 603 ret = __graph_parse_node(priv, gtype, ep, 604 li, is_cpu, idx); 605 of_node_put(ep); 606 if (ret < 0) 607 break; 608 } 609 } else { 610 /* Single CPU / Codec */ 611 ep = port_to_endpoint(port); 612 ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); 613 of_node_put(ep); 614 } 615 616 return ret; 617} 618 619static void graph_parse_daifmt(struct device_node *node, 620 unsigned int *daifmt, unsigned int *bit_frame) 621{ 622 unsigned int fmt; 623 624 /* 625 * see also above "daifmt" explanation 626 * and samples. 627 */ 628 629 /* 630 * ports { 631 * (A) 632 * port { 633 * (B) 634 * endpoint { 635 * (C) 636 * }; 637 * }; 638 * }; 639 * }; 640 */ 641 642 /* 643 * clock_provider: 644 * 645 * It can be judged it is provider 646 * if (A) or (B) or (C) has bitclock-master / frame-master flag. 647 * 648 * use "or" 649 */ 650 *bit_frame |= snd_soc_daifmt_parse_clock_provider_as_bitmap(node, NULL); 651 652#define update_daifmt(name) \ 653 if (!(*daifmt & SND_SOC_DAIFMT_##name##_MASK) && \ 654 (fmt & SND_SOC_DAIFMT_##name##_MASK)) \ 655 *daifmt |= fmt & SND_SOC_DAIFMT_##name##_MASK 656 657 /* 658 * format 659 * 660 * This function is called by (C) -> (B) -> (A) order. 661 * Set if applicable part was not yet set. 662 */ 663 fmt = snd_soc_daifmt_parse_format(node, NULL); 664 update_daifmt(FORMAT); 665 update_daifmt(CLOCK); 666 update_daifmt(INV); 667} 668 669static void graph_link_init(struct asoc_simple_priv *priv, 670 struct device_node *port, 671 struct link_info *li, 672 int is_cpu_node) 673{ 674 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 675 struct device_node *ep; 676 struct device_node *ports; 677 unsigned int daifmt = 0, daiclk = 0; 678 unsigned int bit_frame = 0; 679 680 if (graph_lnk_is_multi(port)) { 681 of_node_get(port); 682 ep = graph_get_next_multi_ep(&port); 683 port = of_get_parent(ep); 684 } else { 685 ep = port_to_endpoint(port); 686 } 687 688 ports = of_get_parent(port); 689 690 /* 691 * ports { 692 * (A) 693 * port { 694 * (B) 695 * endpoint { 696 * (C) 697 * }; 698 * }; 699 * }; 700 * }; 701 */ 702 graph_parse_daifmt(ep, &daifmt, &bit_frame); /* (C) */ 703 graph_parse_daifmt(port, &daifmt, &bit_frame); /* (B) */ 704 if (of_node_name_eq(ports, "ports")) 705 graph_parse_daifmt(ports, &daifmt, &bit_frame); /* (A) */ 706 707 /* 708 * convert bit_frame 709 * We need to flip clock_provider if it was CPU node, 710 * because it is Codec base. 711 */ 712 daiclk = snd_soc_daifmt_clock_provider_from_bitmap(bit_frame); 713 if (is_cpu_node) 714 daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk); 715 716 dai_link->dai_fmt = daifmt | daiclk; 717 dai_link->init = asoc_simple_dai_init; 718 dai_link->ops = &graph_ops; 719 if (priv->ops) 720 dai_link->ops = priv->ops; 721} 722 723int audio_graph2_link_normal(struct asoc_simple_priv *priv, 724 struct device_node *lnk, 725 struct link_info *li) 726{ 727 struct device_node *cpu_port = lnk; 728 struct device_node *cpu_ep = port_to_endpoint(cpu_port); 729 struct device_node *codec_port = of_graph_get_remote_port(cpu_ep); 730 int ret; 731 732 /* 733 * call Codec first. 734 * see 735 * __graph_parse_node() :: DAI Naming 736 */ 737 ret = graph_parse_node(priv, GRAPH_NORMAL, codec_port, li, 0); 738 if (ret < 0) 739 goto err; 740 741 /* 742 * call CPU, and set DAI Name 743 */ 744 ret = graph_parse_node(priv, GRAPH_NORMAL, cpu_port, li, 1); 745 if (ret < 0) 746 goto err; 747 748 graph_link_init(priv, cpu_port, li, 1); 749err: 750 of_node_put(codec_port); 751 of_node_put(cpu_ep); 752 753 return ret; 754} 755EXPORT_SYMBOL_GPL(audio_graph2_link_normal); 756 757int audio_graph2_link_dpcm(struct asoc_simple_priv *priv, 758 struct device_node *lnk, 759 struct link_info *li) 760{ 761 struct device_node *ep = port_to_endpoint(lnk); 762 struct device_node *rep = of_graph_get_remote_endpoint(ep); 763 struct device_node *rport = of_graph_get_remote_port(ep); 764 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 765 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); 766 int is_cpu = asoc_graph_is_ports0(lnk); 767 int ret; 768 769 if (is_cpu) { 770 /* 771 * dpcm { 772 * // Front-End 773 * ports@0 { 774 * => lnk: port@0 { ep: { ... = rep }; }; 775 * ... 776 * }; 777 * // Back-End 778 * ports@0 { 779 * ... 780 * }; 781 * }; 782 * 783 * CPU { 784 * rports: ports { 785 * rport: port@0 { rep: { ... = ep } }; 786 * } 787 * } 788 */ 789 /* 790 * setup CPU here, Codec is already set as dummy. 791 * see 792 * asoc_simple_init_priv() 793 */ 794 dai_link->dynamic = 1; 795 dai_link->dpcm_merged_format = 1; 796 797 ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 1); 798 if (ret) 799 goto err; 800 } else { 801 /* 802 * dpcm { 803 * // Front-End 804 * ports@0 { 805 * ... 806 * }; 807 * // Back-End 808 * ports@0 { 809 * => lnk: port@0 { ep: { ... = rep; }; }; 810 * ... 811 * }; 812 * }; 813 * 814 * Codec { 815 * rports: ports { 816 * rport: port@0 { rep: { ... = ep; }; }; 817 * } 818 * } 819 */ 820 /* 821 * setup Codec here, CPU is already set as dummy. 822 * see 823 * asoc_simple_init_priv() 824 */ 825 826 /* BE settings */ 827 dai_link->no_pcm = 1; 828 dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; 829 830 ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 0); 831 if (ret < 0) 832 goto err; 833 } 834 835 graph_parse_convert(rep, dai_props); 836 837 snd_soc_dai_link_set_capabilities(dai_link); 838 839 graph_link_init(priv, rport, li, is_cpu); 840err: 841 of_node_put(ep); 842 of_node_put(rep); 843 of_node_put(rport); 844 845 return ret; 846} 847EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm); 848 849int audio_graph2_link_c2c(struct asoc_simple_priv *priv, 850 struct device_node *lnk, 851 struct link_info *li) 852{ 853 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 854 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); 855 struct snd_soc_pcm_stream *c2c_conf = dai_props->c2c_conf; 856 struct device_node *port0, *port1, *ports; 857 struct device_node *codec0_port, *codec1_port; 858 struct device_node *ep0, *ep1; 859 u32 val; 860 int ret = -EINVAL; 861 862 /* 863 * codec2codec { 864 * ports { 865 * rate = <48000>; 866 * => lnk: port@0 { c2c0_ep: { ... = codec0_ep; }; }; 867 * port@1 { c2c1_ep: { ... = codec1_ep; }; }; 868 * }; 869 * }; 870 * 871 * Codec { 872 * ports { 873 * port@0 { codec0_ep: ... }; }; 874 * port@1 { codec1_ep: ... }; }; 875 * }; 876 * }; 877 */ 878 of_node_get(lnk); 879 port0 = lnk; 880 ports = of_get_parent(port0); 881 port1 = of_get_next_child(ports, lnk); 882 883 if (!of_get_property(ports, "rate", &val)) { 884 struct device *dev = simple_priv_to_dev(priv); 885 886 dev_err(dev, "Codec2Codec needs rate settings\n"); 887 goto err1; 888 } 889 890 c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */ 891 c2c_conf->rate_min = 892 c2c_conf->rate_max = val; 893 c2c_conf->channels_min = 894 c2c_conf->channels_max = 2; /* update ME */ 895 dai_link->params = c2c_conf; 896 897 ep0 = port_to_endpoint(port0); 898 ep1 = port_to_endpoint(port1); 899 900 codec0_port = of_graph_get_remote_port(ep0); 901 codec1_port = of_graph_get_remote_port(ep1); 902 903 /* 904 * call Codec first. 905 * see 906 * __graph_parse_node() :: DAI Naming 907 */ 908 ret = graph_parse_node(priv, GRAPH_C2C, codec1_port, li, 0); 909 if (ret < 0) 910 goto err2; 911 912 /* 913 * call CPU, and set DAI Name 914 */ 915 ret = graph_parse_node(priv, GRAPH_C2C, codec0_port, li, 1); 916 if (ret < 0) 917 goto err2; 918 919 graph_link_init(priv, codec0_port, li, 1); 920err2: 921 of_node_put(ep0); 922 of_node_put(ep1); 923 of_node_put(codec0_port); 924 of_node_put(codec1_port); 925err1: 926 of_node_put(ports); 927 of_node_put(port0); 928 of_node_put(port1); 929 930 return ret; 931} 932EXPORT_SYMBOL_GPL(audio_graph2_link_c2c); 933 934static int graph_link(struct asoc_simple_priv *priv, 935 struct graph2_custom_hooks *hooks, 936 enum graph_type gtype, 937 struct device_node *lnk, 938 struct link_info *li) 939{ 940 struct device *dev = simple_priv_to_dev(priv); 941 GRAPH2_CUSTOM func = NULL; 942 int ret = -EINVAL; 943 944 switch (gtype) { 945 case GRAPH_NORMAL: 946 if (hooks && hooks->custom_normal) 947 func = hooks->custom_normal; 948 else 949 func = audio_graph2_link_normal; 950 break; 951 case GRAPH_DPCM: 952 if (hooks && hooks->custom_dpcm) 953 func = hooks->custom_dpcm; 954 else 955 func = audio_graph2_link_dpcm; 956 break; 957 case GRAPH_C2C: 958 if (hooks && hooks->custom_c2c) 959 func = hooks->custom_c2c; 960 else 961 func = audio_graph2_link_c2c; 962 break; 963 default: 964 break; 965 } 966 967 if (!func) { 968 dev_err(dev, "non supported gtype (%d)\n", gtype); 969 goto err; 970 } 971 972 ret = func(priv, lnk, li); 973 if (ret < 0) 974 goto err; 975 976 li->link++; 977err: 978 return ret; 979} 980 981static int graph_counter(struct device_node *lnk) 982{ 983 /* 984 * Multi CPU / Codec 985 * 986 * multi { 987 * ports { 988 * => lnk: port@0 { ... }; 989 * port@1 { ... }; 990 * port@2 { ... }; 991 * ... 992 * }; 993 * }; 994 * 995 * ignore first lnk part 996 */ 997 if (graph_lnk_is_multi(lnk)) 998 return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1; 999 /* 1000 * Single CPU / Codec 1001 */ 1002 else 1003 return 1; 1004} 1005 1006static int graph_count_normal(struct asoc_simple_priv *priv, 1007 struct device_node *lnk, 1008 struct link_info *li) 1009{ 1010 struct device_node *cpu_port = lnk; 1011 struct device_node *cpu_ep = port_to_endpoint(cpu_port); 1012 struct device_node *codec_port = of_graph_get_remote_port(cpu_ep); 1013 1014 /* 1015 * CPU { 1016 * => lnk: port { endpoint { .. }; }; 1017 * }; 1018 */ 1019 li->num[li->link].cpus = 1020 li->num[li->link].platforms = graph_counter(cpu_port); 1021 li->num[li->link].codecs = graph_counter(codec_port); 1022 1023 of_node_put(cpu_ep); 1024 of_node_put(codec_port); 1025 1026 return 0; 1027} 1028 1029static int graph_count_dpcm(struct asoc_simple_priv *priv, 1030 struct device_node *lnk, 1031 struct link_info *li) 1032{ 1033 struct device_node *ep = port_to_endpoint(lnk); 1034 struct device_node *rport = of_graph_get_remote_port(ep); 1035 1036 /* 1037 * dpcm { 1038 * // Front-End 1039 * ports@0 { 1040 * => lnk: port@0 { endpoint { ... }; }; 1041 * ... 1042 * }; 1043 * // Back-End 1044 * ports@1 { 1045 * => lnk: port@0 { endpoint { ... }; }; 1046 * ... 1047 * }; 1048 * }; 1049 */ 1050 1051 if (asoc_graph_is_ports0(lnk)) { 1052 li->num[li->link].cpus = graph_counter(rport); /* FE */ 1053 li->num[li->link].platforms = graph_counter(rport); 1054 } else { 1055 li->num[li->link].codecs = graph_counter(rport); /* BE */ 1056 } 1057 1058 of_node_put(ep); 1059 of_node_put(rport); 1060 1061 return 0; 1062} 1063 1064static int graph_count_c2c(struct asoc_simple_priv *priv, 1065 struct device_node *lnk, 1066 struct link_info *li) 1067{ 1068 struct device_node *ports = of_get_parent(lnk); 1069 struct device_node *port0 = lnk; 1070 struct device_node *port1 = of_get_next_child(ports, lnk); 1071 struct device_node *ep0 = port_to_endpoint(port0); 1072 struct device_node *ep1 = port_to_endpoint(port1); 1073 struct device_node *codec0 = of_graph_get_remote_port(ep0); 1074 struct device_node *codec1 = of_graph_get_remote_port(ep1); 1075 1076 of_node_get(lnk); 1077 1078 /* 1079 * codec2codec { 1080 * ports { 1081 * => lnk: port@0 { endpoint { ... }; }; 1082 * port@1 { endpoint { ... }; }; 1083 * }; 1084 * }; 1085 */ 1086 li->num[li->link].cpus = 1087 li->num[li->link].platforms = graph_counter(codec0); 1088 li->num[li->link].codecs = graph_counter(codec1); 1089 li->num[li->link].c2c = 1; 1090 1091 of_node_put(ports); 1092 of_node_put(port1); 1093 of_node_put(ep0); 1094 of_node_put(ep1); 1095 of_node_put(codec0); 1096 of_node_put(codec1); 1097 1098 return 0; 1099} 1100 1101static int graph_count(struct asoc_simple_priv *priv, 1102 struct graph2_custom_hooks *hooks, 1103 enum graph_type gtype, 1104 struct device_node *lnk, 1105 struct link_info *li) 1106{ 1107 struct device *dev = simple_priv_to_dev(priv); 1108 GRAPH2_CUSTOM func = NULL; 1109 int ret = -EINVAL; 1110 1111 if (li->link >= SNDRV_MAX_LINKS) { 1112 dev_err(dev, "too many links\n"); 1113 return ret; 1114 } 1115 1116 switch (gtype) { 1117 case GRAPH_NORMAL: 1118 func = graph_count_normal; 1119 break; 1120 case GRAPH_DPCM: 1121 func = graph_count_dpcm; 1122 break; 1123 case GRAPH_C2C: 1124 func = graph_count_c2c; 1125 break; 1126 default: 1127 break; 1128 } 1129 1130 if (!func) { 1131 dev_err(dev, "non supported gtype (%d)\n", gtype); 1132 goto err; 1133 } 1134 1135 ret = func(priv, lnk, li); 1136 if (ret < 0) 1137 goto err; 1138 1139 li->link++; 1140err: 1141 return ret; 1142} 1143 1144static int graph_for_each_link(struct asoc_simple_priv *priv, 1145 struct graph2_custom_hooks *hooks, 1146 struct link_info *li, 1147 int (*func)(struct asoc_simple_priv *priv, 1148 struct graph2_custom_hooks *hooks, 1149 enum graph_type gtype, 1150 struct device_node *lnk, 1151 struct link_info *li)) 1152{ 1153 struct of_phandle_iterator it; 1154 struct device *dev = simple_priv_to_dev(priv); 1155 struct device_node *node = dev->of_node; 1156 struct device_node *lnk; 1157 enum graph_type gtype; 1158 int rc, ret; 1159 1160 /* loop for all listed CPU port */ 1161 of_for_each_phandle(&it, rc, node, "links", NULL, 0) { 1162 lnk = it.node; 1163 1164 gtype = graph_get_type(priv, lnk); 1165 1166 ret = func(priv, hooks, gtype, lnk, li); 1167 if (ret < 0) 1168 return ret; 1169 } 1170 1171 return 0; 1172} 1173 1174int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev, 1175 struct graph2_custom_hooks *hooks) 1176{ 1177 struct snd_soc_card *card = simple_priv_to_card(priv); 1178 struct link_info *li; 1179 int ret; 1180 1181 li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); 1182 if (!li) 1183 return -ENOMEM; 1184 1185 card->probe = asoc_graph_card_probe; 1186 card->owner = THIS_MODULE; 1187 card->dev = dev; 1188 1189 if ((hooks) && (hooks)->hook_pre) { 1190 ret = (hooks)->hook_pre(priv); 1191 if (ret < 0) 1192 goto err; 1193 } 1194 1195 ret = graph_for_each_link(priv, hooks, li, graph_count); 1196 if (!li->link) 1197 ret = -EINVAL; 1198 if (ret < 0) 1199 goto err; 1200 1201 ret = asoc_simple_init_priv(priv, li); 1202 if (ret < 0) 1203 goto err; 1204 1205 priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); 1206 if (IS_ERR(priv->pa_gpio)) { 1207 ret = PTR_ERR(priv->pa_gpio); 1208 dev_err(dev, "failed to get amplifier gpio: %d\n", ret); 1209 goto err; 1210 } 1211 1212 ret = asoc_simple_parse_widgets(card, NULL); 1213 if (ret < 0) 1214 goto err; 1215 1216 ret = asoc_simple_parse_routing(card, NULL); 1217 if (ret < 0) 1218 goto err; 1219 1220 memset(li, 0, sizeof(*li)); 1221 ret = graph_for_each_link(priv, hooks, li, graph_link); 1222 if (ret < 0) 1223 goto err; 1224 1225 ret = asoc_simple_parse_card_name(card, NULL); 1226 if (ret < 0) 1227 goto err; 1228 1229 snd_soc_card_set_drvdata(card, priv); 1230 1231 if ((hooks) && (hooks)->hook_post) { 1232 ret = (hooks)->hook_post(priv); 1233 if (ret < 0) 1234 goto err; 1235 } 1236 1237 asoc_simple_debug_info(priv); 1238 1239 ret = devm_snd_soc_register_card(dev, card); 1240err: 1241 devm_kfree(dev, li); 1242 1243 if (ret < 0) 1244 dev_err_probe(dev, ret, "parse error\n"); 1245 1246 if (ret == 0) 1247 dev_warn(dev, "Audio Graph Card2 is still under Experimental stage\n"); 1248 1249 return ret; 1250} 1251EXPORT_SYMBOL_GPL(audio_graph2_parse_of); 1252 1253static int graph_probe(struct platform_device *pdev) 1254{ 1255 struct asoc_simple_priv *priv; 1256 struct device *dev = &pdev->dev; 1257 1258 /* Allocate the private data and the DAI link array */ 1259 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 1260 if (!priv) 1261 return -ENOMEM; 1262 1263 return audio_graph2_parse_of(priv, dev, NULL); 1264} 1265 1266static const struct of_device_id graph_of_match[] = { 1267 { .compatible = "audio-graph-card2", }, 1268 {}, 1269}; 1270MODULE_DEVICE_TABLE(of, graph_of_match); 1271 1272static struct platform_driver graph_card = { 1273 .driver = { 1274 .name = "asoc-audio-graph-card2", 1275 .pm = &snd_soc_pm_ops, 1276 .of_match_table = graph_of_match, 1277 }, 1278 .probe = graph_probe, 1279 .remove = asoc_simple_remove, 1280}; 1281module_platform_driver(graph_card); 1282 1283MODULE_ALIAS("platform:asoc-audio-graph-card2"); 1284MODULE_LICENSE("GPL v2"); 1285MODULE_DESCRIPTION("ASoC Audio Graph Card2"); 1286MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");