File Index
Files and directories
Sign in
FILE

audio-graph-card2.c

File preview with syntax highlighting.

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