Linux Audio

Check our new training course

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