File Index
Files and directories
Sign in
FILE

simple-card-utils.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/generic/simple-card-utils.c C
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// simple-card-utils.c
   4//
   5// Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   6
   7#include <dt-bindings/sound/audio-graph.h>
   8#include <linux/cleanup.h>
   9#include <linux/clk.h>
  10#include <linux/gpio/consumer.h>
  11#include <linux/module.h>
  12#include <linux/of.h>
  13#include <linux/of_graph.h>
  14#include <sound/jack.h>
  15#include <sound/pcm_params.h>
  16#include <sound/simple_card_utils.h>
  17
  18#define simple_ret(priv, ret) _simple_ret(priv, __func__, ret)
  19static inline int _simple_ret(struct simple_util_priv *priv,
  20			      const char *func, int ret)
  21{
  22	return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func);
  23}
  24
  25int simple_util_get_sample_fmt(struct simple_util_data *data)
  26{
  27	int i;
  28	int val = -EINVAL;
  29
  30	struct {
  31		char *fmt;
  32		u32 val;
  33	} of_sample_fmt_table[] = {
  34		{ "s8",		SNDRV_PCM_FORMAT_S8},
  35		{ "s16_le",	SNDRV_PCM_FORMAT_S16_LE},
  36		{ "s24_le",	SNDRV_PCM_FORMAT_S24_LE},
  37		{ "s24_3le",	SNDRV_PCM_FORMAT_S24_3LE},
  38		{ "s32_le",	SNDRV_PCM_FORMAT_S32_LE},
  39	};
  40
  41	for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) {
  42		if (!strcmp(data->convert_sample_format,
  43			    of_sample_fmt_table[i].fmt)) {
  44			val = of_sample_fmt_table[i].val;
  45			break;
  46		}
  47	}
  48	return val;
  49}
  50EXPORT_SYMBOL_GPL(simple_util_get_sample_fmt);
  51
  52static void simple_fixup_sample_fmt(struct simple_util_data *data,
  53				    struct snd_pcm_hw_params *params)
  54{
  55	int val;
  56	struct snd_mask *mask = hw_param_mask(params,
  57					      SNDRV_PCM_HW_PARAM_FORMAT);
  58
  59	val = simple_util_get_sample_fmt(data);
  60	if (val >= 0) {
  61		snd_mask_none(mask);
  62		snd_mask_set(mask, val);
  63	}
  64}
  65
  66void simple_util_parse_convert(struct device_node *np,
  67			       char *prefix,
  68			       struct simple_util_data *data)
  69{
  70	char prop[128];
  71
  72	if (!np)
  73		return;
  74
  75	if (!prefix)
  76		prefix = "";
  77
  78	/* sampling rate convert */
  79	snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
  80	of_property_read_u32(np, prop, &data->convert_rate);
  81
  82	/* channels transfer */
  83	snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
  84	of_property_read_u32(np, prop, &data->convert_channels);
  85
  86	/* convert sample format */
  87	snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-sample-format");
  88	of_property_read_string(np, prop, &data->convert_sample_format);
  89}
  90EXPORT_SYMBOL_GPL(simple_util_parse_convert);
  91
  92/**
  93 * simple_util_is_convert_required() - Query if HW param conversion was requested
  94 * @data: Link data.
  95 *
  96 * Returns true if any HW param conversion was requested for this DAI link with
  97 * any "convert-xxx" properties.
  98 */
  99bool simple_util_is_convert_required(const struct simple_util_data *data)
 100{
 101	return data->convert_rate ||
 102	       data->convert_channels ||
 103	       data->convert_sample_format;
 104}
 105EXPORT_SYMBOL_GPL(simple_util_is_convert_required);
 106
 107int simple_util_parse_daifmt(struct device *dev,
 108			     struct device_node *node,
 109			     struct device_node *codec,
 110			     char *prefix,
 111			     unsigned int *retfmt)
 112{
 113	struct device_node *bitclkmaster = NULL;
 114	struct device_node *framemaster = NULL;
 115	unsigned int daifmt;
 116
 117	daifmt = snd_soc_daifmt_parse_format(node, prefix);
 118
 119	snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster);
 120	if (!bitclkmaster && !framemaster) {
 121		/*
 122		 * No dai-link level and master setting was not found from
 123		 * sound node level, revert back to legacy DT parsing and
 124		 * take the settings from codec node.
 125		 */
 126		dev_dbg(dev, "Revert to legacy daifmt parsing\n");
 127
 128		daifmt |= snd_soc_daifmt_parse_clock_provider_as_flag(codec, NULL);
 129	} else {
 130		daifmt |= snd_soc_daifmt_clock_provider_from_bitmap(
 131				((codec == bitclkmaster) << 4) | (codec == framemaster));
 132	}
 133
 134	of_node_put(bitclkmaster);
 135	of_node_put(framemaster);
 136
 137	*retfmt = daifmt;
 138
 139	return 0;
 140}
 141EXPORT_SYMBOL_GPL(simple_util_parse_daifmt);
 142
 143int simple_util_parse_tdm_width_map(struct simple_util_priv *priv, struct device_node *np,
 144				    struct simple_util_dai *dai)
 145{
 146	struct device *dev = simple_priv_to_dev(priv);
 147	int n, i, ret;
 148	u32 *p;
 149
 150	/*
 151	 * NOTE
 152	 *
 153	 * Clang doesn't allow to use "goto end" before calling __free(),
 154	 * because it bypasses the initialization. Use simple_ret() directly.
 155	 */
 156
 157	n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32));
 158	if (n <= 0)
 159		return 0;
 160
 161	if (n % 3) {
 162		dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n");
 163		return simple_ret(priv, -EINVAL); /* see NOTE */
 164	}
 165
 166	ret = -ENOMEM;
 167	dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL);
 168	if (!dai->tdm_width_map)
 169		return simple_ret(priv, ret); /* see NOTE */
 170
 171	u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values), GFP_KERNEL);
 172	if (!array_values)
 173		goto end;
 174
 175	ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n);
 176	if (ret < 0) {
 177		dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret);
 178		goto end;
 179	}
 180
 181	p = array_values;
 182	for (i = 0; i < n / 3; ++i) {
 183		dai->tdm_width_map[i].sample_bits = *p++;
 184		dai->tdm_width_map[i].slot_width = *p++;
 185		dai->tdm_width_map[i].slot_count = *p++;
 186	}
 187
 188	dai->n_tdm_widths = i;
 189	ret = 0;
 190end:
 191	return simple_ret(priv, ret);
 192}
 193EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map);
 194
 195int simple_util_set_dailink_name(struct simple_util_priv *priv,
 196				 struct snd_soc_dai_link *dai_link,
 197				 const char *fmt, ...)
 198{
 199	struct device *dev = simple_priv_to_dev(priv);
 200	va_list ap;
 201	char *name = NULL;
 202	int ret = -ENOMEM;
 203
 204	va_start(ap, fmt);
 205	name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
 206	va_end(ap);
 207
 208	if (name) {
 209		ret = 0;
 210
 211		dai_link->name		= name;
 212		dai_link->stream_name	= name;
 213	}
 214
 215	return simple_ret(priv, ret);
 216}
 217EXPORT_SYMBOL_GPL(simple_util_set_dailink_name);
 218
 219int simple_util_parse_card_name(struct simple_util_priv *priv,
 220				char *prefix)
 221{
 222	struct snd_soc_card *card = simple_priv_to_card(priv);
 223	int ret;
 224
 225	if (!prefix)
 226		prefix = "";
 227
 228	/* Parse the card name from DT */
 229	ret = snd_soc_of_parse_card_name(card, "label");
 230	if (ret < 0 || !card->name) {
 231		char prop[128];
 232
 233		snprintf(prop, sizeof(prop), "%sname", prefix);
 234		ret = snd_soc_of_parse_card_name(card, prop);
 235		if (ret < 0)
 236			goto end;
 237	}
 238
 239	if (!card->name && card->dai_link)
 240		card->name = card->dai_link->name;
 241end:
 242	return simple_ret(priv, ret);
 243}
 244EXPORT_SYMBOL_GPL(simple_util_parse_card_name);
 245
 246static int simple_clk_enable(struct simple_util_dai *dai)
 247{
 248	if (dai)
 249		return clk_prepare_enable(dai->clk);
 250
 251	return 0;
 252}
 253
 254static void simple_clk_disable(struct simple_util_dai *dai)
 255{
 256	if (dai)
 257		clk_disable_unprepare(dai->clk);
 258}
 259
 260int simple_util_parse_clk(struct device *dev,
 261			  struct device_node *node,
 262			  struct simple_util_dai *simple_dai,
 263			  struct snd_soc_dai_link_component *dlc)
 264{
 265	struct clk *clk;
 266	u32 val;
 267
 268	/*
 269	 * Parse dai->sysclk come from "clocks = <&xxx>"
 270	 * (if system has common clock)
 271	 *  or "system-clock-frequency = <xxx>"
 272	 *  or device's module clock.
 273	 */
 274	clk = devm_get_clk_from_child(dev, node, NULL);
 275	simple_dai->clk_fixed = of_property_read_bool(
 276		node, "system-clock-fixed");
 277	if (!IS_ERR(clk)) {
 278		simple_dai->sysclk = clk_get_rate(clk);
 279
 280		simple_dai->clk = clk;
 281	} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
 282		simple_dai->sysclk = val;
 283		simple_dai->clk_fixed = true;
 284	} else {
 285		clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
 286		if (!IS_ERR(clk))
 287			simple_dai->sysclk = clk_get_rate(clk);
 288	}
 289
 290	if (of_property_read_bool(node, "system-clock-direction-out"))
 291		simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
 292
 293	return 0;
 294}
 295EXPORT_SYMBOL_GPL(simple_util_parse_clk);
 296
 297static int simple_check_fixed_sysclk(struct device *dev,
 298					  struct simple_util_dai *dai,
 299					  unsigned int *fixed_sysclk)
 300{
 301	if (dai->clk_fixed) {
 302		if (*fixed_sysclk && *fixed_sysclk != dai->sysclk) {
 303			dev_err(dev, "inconsistent fixed sysclk rates (%u vs %u)\n",
 304				*fixed_sysclk, dai->sysclk);
 305			return -EINVAL;
 306		}
 307		*fixed_sysclk = dai->sysclk;
 308	}
 309
 310	return 0;
 311}
 312
 313int simple_util_startup(struct snd_pcm_substream *substream)
 314{
 315	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 316	struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 317	struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
 318	struct simple_util_dai *dai;
 319	unsigned int fixed_sysclk = 0;
 320	int i1, i2, i;
 321	int ret;
 322
 323	for_each_prop_dai_cpu(props, i1, dai) {
 324		ret = simple_clk_enable(dai);
 325		if (ret)
 326			goto cpu_err;
 327		ret = simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
 328		if (ret)
 329			goto cpu_err;
 330	}
 331
 332	for_each_prop_dai_codec(props, i2, dai) {
 333		ret = simple_clk_enable(dai);
 334		if (ret)
 335			goto codec_err;
 336		ret = simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
 337		if (ret)
 338			goto codec_err;
 339	}
 340
 341	if (fixed_sysclk && props->mclk_fs) {
 342		unsigned int fixed_rate = fixed_sysclk / props->mclk_fs;
 343
 344		if (fixed_sysclk % props->mclk_fs) {
 345			dev_err(rtd->dev, "fixed sysclk %u not divisible by mclk_fs %u\n",
 346				fixed_sysclk, props->mclk_fs);
 347			ret = -EINVAL;
 348			goto codec_err;
 349		}
 350		ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
 351			fixed_rate, fixed_rate);
 352		if (ret < 0)
 353			goto codec_err;
 354	}
 355
 356	return 0;
 357
 358codec_err:
 359	for_each_prop_dai_codec(props, i, dai) {
 360		if (i >= i2)
 361			break;
 362		simple_clk_disable(dai);
 363	}
 364cpu_err:
 365	for_each_prop_dai_cpu(props, i, dai) {
 366		if (i >= i1)
 367			break;
 368		simple_clk_disable(dai);
 369	}
 370
 371	return simple_ret(priv, ret);
 372}
 373EXPORT_SYMBOL_GPL(simple_util_startup);
 374
 375void simple_util_shutdown(struct snd_pcm_substream *substream)
 376{
 377	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 378	struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 379	struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
 380	struct simple_util_dai *dai;
 381	int i;
 382
 383	for_each_prop_dai_cpu(props, i, dai) {
 384		struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, i);
 385
 386		if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(cpu_dai))
 387			snd_soc_dai_set_sysclk(cpu_dai, 0, 0, dai->clk_direction);
 388
 389		simple_clk_disable(dai);
 390	}
 391	for_each_prop_dai_codec(props, i, dai) {
 392		struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, i);
 393
 394		if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(codec_dai))
 395			snd_soc_dai_set_sysclk(codec_dai, 0, 0, dai->clk_direction);
 396
 397		simple_clk_disable(dai);
 398	}
 399}
 400EXPORT_SYMBOL_GPL(simple_util_shutdown);
 401
 402static int simple_set_clk_rate(struct simple_util_priv *priv,
 403			       struct simple_util_dai *simple_dai,
 404			       unsigned long rate)
 405{
 406	struct device *dev = simple_priv_to_dev(priv);
 407	int ret = -EINVAL;
 408
 409	if (!simple_dai)
 410		return 0;
 411
 412	if (simple_dai->clk_fixed && rate != simple_dai->sysclk) {
 413		dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate);
 414		goto end;
 415	}
 416
 417	if (!simple_dai->clk)
 418		return 0;
 419
 420	if (clk_get_rate(simple_dai->clk) == rate)
 421		return 0;
 422
 423	ret = clk_set_rate(simple_dai->clk, rate);
 424end:
 425	return simple_ret(priv, ret);
 426}
 427
 428static int simple_set_tdm(struct simple_util_priv *priv,
 429			  struct snd_soc_dai *dai,
 430			  struct simple_util_dai *simple_dai,
 431			  struct snd_pcm_hw_params *params)
 432{
 433	int sample_bits = params_width(params);
 434	int slot_width, slot_count;
 435	int i, ret;
 436
 437	if (!simple_dai || !simple_dai->tdm_width_map)
 438		return 0;
 439
 440	slot_width = simple_dai->slot_width;
 441	slot_count = simple_dai->slots;
 442
 443	if (slot_width == 0)
 444		slot_width = sample_bits;
 445
 446	for (i = 0; i < simple_dai->n_tdm_widths; ++i) {
 447		if (simple_dai->tdm_width_map[i].sample_bits == sample_bits) {
 448			slot_width = simple_dai->tdm_width_map[i].slot_width;
 449			slot_count = simple_dai->tdm_width_map[i].slot_count;
 450			break;
 451		}
 452	}
 453
 454	ret = snd_soc_dai_set_tdm_slot(dai,
 455				       simple_dai->tx_slot_mask,
 456				       simple_dai->rx_slot_mask,
 457				       slot_count,
 458				       slot_width);
 459
 460	return simple_ret(priv, ret);
 461}
 462
 463int simple_util_hw_params(struct snd_pcm_substream *substream,
 464			  struct snd_pcm_hw_params *params)
 465{
 466	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 467	struct simple_util_dai *pdai;
 468	struct snd_soc_dai *sdai;
 469	struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 470	struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
 471	unsigned int mclk, mclk_fs = 0;
 472	int i, ret;
 473
 474	if (props->mclk_fs)
 475		mclk_fs = props->mclk_fs;
 476
 477	if (mclk_fs) {
 478		struct snd_soc_component *component;
 479		mclk = params_rate(params) * mclk_fs;
 480
 481		for_each_prop_dai_codec(props, i, pdai) {
 482			ret = simple_set_clk_rate(priv, pdai, mclk);
 483			if (ret < 0)
 484				goto end;
 485		}
 486
 487		for_each_prop_dai_cpu(props, i, pdai) {
 488			ret = simple_set_clk_rate(priv, pdai, mclk);
 489			if (ret < 0)
 490				goto end;
 491		}
 492
 493		/* Ensure sysclk is set on all components in case any
 494		 * (such as platform components) are missed by calls to
 495		 * snd_soc_dai_set_sysclk.
 496		 */
 497		for_each_rtd_components(rtd, i, component) {
 498			ret = snd_soc_component_set_sysclk(component, 0, 0,
 499							   mclk, SND_SOC_CLOCK_IN);
 500			if (ret && ret != -ENOTSUPP)
 501				goto end;
 502		}
 503
 504		for_each_rtd_codec_dais(rtd, i, sdai) {
 505			pdai = simple_props_to_dai_codec(props, i);
 506			ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
 507			if (ret && ret != -ENOTSUPP)
 508				goto end;
 509		}
 510
 511		for_each_rtd_cpu_dais(rtd, i, sdai) {
 512			pdai = simple_props_to_dai_cpu(props, i);
 513			ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
 514			if (ret && ret != -ENOTSUPP)
 515				goto end;
 516		}
 517	}
 518
 519	for_each_prop_dai_codec(props, i, pdai) {
 520		sdai = snd_soc_rtd_to_codec(rtd, i);
 521		ret = simple_set_tdm(priv, sdai, pdai, params);
 522		if (ret < 0)
 523			goto end;
 524	}
 525
 526	for_each_prop_dai_cpu(props, i, pdai) {
 527		sdai = snd_soc_rtd_to_cpu(rtd, i);
 528		ret = simple_set_tdm(priv, sdai, pdai, params);
 529		if (ret < 0)
 530			goto end;
 531	}
 532	ret = 0;
 533end:
 534	return simple_ret(priv, ret);
 535}
 536EXPORT_SYMBOL_GPL(simple_util_hw_params);
 537
 538int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 539				   struct snd_pcm_hw_params *params)
 540{
 541	struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 542	struct simple_dai_props *dai_props = runtime_simple_priv_to_props(priv, rtd);
 543	struct simple_util_data *data = &dai_props->adata;
 544	struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 545	struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
 546
 547	if (data->convert_rate)
 548		rate->min =
 549		rate->max = data->convert_rate;
 550
 551	if (data->convert_channels)
 552		channels->min =
 553		channels->max = data->convert_channels;
 554
 555	if (data->convert_sample_format)
 556		simple_fixup_sample_fmt(data, params);
 557
 558	return 0;
 559}
 560EXPORT_SYMBOL_GPL(simple_util_be_hw_params_fixup);
 561
 562static int simple_init_dai(struct simple_util_priv *priv,
 563			   struct snd_soc_dai *dai, struct simple_util_dai *simple_dai)
 564{
 565	int ret;
 566
 567	if (!simple_dai)
 568		return 0;
 569
 570	if (simple_dai->sysclk) {
 571		ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
 572					     simple_dai->clk_direction);
 573		if (ret && ret != -ENOTSUPP) {
 574			dev_err(dai->dev, "simple-card: set_sysclk error\n");
 575			goto end;
 576		}
 577	}
 578
 579	if (simple_dai->slots) {
 580		ret = snd_soc_dai_set_tdm_slot(dai,
 581					       simple_dai->tx_slot_mask,
 582					       simple_dai->rx_slot_mask,
 583					       simple_dai->slots,
 584					       simple_dai->slot_width);
 585		if (ret && ret != -ENOTSUPP) {
 586			dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
 587			goto end;
 588		}
 589	}
 590	ret = 0;
 591end:
 592	return simple_ret(priv, ret);
 593}
 594
 595static inline int simple_component_is_codec(struct snd_soc_component *component)
 596{
 597	return component->driver->endianness;
 598}
 599
 600static int simple_init_for_codec2codec(struct simple_util_priv *priv,
 601				       struct snd_soc_pcm_runtime *rtd,
 602				       struct simple_dai_props *dai_props)
 603{
 604	struct snd_soc_dai_link *dai_link = rtd->dai_link;
 605	struct snd_soc_component *component;
 606	struct snd_soc_pcm_stream *c2c_params;
 607	struct snd_pcm_hardware hw;
 608	int i, ret, stream;
 609
 610	/* Do nothing if it already has Codec2Codec settings */
 611	if (dai_link->c2c_params)
 612		return 0;
 613
 614	/* Do nothing if it was DPCM :: BE */
 615	if (dai_link->no_pcm)
 616		return 0;
 617
 618	/* Only Codecs */
 619	for_each_rtd_components(rtd, i, component) {
 620		if (!simple_component_is_codec(component))
 621			return 0;
 622	}
 623
 624	/* Assumes the capabilities are the same for all supported streams */
 625	for_each_pcm_streams(stream) {
 626		ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
 627		if (ret == 0)
 628			break;
 629	}
 630
 631	if (ret < 0) {
 632		dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
 633		goto end;
 634	}
 635
 636	ret = -ENOMEM;
 637	c2c_params = devm_kzalloc(rtd->dev, sizeof(*c2c_params), GFP_KERNEL);
 638	if (!c2c_params)
 639		goto end;
 640
 641	c2c_params->formats		= hw.formats;
 642	c2c_params->rates		= hw.rates;
 643	c2c_params->rate_min		= hw.rate_min;
 644	c2c_params->rate_max		= hw.rate_max;
 645	c2c_params->channels_min	= hw.channels_min;
 646	c2c_params->channels_max	= hw.channels_max;
 647
 648	dai_link->c2c_params		= c2c_params;
 649	dai_link->num_c2c_params	= 1;
 650
 651	ret = 0;
 652end:
 653	return simple_ret(priv, ret);
 654}
 655
 656int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd)
 657{
 658	struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 659	struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
 660	struct simple_util_dai *dai;
 661	int i, ret;
 662
 663	for_each_prop_dai_codec(props, i, dai) {
 664		ret = simple_init_dai(priv, snd_soc_rtd_to_codec(rtd, i), dai);
 665		if (ret < 0)
 666			goto end;
 667	}
 668	for_each_prop_dai_cpu(props, i, dai) {
 669		ret = simple_init_dai(priv, snd_soc_rtd_to_cpu(rtd, i), dai);
 670		if (ret < 0)
 671			goto end;
 672	}
 673
 674	ret = simple_init_for_codec2codec(priv, rtd, props);
 675end:
 676	return simple_ret(priv, ret);
 677}
 678EXPORT_SYMBOL_GPL(simple_util_dai_init);
 679
 680void simple_util_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
 681				       struct snd_soc_dai_link_component *cpus)
 682{
 683	/*
 684	 * Assumes Platform == CPU
 685	 *
 686	 * Some CPU might be using soc-generic-dmaengine-pcm. This means CPU and Platform
 687	 * are different Component, but are sharing same component->dev.
 688	 *
 689	 * Let's assume Platform is same as CPU if it doesn't identify Platform on DT.
 690	 * see
 691	 *	simple-card.c :: simple_count_noml()
 692	 */
 693	if (!platforms->of_node)
 694		snd_soc_dlc_use_cpu_as_platform(platforms, cpus);
 695}
 696EXPORT_SYMBOL_GPL(simple_util_canonicalize_platform);
 697
 698void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
 699				  int is_single_links)
 700{
 701	/*
 702	 * In soc_bind_dai_link() will check cpu name after
 703	 * of_node matching if dai_link has cpu_dai_name.
 704	 * but, it will never match if name was created by
 705	 * fmt_single_name() remove cpu_dai_name if cpu_args
 706	 * was 0. See:
 707	 *	fmt_single_name()
 708	 *	fmt_multiple_name()
 709	 */
 710	if (is_single_links)
 711		cpus->dai_name = NULL;
 712}
 713EXPORT_SYMBOL_GPL(simple_util_canonicalize_cpu);
 714
 715void simple_util_clean_reference(struct snd_soc_card *card)
 716{
 717	struct snd_soc_dai_link *dai_link;
 718	struct snd_soc_dai_link_component *cpu;
 719	struct snd_soc_dai_link_component *codec;
 720	int i, j;
 721
 722	for_each_card_prelinks(card, i, dai_link) {
 723		for_each_link_cpus(dai_link, j, cpu)
 724			of_node_put(cpu->of_node);
 725		for_each_link_codecs(dai_link, j, codec)
 726			of_node_put(codec->of_node);
 727	}
 728}
 729EXPORT_SYMBOL_GPL(simple_util_clean_reference);
 730
 731int simple_util_parse_routing(struct snd_soc_card *card,
 732			      char *prefix)
 733{
 734	struct device_node *node = card->dev->of_node;
 735	char prop[128];
 736
 737	if (!prefix)
 738		prefix = "";
 739
 740	snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
 741
 742	if (!of_property_present(node, prop))
 743		return 0;
 744
 745	return snd_soc_of_parse_audio_routing(card, prop);
 746}
 747EXPORT_SYMBOL_GPL(simple_util_parse_routing);
 748
 749int simple_util_parse_widgets(struct snd_soc_card *card,
 750			      char *prefix)
 751{
 752	struct device_node *node = card->dev->of_node;
 753	char prop[128];
 754
 755	if (!prefix)
 756		prefix = "";
 757
 758	snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
 759
 760	if (of_property_present(node, prop))
 761		return snd_soc_of_parse_audio_simple_widgets(card, prop);
 762
 763	/* no widgets is not error */
 764	return 0;
 765}
 766EXPORT_SYMBOL_GPL(simple_util_parse_widgets);
 767
 768int simple_util_parse_pin_switches(struct snd_soc_card *card,
 769				   char *prefix)
 770{
 771	char prop[128];
 772
 773	if (!prefix)
 774		prefix = "";
 775
 776	snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
 777
 778	return snd_soc_of_parse_pin_switches(card, prop);
 779}
 780EXPORT_SYMBOL_GPL(simple_util_parse_pin_switches);
 781
 782int simple_util_init_jack(struct snd_soc_card *card,
 783			  struct simple_util_jack *sjack,
 784			  int is_hp, char *prefix,
 785			  char *pin)
 786{
 787	struct device *dev = card->dev;
 788	struct gpio_desc *desc;
 789	char prop[128];
 790	char *pin_name;
 791	char *gpio_name;
 792	int mask;
 793	int error;
 794
 795	if (!prefix)
 796		prefix = "";
 797
 798	if (is_hp) {
 799		snprintf(prop, sizeof(prop), "%shp-det", prefix);
 800		pin_name	= pin ? pin : "Headphones";
 801		gpio_name	= "Headphone detection";
 802		mask		= SND_JACK_HEADPHONE;
 803	} else {
 804		snprintf(prop, sizeof(prop), "%smic-det", prefix);
 805		pin_name	= pin ? pin : "Mic Jack";
 806		gpio_name	= "Mic detection";
 807		mask		= SND_JACK_MICROPHONE;
 808	}
 809
 810	desc = gpiod_get_optional(dev, prop, GPIOD_IN);
 811	error = PTR_ERR_OR_ZERO(desc);
 812	if (error)
 813		return error;
 814
 815	if (desc) {
 816		error = gpiod_set_consumer_name(desc, gpio_name);
 817		if (error)
 818			return error;
 819
 820		sjack->pin.pin		= pin_name;
 821		sjack->pin.mask		= mask;
 822
 823		sjack->gpio.name	= gpio_name;
 824		sjack->gpio.report	= mask;
 825		sjack->gpio.desc	= desc;
 826		sjack->gpio.debounce_time = 150;
 827
 828		snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack,
 829					   &sjack->pin, 1);
 830
 831		snd_soc_jack_add_gpios(&sjack->jack, 1, &sjack->gpio);
 832	}
 833
 834	return 0;
 835}
 836EXPORT_SYMBOL_GPL(simple_util_init_jack);
 837
 838int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix)
 839{
 840	struct snd_soc_card *card = simple_priv_to_card(priv);
 841	struct snd_soc_component *component;
 842	int found_jack_index = 0;
 843	int type = 0;
 844	int num = 0;
 845	int ret;
 846
 847	if (priv->aux_jacks)
 848		return 0;
 849
 850	for_each_card_auxs(card, component) {
 851		type = snd_soc_component_get_jack_type(component);
 852		if (type > 0)
 853			num++;
 854	}
 855	if (num < 1)
 856		return 0;
 857
 858	priv->aux_jacks = devm_kcalloc(card->dev, num,
 859				       sizeof(struct snd_soc_jack), GFP_KERNEL);
 860	if (!priv->aux_jacks)
 861		return simple_ret(priv, -ENOMEM);
 862
 863	for_each_card_auxs(card, component) {
 864		char id[128];
 865		struct snd_soc_jack *jack;
 866
 867		if (found_jack_index >= num)
 868			break;
 869
 870		type = snd_soc_component_get_jack_type(component);
 871		if (type <= 0)
 872			continue;
 873
 874		/* create jack */
 875		jack = &(priv->aux_jacks[found_jack_index++]);
 876		snprintf(id, sizeof(id), "%s-jack", component->name);
 877		ret = snd_soc_card_jack_new(card, id, type, jack);
 878		if (ret)
 879			continue;
 880
 881		(void)snd_soc_component_set_jack(component, jack, NULL);
 882	}
 883	return 0;
 884}
 885EXPORT_SYMBOL_GPL(simple_util_init_aux_jacks);
 886
 887static struct simple_util_dai dummy_util_dais = {
 888	.name = "dummy_util_dais",
 889};
 890
 891int simple_util_init_priv(struct simple_util_priv *priv,
 892			  struct link_info *li)
 893{
 894	struct snd_soc_card *card = simple_priv_to_card(priv);
 895	struct device *dev = simple_priv_to_dev(priv);
 896	struct snd_soc_dai_link *dai_link;
 897	struct simple_dai_props *dai_props;
 898	struct simple_util_dai *dais;
 899	struct snd_soc_dai_link_component *dlcs;
 900	struct snd_soc_codec_conf *cconf = NULL;
 901	int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
 902
 903	dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
 904	dai_link  = devm_kcalloc(dev, li->link, sizeof(*dai_link),  GFP_KERNEL);
 905	if (!dai_props || !dai_link)
 906		return -ENOMEM;
 907
 908	/*
 909	 * dais (= CPU+Codec)
 910	 * dlcs (= CPU+Codec+Platform)
 911	 */
 912	for (i = 0; i < li->link; i++) {
 913		int cc = li->num[i].cpus + li->num[i].codecs;
 914
 915		dai_num += cc;
 916		dlc_num += cc + li->num[i].platforms;
 917
 918		if (!li->num[i].cpus)
 919			cnf_num += li->num[i].codecs;
 920	}
 921
 922	dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
 923	dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL);
 924	if (!dais || !dlcs)
 925		return -ENOMEM;
 926
 927	if (cnf_num) {
 928		cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
 929		if (!cconf)
 930			return -ENOMEM;
 931	}
 932
 933	dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
 934		li->link, dai_num, cnf_num);
 935
 936	priv->dai_props		= dai_props;
 937	priv->dai_link		= dai_link;
 938	priv->dais		= dais;
 939	priv->dlcs		= dlcs;
 940	priv->codec_conf	= cconf;
 941
 942	card->dai_link		= priv->dai_link;
 943	card->num_links		= li->link;
 944	card->codec_conf	= cconf;
 945	card->num_configs	= cnf_num;
 946
 947	for (i = 0; i < li->link; i++) {
 948		if (li->num[i].cpus) {
 949			/* Normal CPU */
 950			dai_link[i].cpus	= dlcs;
 951			dai_props[i].num.cpus	=
 952			dai_link[i].num_cpus	= li->num[i].cpus;
 953			dai_props[i].cpu_dai	= dais;
 954
 955			dlcs += li->num[i].cpus;
 956			dais += li->num[i].cpus;
 957		} else {
 958			/* DPCM Be's CPU = dummy */
 959			dai_link[i].cpus	= &snd_soc_dummy_dlc;
 960			dai_props[i].num.cpus	=
 961			dai_link[i].num_cpus	= 1;
 962			dai_props[i].cpu_dai	= &dummy_util_dais;
 963		}
 964
 965		if (li->num[i].codecs) {
 966			/* Normal Codec */
 967			dai_link[i].codecs	= dlcs;
 968			dai_props[i].num.codecs	=
 969			dai_link[i].num_codecs	= li->num[i].codecs;
 970			dai_props[i].codec_dai	= dais;
 971
 972			dlcs += li->num[i].codecs;
 973			dais += li->num[i].codecs;
 974
 975			if (!li->num[i].cpus) {
 976				/* DPCM Be's Codec */
 977				dai_props[i].codec_conf = cconf;
 978				cconf += li->num[i].codecs;
 979			}
 980		} else {
 981			/* DPCM Fe's Codec = dummy */
 982			dai_link[i].codecs	= &snd_soc_dummy_dlc;
 983			dai_props[i].num.codecs	=
 984			dai_link[i].num_codecs	= 1;
 985			dai_props[i].codec_dai	= &dummy_util_dais;
 986		}
 987
 988		if (li->num[i].platforms) {
 989			/* Have Platform */
 990			dai_link[i].platforms		= dlcs;
 991			dai_props[i].num.platforms	=
 992			dai_link[i].num_platforms	= li->num[i].platforms;
 993
 994			dlcs += li->num[i].platforms;
 995		} else {
 996			/* Doesn't have Platform */
 997			dai_link[i].platforms		= NULL;
 998			dai_props[i].num.platforms	=
 999			dai_link[i].num_platforms	= 0;
1000		}
1001	}
1002
1003	return 0;
1004}
1005EXPORT_SYMBOL_GPL(simple_util_init_priv);
1006
1007void simple_util_remove(struct platform_device *pdev)
1008{
1009	struct snd_soc_card *card = platform_get_drvdata(pdev);
1010
1011	simple_util_clean_reference(card);
1012}
1013EXPORT_SYMBOL_GPL(simple_util_remove);
1014
1015int graph_util_card_probe(struct snd_soc_card *card)
1016{
1017	struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
1018	int ret;
1019
1020	ret = simple_util_init_hp(card, &priv->hp_jack, NULL);
1021	if (ret < 0)
1022		goto end;
1023
1024	ret = simple_util_init_mic(card, &priv->mic_jack, NULL);
1025end:
1026	return simple_ret(priv, ret);
1027}
1028EXPORT_SYMBOL_GPL(graph_util_card_probe);
1029
1030int graph_util_is_ports0(struct device_node *np)
1031{
1032	struct device_node *parent __free(device_node) = of_get_parent(np);
1033	struct device_node *port;
1034
1035	/* np is "endpoint" or "port" */
1036	if (of_node_name_eq(np, "endpoint"))
1037		port = parent;
1038	else
1039		port = np;
1040
1041	struct device_node *ports __free(device_node) = of_get_parent(port);
1042	const char *at = strchr(kbasename(ports->full_name), '@');
1043
1044	/*
1045	 * Since child iteration order may differ
1046	 * between a base DT and DT overlays,
1047	 * string match "ports" or "ports@0" in the node name instead.
1048	 */
1049	return !at || !strcmp(at, "@0");
1050}
1051EXPORT_SYMBOL_GPL(graph_util_is_ports0);
1052
1053static int graph_get_dai_id(struct device_node *ep)
1054{
1055	struct device_node *node __free(device_node) = of_graph_get_port_parent(ep);
1056	struct device_node *port __free(device_node) = of_get_parent(ep);
1057	struct of_endpoint info;
1058	int i, id;
1059	int ret;
1060
1061	/* use driver specified DAI ID if exist */
1062	ret = snd_soc_get_dai_id(ep);
1063	if (ret != -ENOTSUPP)
1064		return ret;
1065
1066	/* use endpoint/port reg if exist */
1067	ret = of_graph_parse_endpoint(ep, &info);
1068	if (ret == 0) {
1069		/*
1070		 * Because it will count port/endpoint if it doesn't have "reg".
1071		 * But, we can't judge whether it has "no reg", or "reg = <0>"
1072		 * only of_graph_parse_endpoint().
1073		 * We need to check "reg" property
1074		 */
1075
1076		/* check port first */
1077		ret = of_property_present(port, "reg");
1078		if (ret)
1079			return info.port;
1080
1081		/* check endpoint 2nd as backup */
1082		if (of_property_present(ep,   "reg"))
1083			return info.id;
1084	}
1085
1086	/*
1087	 * Non HDMI sound case, counting port/endpoint on its DT
1088	 * is enough. Let's count it.
1089	 */
1090	i = 0;
1091	id = -1;
1092	for_each_of_graph_port(node, p) {
1093		if (port == p) {
1094			id = i;
1095			break;
1096		}
1097		i++;
1098	}
1099
1100	if (id < 0)
1101		return -ENODEV;
1102
1103	return id;
1104}
1105
1106int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep,
1107			 struct snd_soc_dai_link_component *dlc, int *is_single_link)
1108{
1109	struct device *dev = simple_priv_to_dev(priv);
1110	struct device_node *node;
1111	struct of_phandle_args args = {};
1112	struct snd_soc_dai *dai;
1113	int ret;
1114
1115	if (!ep)
1116		return 0;
1117
1118	node = of_graph_get_port_parent(ep);
1119
1120	/*
1121	 * Try to find from DAI node
1122	 */
1123	args.np = ep;
1124	dai = snd_soc_get_dai_via_args(&args);
1125	if (dai) {
1126		const char *dai_name = snd_soc_dai_name_get(dai);
1127		const struct of_phandle_args *dai_args = snd_soc_copy_dai_args(dev, &args);
1128
1129		ret = -ENOMEM;
1130		if (!dai_args)
1131			goto err;
1132
1133		dlc->of_node  = node;
1134		dlc->dai_name = dai_name;
1135		dlc->dai_args = dai_args;
1136
1137		goto parse_dai_end;
1138	}
1139
1140	/* Get dai->name */
1141	args.np		= node;
1142	args.args[0]	= graph_get_dai_id(ep);
1143	args.args_count	= (of_graph_get_endpoint_count(node) > 1);
1144
1145	/*
1146	 * FIXME
1147	 *
1148	 * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
1149	 * If user unbinded CPU or Codec driver, but not for Sound Card,
1150	 * dlc->dai_name is keeping unbinded CPU or Codec
1151	 * driver's pointer.
1152	 *
1153	 * If user re-bind CPU or Codec driver again, ALSA SoC will try
1154	 * to rebind Card via snd_soc_try_rebind_card(), but because of
1155	 * above reason, it might can't bind Sound Card.
1156	 * Because Sound Card is pointing to released dai_name pointer.
1157	 *
1158	 * To avoid this rebind Card issue,
1159	 * 1) It needs to alloc memory to keep dai_name eventhough
1160	 *    CPU or Codec driver was unbinded, or
1161	 * 2) user need to rebind Sound Card everytime
1162	 *    if he unbinded CPU or Codec.
1163	 */
1164	ret = snd_soc_get_dlc(&args, dlc);
1165	if (ret < 0)
1166		goto err;
1167
1168parse_dai_end:
1169	if (is_single_link)
1170		*is_single_link = of_graph_get_endpoint_count(node) == 1;
1171	ret = 0;
1172err:
1173	if (ret < 0)
1174		of_node_put(node);
1175
1176	return simple_ret(priv, ret);
1177}
1178EXPORT_SYMBOL_GPL(graph_util_parse_dai);
1179
1180void graph_util_parse_link_direction(struct device_node *np,
1181				    bool *playback_only, bool *capture_only)
1182{
1183	bool is_playback_only = of_property_read_bool(np, "playback-only");
1184	bool is_capture_only  = of_property_read_bool(np, "capture-only");
1185
1186	if (playback_only && is_playback_only)
1187		*playback_only = is_playback_only;
1188	if (capture_only && is_capture_only)
1189		*capture_only = is_capture_only;
1190}
1191EXPORT_SYMBOL_GPL(graph_util_parse_link_direction);
1192
1193static enum snd_soc_trigger_order
1194__graph_util_parse_trigger_order(struct simple_util_priv *priv,
1195				 struct device_node *np,
1196				 const char *prop)
1197{
1198	u32 val[SND_SOC_TRIGGER_SIZE];
1199	int ret;
1200
1201	ret = of_property_read_u32_array(np, prop, val, SND_SOC_TRIGGER_SIZE);
1202	if (ret == 0) {
1203		struct device *dev = simple_priv_to_dev(priv);
1204		u32 order =	(val[0] << 8) +
1205			(val[1] << 4) +
1206			(val[2]);
1207
1208		switch (order) {
1209		case	(SND_SOC_TRIGGER_LINK		<< 8) +
1210			(SND_SOC_TRIGGER_COMPONENT	<< 4) +
1211			(SND_SOC_TRIGGER_DAI):
1212			return SND_SOC_TRIGGER_ORDER_DEFAULT;
1213
1214		case	(SND_SOC_TRIGGER_LINK		<< 8) +
1215			(SND_SOC_TRIGGER_DAI		<< 4) +
1216			(SND_SOC_TRIGGER_COMPONENT):
1217			return SND_SOC_TRIGGER_ORDER_LDC;
1218
1219		default:
1220			dev_err(dev, "unsupported trigger order [0x%x]\n", order);
1221		}
1222	}
1223
1224	/* SND_SOC_TRIGGER_ORDER_MAX means error */
1225	return SND_SOC_TRIGGER_ORDER_MAX;
1226}
1227
1228void graph_util_parse_trigger_order(struct simple_util_priv *priv,
1229				    struct device_node *np,
1230				    enum snd_soc_trigger_order *trigger_start,
1231				    enum snd_soc_trigger_order *trigger_stop)
1232{
1233	static enum snd_soc_trigger_order order;
1234
1235	/*
1236	 * We can use it like below
1237	 *
1238	 * #include <dt-bindings/sound/audio-graph.h>
1239	 *
1240	 * link-trigger-order = <SND_SOC_TRIGGER_LINK
1241	 *			 SND_SOC_TRIGGER_COMPONENT
1242	 *			 SND_SOC_TRIGGER_DAI>;
1243	 */
1244
1245	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order");
1246	if (order < SND_SOC_TRIGGER_ORDER_MAX) {
1247		*trigger_start = order;
1248		*trigger_stop  = order;
1249	}
1250
1251	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-start");
1252	if (order < SND_SOC_TRIGGER_ORDER_MAX)
1253		*trigger_start = order;
1254
1255	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-stop");
1256	if (order < SND_SOC_TRIGGER_ORDER_MAX)
1257		*trigger_stop  = order;
1258
1259	return;
1260}
1261EXPORT_SYMBOL_GPL(graph_util_parse_trigger_order);
1262
1263/* Module information */
1264MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
1265MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
1266MODULE_LICENSE("GPL v2");
~/ Read-only file preview.