xref: /linux/sound/soc/generic/simple-card-utils.c (revision dc1d9408c961c1c4d4b3b99a1d9390c17e13de71)
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)
_simple_ret(struct simple_util_priv * priv,const char * func,int ret)19 static 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 
simple_util_get_sample_fmt(struct simple_util_data * data)25 int 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 }
50 EXPORT_SYMBOL_GPL(simple_util_get_sample_fmt);
51 
simple_fixup_sample_fmt(struct simple_util_data * data,struct snd_pcm_hw_params * params)52 static 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 
simple_util_parse_convert(struct device_node * np,char * prefix,struct simple_util_data * data)66 void 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 }
90 EXPORT_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  */
simple_util_is_convert_required(const struct simple_util_data * data)99 bool 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 }
105 EXPORT_SYMBOL_GPL(simple_util_is_convert_required);
106 
simple_util_parse_daifmt(struct device * dev,struct device_node * node,struct device_node * codec,char * prefix,unsigned int * retfmt)107 int 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 }
141 EXPORT_SYMBOL_GPL(simple_util_parse_daifmt);
142 
simple_util_parse_tdm_width_map(struct simple_util_priv * priv,struct device_node * np,struct simple_util_dai * dai)143 int 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;
190 end:
191 	return simple_ret(priv, ret);
192 }
193 EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map);
194 
simple_util_set_dailink_name(struct simple_util_priv * priv,struct snd_soc_dai_link * dai_link,const char * fmt,...)195 int 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 }
217 EXPORT_SYMBOL_GPL(simple_util_set_dailink_name);
218 
simple_util_parse_card_name(struct simple_util_priv * priv,char * prefix)219 int 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;
241 end:
242 	return simple_ret(priv, ret);
243 }
244 EXPORT_SYMBOL_GPL(simple_util_parse_card_name);
245 
simple_clk_enable(struct simple_util_dai * dai)246 static 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 
simple_clk_disable(struct simple_util_dai * dai)254 static void simple_clk_disable(struct simple_util_dai *dai)
255 {
256 	if (dai)
257 		clk_disable_unprepare(dai->clk);
258 }
259 
simple_util_parse_clk(struct device * dev,struct device_node * node,struct simple_util_dai * simple_dai,struct snd_soc_dai_link_component * dlc)260 int 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 }
295 EXPORT_SYMBOL_GPL(simple_util_parse_clk);
296 
simple_check_fixed_sysclk(struct device * dev,struct simple_util_dai * dai,unsigned int * fixed_sysclk)297 static 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 
simple_util_startup(struct snd_pcm_substream * substream)313 int 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 
358 codec_err:
359 	for_each_prop_dai_codec(props, i, dai) {
360 		if (i >= i2)
361 			break;
362 		simple_clk_disable(dai);
363 	}
364 cpu_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 }
373 EXPORT_SYMBOL_GPL(simple_util_startup);
374 
simple_util_shutdown(struct snd_pcm_substream * substream)375 void 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 }
400 EXPORT_SYMBOL_GPL(simple_util_shutdown);
401 
simple_set_clk_rate(struct simple_util_priv * priv,struct simple_util_dai * simple_dai,unsigned long rate)402 static 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);
424 end:
425 	return simple_ret(priv, ret);
426 }
427 
simple_set_tdm(struct simple_util_priv * priv,struct snd_soc_dai * dai,struct simple_util_dai * simple_dai,struct snd_pcm_hw_params * params)428 static 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 
simple_util_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)463 int 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 	enum simple_util_sysclk_order order = props->sysclk_order;
472 	unsigned int mclk, mclk_fs = 0;
473 	int i, ret;
474 
475 	if (props->mclk_fs)
476 		mclk_fs = props->mclk_fs;
477 
478 	if (mclk_fs) {
479 		struct snd_soc_component *component;
480 		mclk = params_rate(params) * mclk_fs;
481 
482 		for_each_prop_dai_codec(props, i, pdai) {
483 			ret = simple_set_clk_rate(priv, pdai, mclk);
484 			if (ret < 0)
485 				goto end;
486 		}
487 
488 		for_each_prop_dai_cpu(props, i, pdai) {
489 			ret = simple_set_clk_rate(priv, pdai, mclk);
490 			if (ret < 0)
491 				goto end;
492 		}
493 
494 		/* Ensure sysclk is set on all components in case any
495 		 * (such as platform components) are missed by calls to
496 		 * snd_soc_dai_set_sysclk.
497 		 */
498 		for_each_rtd_components(rtd, i, component) {
499 			ret = snd_soc_component_set_sysclk(component, 0, 0,
500 							   mclk, SND_SOC_CLOCK_IN);
501 			if (ret && ret != -ENOTSUPP)
502 				goto end;
503 		}
504 
505 		if (order == SIMPLE_SYSCLK_ORDER_CPU_FIRST) {
506 			/* CPU first */
507 			for_each_rtd_cpu_dais(rtd, i, sdai) {
508 				pdai = simple_props_to_dai_cpu(props, i);
509 				ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
510 				if (ret && ret != -ENOTSUPP)
511 					goto end;
512 			}
513 
514 			for_each_rtd_codec_dais(rtd, i, sdai) {
515 				pdai = simple_props_to_dai_codec(props, i);
516 				ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
517 				if (ret && ret != -ENOTSUPP)
518 					goto end;
519 			}
520 		} else {
521 			/* default: codec first */
522 			for_each_rtd_codec_dais(rtd, i, sdai) {
523 				pdai = simple_props_to_dai_codec(props, i);
524 				ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
525 				if (ret && ret != -ENOTSUPP)
526 					goto end;
527 			}
528 
529 			for_each_rtd_cpu_dais(rtd, i, sdai) {
530 				pdai = simple_props_to_dai_cpu(props, i);
531 				ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
532 				if (ret && ret != -ENOTSUPP)
533 					goto end;
534 			}
535 		}
536 	}
537 
538 	for_each_prop_dai_codec(props, i, pdai) {
539 		sdai = snd_soc_rtd_to_codec(rtd, i);
540 		ret = simple_set_tdm(priv, sdai, pdai, params);
541 		if (ret < 0)
542 			goto end;
543 	}
544 
545 	for_each_prop_dai_cpu(props, i, pdai) {
546 		sdai = snd_soc_rtd_to_cpu(rtd, i);
547 		ret = simple_set_tdm(priv, sdai, pdai, params);
548 		if (ret < 0)
549 			goto end;
550 	}
551 	ret = 0;
552 end:
553 	return simple_ret(priv, ret);
554 }
555 EXPORT_SYMBOL_GPL(simple_util_hw_params);
556 
simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime * rtd,struct snd_pcm_hw_params * params)557 int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
558 				   struct snd_pcm_hw_params *params)
559 {
560 	struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
561 	struct simple_dai_props *dai_props = runtime_simple_priv_to_props(priv, rtd);
562 	struct simple_util_data *data = &dai_props->adata;
563 	struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
564 	struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
565 
566 	if (data->convert_rate)
567 		rate->min =
568 		rate->max = data->convert_rate;
569 
570 	if (data->convert_channels)
571 		channels->min =
572 		channels->max = data->convert_channels;
573 
574 	if (data->convert_sample_format)
575 		simple_fixup_sample_fmt(data, params);
576 
577 	return 0;
578 }
579 EXPORT_SYMBOL_GPL(simple_util_be_hw_params_fixup);
580 
simple_init_dai(struct simple_util_priv * priv,struct snd_soc_dai * dai,struct simple_util_dai * simple_dai)581 static int simple_init_dai(struct simple_util_priv *priv,
582 			   struct snd_soc_dai *dai, struct simple_util_dai *simple_dai)
583 {
584 	int ret;
585 
586 	if (!simple_dai)
587 		return 0;
588 
589 	if (simple_dai->sysclk) {
590 		ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
591 					     simple_dai->clk_direction);
592 		if (ret && ret != -ENOTSUPP) {
593 			dev_err(dai->dev, "simple-card: set_sysclk error\n");
594 			goto end;
595 		}
596 	}
597 
598 	if (simple_dai->slots) {
599 		ret = snd_soc_dai_set_tdm_slot(dai,
600 					       simple_dai->tx_slot_mask,
601 					       simple_dai->rx_slot_mask,
602 					       simple_dai->slots,
603 					       simple_dai->slot_width);
604 		if (ret && ret != -ENOTSUPP) {
605 			dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
606 			goto end;
607 		}
608 	}
609 	ret = 0;
610 end:
611 	return simple_ret(priv, ret);
612 }
613 
simple_component_is_codec(struct snd_soc_component * component)614 static inline int simple_component_is_codec(struct snd_soc_component *component)
615 {
616 	return component->driver->endianness;
617 }
618 
simple_init_for_codec2codec(struct simple_util_priv * priv,struct snd_soc_pcm_runtime * rtd,struct simple_dai_props * dai_props)619 static int simple_init_for_codec2codec(struct simple_util_priv *priv,
620 				       struct snd_soc_pcm_runtime *rtd,
621 				       struct simple_dai_props *dai_props)
622 {
623 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
624 	struct snd_soc_component *component;
625 	struct snd_soc_pcm_stream *c2c_params;
626 	struct snd_pcm_hardware hw;
627 	int i, ret, stream;
628 
629 	/* Do nothing if it already has Codec2Codec settings */
630 	if (dai_link->c2c_params)
631 		return 0;
632 
633 	/* Do nothing if it was DPCM :: BE */
634 	if (dai_link->no_pcm)
635 		return 0;
636 
637 	/* Only Codecs */
638 	for_each_rtd_components(rtd, i, component) {
639 		if (!simple_component_is_codec(component))
640 			return 0;
641 	}
642 
643 	/* Assumes the capabilities are the same for all supported streams */
644 	for_each_pcm_streams(stream) {
645 		ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
646 		if (ret == 0)
647 			break;
648 	}
649 
650 	if (ret < 0) {
651 		dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
652 		goto end;
653 	}
654 
655 	ret = -ENOMEM;
656 	c2c_params = devm_kzalloc(rtd->dev, sizeof(*c2c_params), GFP_KERNEL);
657 	if (!c2c_params)
658 		goto end;
659 
660 	c2c_params->formats		= hw.formats;
661 	c2c_params->rates		= hw.rates;
662 	c2c_params->rate_min		= hw.rate_min;
663 	c2c_params->rate_max		= hw.rate_max;
664 	c2c_params->channels_min	= hw.channels_min;
665 	c2c_params->channels_max	= hw.channels_max;
666 
667 	dai_link->c2c_params		= c2c_params;
668 	dai_link->num_c2c_params	= 1;
669 
670 	ret = 0;
671 end:
672 	return simple_ret(priv, ret);
673 }
674 
simple_util_dai_init(struct snd_soc_pcm_runtime * rtd)675 int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd)
676 {
677 	struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
678 	struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
679 	struct simple_util_dai *dai;
680 	int i, ret;
681 
682 	for_each_prop_dai_codec(props, i, dai) {
683 		ret = simple_init_dai(priv, snd_soc_rtd_to_codec(rtd, i), dai);
684 		if (ret < 0)
685 			goto end;
686 	}
687 	for_each_prop_dai_cpu(props, i, dai) {
688 		ret = simple_init_dai(priv, snd_soc_rtd_to_cpu(rtd, i), dai);
689 		if (ret < 0)
690 			goto end;
691 	}
692 
693 	ret = simple_init_for_codec2codec(priv, rtd, props);
694 end:
695 	return simple_ret(priv, ret);
696 }
697 EXPORT_SYMBOL_GPL(simple_util_dai_init);
698 
simple_util_canonicalize_platform(struct snd_soc_dai_link_component * platforms,struct snd_soc_dai_link_component * cpus)699 void simple_util_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
700 				       struct snd_soc_dai_link_component *cpus)
701 {
702 	/*
703 	 * Assumes Platform == CPU
704 	 *
705 	 * Some CPU might be using soc-generic-dmaengine-pcm. This means CPU and Platform
706 	 * are different Component, but are sharing same component->dev.
707 	 *
708 	 * Let's assume Platform is same as CPU if it doesn't identify Platform on DT.
709 	 * see
710 	 *	simple-card.c :: simple_count_noml()
711 	 */
712 	if (!platforms->of_node)
713 		snd_soc_dlc_use_cpu_as_platform(platforms, cpus);
714 }
715 EXPORT_SYMBOL_GPL(simple_util_canonicalize_platform);
716 
simple_util_canonicalize_cpu(struct snd_soc_dai_link_component * cpus,int is_single_links)717 void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
718 				  int is_single_links)
719 {
720 	/*
721 	 * In snd_soc_add_pcm_runtime() will check cpu name after
722 	 * of_node matching if dai_link has cpu_dai_name.
723 	 * but, it will never match if name was created by
724 	 * fmt_single_name() remove cpu_dai_name if cpu_args
725 	 * was 0. See:
726 	 *	fmt_single_name()
727 	 *	fmt_multiple_name()
728 	 */
729 	if (is_single_links)
730 		cpus->dai_name = NULL;
731 }
732 EXPORT_SYMBOL_GPL(simple_util_canonicalize_cpu);
733 
simple_util_clean_reference(struct snd_soc_card * card)734 void simple_util_clean_reference(struct snd_soc_card *card)
735 {
736 	struct snd_soc_dai_link *dai_link;
737 	struct snd_soc_dai_link_component *cpu;
738 	struct snd_soc_dai_link_component *codec;
739 	int i, j;
740 
741 	for_each_card_prelinks(card, i, dai_link) {
742 		for_each_link_cpus(dai_link, j, cpu)
743 			of_node_put(cpu->of_node);
744 		for_each_link_codecs(dai_link, j, codec)
745 			of_node_put(codec->of_node);
746 	}
747 }
748 EXPORT_SYMBOL_GPL(simple_util_clean_reference);
749 
simple_util_parse_routing(struct snd_soc_card * card,char * prefix)750 int simple_util_parse_routing(struct snd_soc_card *card,
751 			      char *prefix)
752 {
753 	struct device_node *node = card->dev->of_node;
754 	char prop[128];
755 
756 	if (!prefix)
757 		prefix = "";
758 
759 	snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
760 
761 	if (!of_property_present(node, prop))
762 		return 0;
763 
764 	return snd_soc_of_parse_audio_routing(card, prop);
765 }
766 EXPORT_SYMBOL_GPL(simple_util_parse_routing);
767 
simple_util_parse_widgets(struct snd_soc_card * card,char * prefix)768 int simple_util_parse_widgets(struct snd_soc_card *card,
769 			      char *prefix)
770 {
771 	struct device_node *node = card->dev->of_node;
772 	char prop[128];
773 
774 	if (!prefix)
775 		prefix = "";
776 
777 	snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
778 
779 	if (of_property_present(node, prop))
780 		return snd_soc_of_parse_audio_simple_widgets(card, prop);
781 
782 	/* no widgets is not error */
783 	return 0;
784 }
785 EXPORT_SYMBOL_GPL(simple_util_parse_widgets);
786 
simple_util_parse_pin_switches(struct snd_soc_card * card,char * prefix)787 int simple_util_parse_pin_switches(struct snd_soc_card *card,
788 				   char *prefix)
789 {
790 	char prop[128];
791 
792 	if (!prefix)
793 		prefix = "";
794 
795 	snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
796 
797 	return snd_soc_of_parse_pin_switches(card, prop);
798 }
799 EXPORT_SYMBOL_GPL(simple_util_parse_pin_switches);
800 
simple_util_init_jack(struct snd_soc_card * card,struct simple_util_jack * sjack,int is_hp,char * prefix,char * pin)801 int simple_util_init_jack(struct snd_soc_card *card,
802 			  struct simple_util_jack *sjack,
803 			  int is_hp, char *prefix,
804 			  char *pin)
805 {
806 	struct device *dev = card->dev;
807 	struct gpio_desc *desc;
808 	char prop[128];
809 	char *pin_name;
810 	char *gpio_name;
811 	int mask;
812 	int error;
813 
814 	if (!prefix)
815 		prefix = "";
816 
817 	if (is_hp) {
818 		snprintf(prop, sizeof(prop), "%shp-det", prefix);
819 		pin_name	= pin ? pin : "Headphones";
820 		gpio_name	= "Headphone detection";
821 		mask		= SND_JACK_HEADPHONE;
822 	} else {
823 		snprintf(prop, sizeof(prop), "%smic-det", prefix);
824 		pin_name	= pin ? pin : "Mic Jack";
825 		gpio_name	= "Mic detection";
826 		mask		= SND_JACK_MICROPHONE;
827 	}
828 
829 	desc = gpiod_get_optional(dev, prop, GPIOD_IN);
830 	error = PTR_ERR_OR_ZERO(desc);
831 	if (error)
832 		return error;
833 
834 	if (desc) {
835 		error = gpiod_set_consumer_name(desc, gpio_name);
836 		if (error)
837 			return error;
838 
839 		sjack->pin.pin		= pin_name;
840 		sjack->pin.mask		= mask;
841 
842 		sjack->gpio.name	= gpio_name;
843 		sjack->gpio.report	= mask;
844 		sjack->gpio.desc	= desc;
845 		sjack->gpio.debounce_time = 150;
846 
847 		snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack,
848 					   &sjack->pin, 1);
849 
850 		snd_soc_jack_add_gpios(&sjack->jack, 1, &sjack->gpio);
851 	}
852 
853 	return 0;
854 }
855 EXPORT_SYMBOL_GPL(simple_util_init_jack);
856 
simple_util_init_aux_jacks(struct simple_util_priv * priv,char * prefix)857 int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix)
858 {
859 	struct snd_soc_card *card = simple_priv_to_card(priv);
860 	struct snd_soc_component *component;
861 	int found_jack_index = 0;
862 	int type = 0;
863 	int num = 0;
864 	int ret;
865 
866 	if (priv->aux_jacks)
867 		return 0;
868 
869 	for_each_card_auxs(card, component) {
870 		type = snd_soc_component_get_jack_type(component);
871 		if (type > 0)
872 			num++;
873 	}
874 	if (num < 1)
875 		return 0;
876 
877 	priv->aux_jacks = devm_kcalloc(card->dev, num,
878 				       sizeof(struct snd_soc_jack), GFP_KERNEL);
879 	if (!priv->aux_jacks)
880 		return simple_ret(priv, -ENOMEM);
881 
882 	for_each_card_auxs(card, component) {
883 		char id[128];
884 		struct snd_soc_jack *jack;
885 
886 		if (found_jack_index >= num)
887 			break;
888 
889 		type = snd_soc_component_get_jack_type(component);
890 		if (type <= 0)
891 			continue;
892 
893 		/* create jack */
894 		jack = &(priv->aux_jacks[found_jack_index++]);
895 		snprintf(id, sizeof(id), "%s-jack", component->name);
896 		ret = snd_soc_card_jack_new(card, id, type, jack);
897 		if (ret)
898 			continue;
899 
900 		(void)snd_soc_component_set_jack(component, jack, NULL);
901 	}
902 	return 0;
903 }
904 EXPORT_SYMBOL_GPL(simple_util_init_aux_jacks);
905 
906 static struct simple_util_dai dummy_util_dais = {
907 	.name = "dummy_util_dais",
908 };
909 
simple_util_init_priv(struct simple_util_priv * priv,struct link_info * li)910 int simple_util_init_priv(struct simple_util_priv *priv,
911 			  struct link_info *li)
912 {
913 	struct snd_soc_card *card = simple_priv_to_card(priv);
914 	struct device *dev = simple_priv_to_dev(priv);
915 	struct snd_soc_dai_link *dai_link;
916 	struct simple_dai_props *dai_props;
917 	struct simple_util_dai *dais;
918 	struct snd_soc_dai_link_component *dlcs;
919 	struct snd_soc_codec_conf *cconf = NULL;
920 	int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
921 
922 	dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
923 	dai_link  = devm_kcalloc(dev, li->link, sizeof(*dai_link),  GFP_KERNEL);
924 	if (!dai_props || !dai_link)
925 		return -ENOMEM;
926 
927 	/*
928 	 * dais (= CPU+Codec)
929 	 * dlcs (= CPU+Codec+Platform)
930 	 */
931 	for (i = 0; i < li->link; i++) {
932 		int cc = li->num[i].cpus + li->num[i].codecs;
933 
934 		dai_num += cc;
935 		dlc_num += cc + li->num[i].platforms;
936 
937 		if (!li->num[i].cpus)
938 			cnf_num += li->num[i].codecs;
939 	}
940 
941 	dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
942 	dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL);
943 	if (!dais || !dlcs)
944 		return -ENOMEM;
945 
946 	if (cnf_num) {
947 		cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
948 		if (!cconf)
949 			return -ENOMEM;
950 	}
951 
952 	dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
953 		li->link, dai_num, cnf_num);
954 
955 	priv->dai_props		= dai_props;
956 	priv->dai_link		= dai_link;
957 	priv->dais		= dais;
958 	priv->dlcs		= dlcs;
959 	priv->codec_conf	= cconf;
960 
961 	card->dai_link		= priv->dai_link;
962 	card->num_links		= li->link;
963 	card->codec_conf	= cconf;
964 	card->num_configs	= cnf_num;
965 
966 	for (i = 0; i < li->link; i++) {
967 		if (li->num[i].cpus) {
968 			/* Normal CPU */
969 			dai_link[i].cpus	= dlcs;
970 			dai_props[i].num.cpus	=
971 			dai_link[i].num_cpus	= li->num[i].cpus;
972 			dai_props[i].cpu_dai	= dais;
973 
974 			dlcs += li->num[i].cpus;
975 			dais += li->num[i].cpus;
976 		} else {
977 			/* DPCM Be's CPU = dummy */
978 			dai_link[i].cpus	= &snd_soc_dummy_dlc;
979 			dai_props[i].num.cpus	=
980 			dai_link[i].num_cpus	= 1;
981 			dai_props[i].cpu_dai	= &dummy_util_dais;
982 		}
983 
984 		if (li->num[i].codecs) {
985 			/* Normal Codec */
986 			dai_link[i].codecs	= dlcs;
987 			dai_props[i].num.codecs	=
988 			dai_link[i].num_codecs	= li->num[i].codecs;
989 			dai_props[i].codec_dai	= dais;
990 
991 			dlcs += li->num[i].codecs;
992 			dais += li->num[i].codecs;
993 
994 			if (!li->num[i].cpus) {
995 				/* DPCM Be's Codec */
996 				dai_props[i].codec_conf = cconf;
997 				cconf += li->num[i].codecs;
998 			}
999 		} else {
1000 			/* DPCM Fe's Codec = dummy */
1001 			dai_link[i].codecs	= &snd_soc_dummy_dlc;
1002 			dai_props[i].num.codecs	=
1003 			dai_link[i].num_codecs	= 1;
1004 			dai_props[i].codec_dai	= &dummy_util_dais;
1005 		}
1006 
1007 		if (li->num[i].platforms) {
1008 			/* Have Platform */
1009 			dai_link[i].platforms		= dlcs;
1010 			dai_props[i].num.platforms	=
1011 			dai_link[i].num_platforms	= li->num[i].platforms;
1012 
1013 			dlcs += li->num[i].platforms;
1014 		} else {
1015 			/* Doesn't have Platform */
1016 			dai_link[i].platforms		= NULL;
1017 			dai_props[i].num.platforms	=
1018 			dai_link[i].num_platforms	= 0;
1019 		}
1020 	}
1021 
1022 	return 0;
1023 }
1024 EXPORT_SYMBOL_GPL(simple_util_init_priv);
1025 
simple_util_remove(struct platform_device * pdev)1026 void simple_util_remove(struct platform_device *pdev)
1027 {
1028 	struct snd_soc_card *card = platform_get_drvdata(pdev);
1029 
1030 	simple_util_clean_reference(card);
1031 }
1032 EXPORT_SYMBOL_GPL(simple_util_remove);
1033 
graph_util_card_probe(struct snd_soc_card * card)1034 int graph_util_card_probe(struct snd_soc_card *card)
1035 {
1036 	struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
1037 	int ret;
1038 
1039 	ret = simple_util_init_hp(card, &priv->hp_jack, NULL);
1040 	if (ret < 0)
1041 		goto end;
1042 
1043 	ret = simple_util_init_mic(card, &priv->mic_jack, NULL);
1044 end:
1045 	return simple_ret(priv, ret);
1046 }
1047 EXPORT_SYMBOL_GPL(graph_util_card_probe);
1048 
graph_util_is_ports0(struct device_node * np)1049 int graph_util_is_ports0(struct device_node *np)
1050 {
1051 	struct device_node *parent __free(device_node) = of_get_parent(np);
1052 	struct device_node *port;
1053 
1054 	/* np is "endpoint" or "port" */
1055 	if (of_node_name_eq(np, "endpoint"))
1056 		port = parent;
1057 	else
1058 		port = np;
1059 
1060 	struct device_node *ports __free(device_node) = of_get_parent(port);
1061 	const char *at = strchr(kbasename(ports->full_name), '@');
1062 
1063 	/*
1064 	 * Since child iteration order may differ
1065 	 * between a base DT and DT overlays,
1066 	 * string match "ports" or "ports@0" in the node name instead.
1067 	 */
1068 	return !at || !strcmp(at, "@0");
1069 }
1070 EXPORT_SYMBOL_GPL(graph_util_is_ports0);
1071 
graph_get_dai_id(struct device_node * ep)1072 static int graph_get_dai_id(struct device_node *ep)
1073 {
1074 	struct device_node *node __free(device_node) = of_graph_get_port_parent(ep);
1075 	struct device_node *port __free(device_node) = of_get_parent(ep);
1076 	struct of_endpoint info;
1077 	int i, id;
1078 	int ret;
1079 
1080 	/* use driver specified DAI ID if exist */
1081 	ret = snd_soc_get_dai_id(ep);
1082 	if (ret != -ENOTSUPP)
1083 		return ret;
1084 
1085 	/* use endpoint/port reg if exist */
1086 	ret = of_graph_parse_endpoint(ep, &info);
1087 	if (ret == 0) {
1088 		/*
1089 		 * Because it will count port/endpoint if it doesn't have "reg".
1090 		 * But, we can't judge whether it has "no reg", or "reg = <0>"
1091 		 * only of_graph_parse_endpoint().
1092 		 * We need to check "reg" property
1093 		 */
1094 
1095 		/* check port first */
1096 		ret = of_property_present(port, "reg");
1097 		if (ret)
1098 			return info.port;
1099 
1100 		/* check endpoint 2nd as backup */
1101 		if (of_property_present(ep,   "reg"))
1102 			return info.id;
1103 	}
1104 
1105 	/*
1106 	 * Non HDMI sound case, counting port/endpoint on its DT
1107 	 * is enough. Let's count it.
1108 	 */
1109 	i = 0;
1110 	id = -1;
1111 	for_each_of_graph_port(node, p) {
1112 		if (port == p) {
1113 			id = i;
1114 			break;
1115 		}
1116 		i++;
1117 	}
1118 
1119 	if (id < 0)
1120 		return -ENODEV;
1121 
1122 	return id;
1123 }
1124 
graph_util_parse_dai(struct simple_util_priv * priv,struct device_node * ep,struct snd_soc_dai_link_component * dlc,int * is_single_link)1125 int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep,
1126 			 struct snd_soc_dai_link_component *dlc, int *is_single_link)
1127 {
1128 	struct device *dev = simple_priv_to_dev(priv);
1129 	struct device_node *node;
1130 	struct of_phandle_args args = {};
1131 	struct snd_soc_dai_link_component resolved_dlc = {};
1132 	struct snd_soc_dai *dai;
1133 	const char *fallback_dai_name;
1134 	int ret;
1135 
1136 	if (!ep)
1137 		return 0;
1138 
1139 	node = of_graph_get_port_parent(ep);
1140 
1141 	/*
1142 	 * Try to find from DAI node
1143 	 */
1144 	args.np = ep;
1145 	dai = snd_soc_get_dai_via_args(&args);
1146 	if (dai) {
1147 		const char *dai_name = snd_soc_dai_name_get(dai);
1148 		const struct of_phandle_args *dai_args = snd_soc_copy_dai_args(dev, &args);
1149 
1150 		ret = -ENOMEM;
1151 		if (!dai_args)
1152 			goto err;
1153 
1154 		dlc->of_node  = node;
1155 		dlc->dai_name = dai_name;
1156 		dlc->dai_args = dai_args;
1157 	} else {
1158 		/* Get dai->name */
1159 		args.np		= node;
1160 		args.args[0]	= graph_get_dai_id(ep);
1161 		args.args_count	= (of_graph_get_endpoint_count(node) > 1);
1162 
1163 		ret = snd_soc_get_dlc(&args, &resolved_dlc);
1164 		if (ret < 0)
1165 			goto err;
1166 
1167 		/* Keep fallback dai_name valid across component rebind */
1168 		fallback_dai_name = resolved_dlc.dai_name;
1169 		if (fallback_dai_name) {
1170 			fallback_dai_name = devm_kstrdup_const(dev, fallback_dai_name,
1171 							       GFP_KERNEL);
1172 			ret = -ENOMEM;
1173 			if (!fallback_dai_name)
1174 				goto err;
1175 		}
1176 
1177 		dlc->of_node = resolved_dlc.of_node;
1178 		dlc->dai_name = fallback_dai_name;
1179 		dlc->dai_args = resolved_dlc.dai_args;
1180 	}
1181 
1182 	if (is_single_link)
1183 		*is_single_link = of_graph_get_endpoint_count(node) == 1;
1184 	ret = 0;
1185 err:
1186 	if (ret < 0)
1187 		of_node_put(node);
1188 
1189 	return simple_ret(priv, ret);
1190 }
1191 EXPORT_SYMBOL_GPL(graph_util_parse_dai);
1192 
graph_util_parse_link_direction(struct device_node * np,bool * playback_only,bool * capture_only)1193 void graph_util_parse_link_direction(struct device_node *np,
1194 				    bool *playback_only, bool *capture_only)
1195 {
1196 	bool is_playback_only = of_property_read_bool(np, "playback-only");
1197 	bool is_capture_only  = of_property_read_bool(np, "capture-only");
1198 
1199 	if (playback_only && is_playback_only)
1200 		*playback_only = is_playback_only;
1201 	if (capture_only && is_capture_only)
1202 		*capture_only = is_capture_only;
1203 }
1204 EXPORT_SYMBOL_GPL(graph_util_parse_link_direction);
1205 
1206 static enum snd_soc_trigger_order
__graph_util_parse_trigger_order(struct simple_util_priv * priv,struct device_node * np,const char * prop)1207 __graph_util_parse_trigger_order(struct simple_util_priv *priv,
1208 				 struct device_node *np,
1209 				 const char *prop)
1210 {
1211 	u32 val[SND_SOC_TRIGGER_SIZE];
1212 	int ret;
1213 
1214 	ret = of_property_read_u32_array(np, prop, val, SND_SOC_TRIGGER_SIZE);
1215 	if (ret == 0) {
1216 		struct device *dev = simple_priv_to_dev(priv);
1217 		u32 order =	(val[0] << 8) +
1218 			(val[1] << 4) +
1219 			(val[2]);
1220 
1221 		switch (order) {
1222 		case	(SND_SOC_TRIGGER_LINK		<< 8) +
1223 			(SND_SOC_TRIGGER_COMPONENT	<< 4) +
1224 			(SND_SOC_TRIGGER_DAI):
1225 			return SND_SOC_TRIGGER_ORDER_DEFAULT;
1226 
1227 		case	(SND_SOC_TRIGGER_LINK		<< 8) +
1228 			(SND_SOC_TRIGGER_DAI		<< 4) +
1229 			(SND_SOC_TRIGGER_COMPONENT):
1230 			return SND_SOC_TRIGGER_ORDER_LDC;
1231 
1232 		default:
1233 			dev_err(dev, "unsupported trigger order [0x%x]\n", order);
1234 		}
1235 	}
1236 
1237 	/* SND_SOC_TRIGGER_ORDER_MAX means error */
1238 	return SND_SOC_TRIGGER_ORDER_MAX;
1239 }
1240 
graph_util_parse_trigger_order(struct simple_util_priv * priv,struct device_node * np,enum snd_soc_trigger_order * trigger_start,enum snd_soc_trigger_order * trigger_stop)1241 void graph_util_parse_trigger_order(struct simple_util_priv *priv,
1242 				    struct device_node *np,
1243 				    enum snd_soc_trigger_order *trigger_start,
1244 				    enum snd_soc_trigger_order *trigger_stop)
1245 {
1246 	static enum snd_soc_trigger_order order;
1247 
1248 	/*
1249 	 * We can use it like below
1250 	 *
1251 	 * #include <dt-bindings/sound/audio-graph.h>
1252 	 *
1253 	 * link-trigger-order = <SND_SOC_TRIGGER_LINK
1254 	 *			 SND_SOC_TRIGGER_COMPONENT
1255 	 *			 SND_SOC_TRIGGER_DAI>;
1256 	 */
1257 
1258 	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order");
1259 	if (order < SND_SOC_TRIGGER_ORDER_MAX) {
1260 		*trigger_start = order;
1261 		*trigger_stop  = order;
1262 	}
1263 
1264 	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-start");
1265 	if (order < SND_SOC_TRIGGER_ORDER_MAX)
1266 		*trigger_start = order;
1267 
1268 	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-stop");
1269 	if (order < SND_SOC_TRIGGER_ORDER_MAX)
1270 		*trigger_stop  = order;
1271 
1272 	return;
1273 }
1274 EXPORT_SYMBOL_GPL(graph_util_parse_trigger_order);
1275 
1276 /* Module information */
1277 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
1278 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
1279 MODULE_LICENSE("GPL v2");
1280