xref: /linux/sound/soc/generic/simple-card-utils.c (revision 404bec4c8f6c38ae5fa208344f1086d38026e93d)
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 <linux/clk.h>
8 #include <linux/gpio.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_gpio.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 static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data,
19 					 struct snd_pcm_hw_params *params)
20 {
21 	int i;
22 	struct snd_mask *mask = hw_param_mask(params,
23 					      SNDRV_PCM_HW_PARAM_FORMAT);
24 	struct {
25 		char *fmt;
26 		u32 val;
27 	} of_sample_fmt_table[] = {
28 		{ "s8",		SNDRV_PCM_FORMAT_S8},
29 		{ "s16_le",	SNDRV_PCM_FORMAT_S16_LE},
30 		{ "s24_le",	SNDRV_PCM_FORMAT_S24_LE},
31 		{ "s24_3le",	SNDRV_PCM_FORMAT_S24_3LE},
32 		{ "s32_le",	SNDRV_PCM_FORMAT_S32_LE},
33 	};
34 
35 	for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) {
36 		if (!strcmp(data->convert_sample_format,
37 			    of_sample_fmt_table[i].fmt)) {
38 			snd_mask_none(mask);
39 			snd_mask_set(mask, of_sample_fmt_table[i].val);
40 			break;
41 		}
42 	}
43 }
44 
45 void asoc_simple_convert_fixup(struct asoc_simple_data *data,
46 			       struct snd_pcm_hw_params *params)
47 {
48 	struct snd_interval *rate = hw_param_interval(params,
49 						SNDRV_PCM_HW_PARAM_RATE);
50 	struct snd_interval *channels = hw_param_interval(params,
51 						SNDRV_PCM_HW_PARAM_CHANNELS);
52 
53 	if (data->convert_rate)
54 		rate->min =
55 		rate->max = data->convert_rate;
56 
57 	if (data->convert_channels)
58 		channels->min =
59 		channels->max = data->convert_channels;
60 
61 	if (data->convert_sample_format)
62 		asoc_simple_fixup_sample_fmt(data, params);
63 }
64 EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
65 
66 void asoc_simple_parse_convert(struct device_node *np,
67 			       char *prefix,
68 			       struct asoc_simple_data *data)
69 {
70 	char prop[128];
71 
72 	if (!prefix)
73 		prefix = "";
74 
75 	/* sampling rate convert */
76 	snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
77 	of_property_read_u32(np, prop, &data->convert_rate);
78 
79 	/* channels transfer */
80 	snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
81 	of_property_read_u32(np, prop, &data->convert_channels);
82 
83 	/* convert sample format */
84 	snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-sample-format");
85 	of_property_read_string(np, prop, &data->convert_sample_format);
86 }
87 EXPORT_SYMBOL_GPL(asoc_simple_parse_convert);
88 
89 int asoc_simple_parse_daifmt(struct device *dev,
90 			     struct device_node *node,
91 			     struct device_node *codec,
92 			     char *prefix,
93 			     unsigned int *retfmt)
94 {
95 	struct device_node *bitclkmaster = NULL;
96 	struct device_node *framemaster = NULL;
97 	unsigned int daifmt;
98 
99 	daifmt = snd_soc_daifmt_parse_format(node, prefix);
100 
101 	snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster);
102 	if (!bitclkmaster && !framemaster) {
103 		/*
104 		 * No dai-link level and master setting was not found from
105 		 * sound node level, revert back to legacy DT parsing and
106 		 * take the settings from codec node.
107 		 */
108 		dev_dbg(dev, "Revert to legacy daifmt parsing\n");
109 
110 		daifmt |= snd_soc_daifmt_parse_clock_provider_as_flag(codec, NULL);
111 	} else {
112 		daifmt |= snd_soc_daifmt_clock_provider_from_bitmap(
113 				((codec == bitclkmaster) << 4) | (codec == framemaster));
114 	}
115 
116 	of_node_put(bitclkmaster);
117 	of_node_put(framemaster);
118 
119 	*retfmt = daifmt;
120 
121 	return 0;
122 }
123 EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt);
124 
125 int asoc_simple_parse_tdm_width_map(struct device *dev, struct device_node *np,
126 				    struct asoc_simple_dai *dai)
127 {
128 	u32 *array_values, *p;
129 	int n, i, ret;
130 
131 	if (!of_property_read_bool(np, "dai-tdm-slot-width-map"))
132 		return 0;
133 
134 	n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32));
135 	if (n % 3) {
136 		dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n");
137 		return -EINVAL;
138 	}
139 
140 	dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL);
141 	if (!dai->tdm_width_map)
142 		return -ENOMEM;
143 
144 	array_values = kcalloc(n, sizeof(*array_values), GFP_KERNEL);
145 	if (!array_values)
146 		return -ENOMEM;
147 
148 	ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n);
149 	if (ret < 0) {
150 		dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret);
151 		goto out;
152 	}
153 
154 	p = array_values;
155 	for (i = 0; i < n / 3; ++i) {
156 		dai->tdm_width_map[i].sample_bits = *p++;
157 		dai->tdm_width_map[i].slot_width = *p++;
158 		dai->tdm_width_map[i].slot_count = *p++;
159 	}
160 
161 	dai->n_tdm_widths = i;
162 	ret = 0;
163 out:
164 	kfree(array_values);
165 
166 	return ret;
167 }
168 EXPORT_SYMBOL_GPL(asoc_simple_parse_tdm_width_map);
169 
170 int asoc_simple_set_dailink_name(struct device *dev,
171 				 struct snd_soc_dai_link *dai_link,
172 				 const char *fmt, ...)
173 {
174 	va_list ap;
175 	char *name = NULL;
176 	int ret = -ENOMEM;
177 
178 	va_start(ap, fmt);
179 	name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
180 	va_end(ap);
181 
182 	if (name) {
183 		ret = 0;
184 
185 		dai_link->name		= name;
186 		dai_link->stream_name	= name;
187 	}
188 
189 	return ret;
190 }
191 EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name);
192 
193 int asoc_simple_parse_card_name(struct snd_soc_card *card,
194 				char *prefix)
195 {
196 	int ret;
197 
198 	if (!prefix)
199 		prefix = "";
200 
201 	/* Parse the card name from DT */
202 	ret = snd_soc_of_parse_card_name(card, "label");
203 	if (ret < 0 || !card->name) {
204 		char prop[128];
205 
206 		snprintf(prop, sizeof(prop), "%sname", prefix);
207 		ret = snd_soc_of_parse_card_name(card, prop);
208 		if (ret < 0)
209 			return ret;
210 	}
211 
212 	if (!card->name && card->dai_link)
213 		card->name = card->dai_link->name;
214 
215 	return 0;
216 }
217 EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name);
218 
219 static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
220 {
221 	if (dai)
222 		return clk_prepare_enable(dai->clk);
223 
224 	return 0;
225 }
226 
227 static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
228 {
229 	if (dai)
230 		clk_disable_unprepare(dai->clk);
231 }
232 
233 int asoc_simple_parse_clk(struct device *dev,
234 			  struct device_node *node,
235 			  struct asoc_simple_dai *simple_dai,
236 			  struct snd_soc_dai_link_component *dlc)
237 {
238 	struct clk *clk;
239 	u32 val;
240 
241 	/*
242 	 * Parse dai->sysclk come from "clocks = <&xxx>"
243 	 * (if system has common clock)
244 	 *  or "system-clock-frequency = <xxx>"
245 	 *  or device's module clock.
246 	 */
247 	clk = devm_get_clk_from_child(dev, node, NULL);
248 	simple_dai->clk_fixed = of_property_read_bool(
249 		node, "system-clock-fixed");
250 	if (!IS_ERR(clk)) {
251 		simple_dai->sysclk = clk_get_rate(clk);
252 
253 		simple_dai->clk = clk;
254 	} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
255 		simple_dai->sysclk = val;
256 		simple_dai->clk_fixed = true;
257 	} else {
258 		clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
259 		if (!IS_ERR(clk))
260 			simple_dai->sysclk = clk_get_rate(clk);
261 	}
262 
263 	if (of_property_read_bool(node, "system-clock-direction-out"))
264 		simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
265 
266 	return 0;
267 }
268 EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
269 
270 static int asoc_simple_check_fixed_sysclk(struct device *dev,
271 					  struct asoc_simple_dai *dai,
272 					  unsigned int *fixed_sysclk)
273 {
274 	if (dai->clk_fixed) {
275 		if (*fixed_sysclk && *fixed_sysclk != dai->sysclk) {
276 			dev_err(dev, "inconsistent fixed sysclk rates (%u vs %u)\n",
277 				*fixed_sysclk, dai->sysclk);
278 			return -EINVAL;
279 		}
280 		*fixed_sysclk = dai->sysclk;
281 	}
282 
283 	return 0;
284 }
285 
286 int asoc_simple_startup(struct snd_pcm_substream *substream)
287 {
288 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
289 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
290 	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
291 	struct asoc_simple_dai *dai;
292 	unsigned int fixed_sysclk = 0;
293 	int i1, i2, i;
294 	int ret;
295 
296 	for_each_prop_dai_cpu(props, i1, dai) {
297 		ret = asoc_simple_clk_enable(dai);
298 		if (ret)
299 			goto cpu_err;
300 		ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
301 		if (ret)
302 			goto cpu_err;
303 	}
304 
305 	for_each_prop_dai_codec(props, i2, dai) {
306 		ret = asoc_simple_clk_enable(dai);
307 		if (ret)
308 			goto codec_err;
309 		ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
310 		if (ret)
311 			goto codec_err;
312 	}
313 
314 	if (fixed_sysclk && props->mclk_fs) {
315 		unsigned int fixed_rate = fixed_sysclk / props->mclk_fs;
316 
317 		if (fixed_sysclk % props->mclk_fs) {
318 			dev_err(rtd->dev, "fixed sysclk %u not divisible by mclk_fs %u\n",
319 				fixed_sysclk, props->mclk_fs);
320 			return -EINVAL;
321 		}
322 		ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
323 			fixed_rate, fixed_rate);
324 		if (ret)
325 			goto codec_err;
326 	}
327 
328 	return 0;
329 
330 codec_err:
331 	for_each_prop_dai_codec(props, i, dai) {
332 		if (i >= i2)
333 			break;
334 		asoc_simple_clk_disable(dai);
335 	}
336 cpu_err:
337 	for_each_prop_dai_cpu(props, i, dai) {
338 		if (i >= i1)
339 			break;
340 		asoc_simple_clk_disable(dai);
341 	}
342 	return ret;
343 }
344 EXPORT_SYMBOL_GPL(asoc_simple_startup);
345 
346 void asoc_simple_shutdown(struct snd_pcm_substream *substream)
347 {
348 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
349 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
350 	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
351 	struct asoc_simple_dai *dai;
352 	int i;
353 
354 	for_each_prop_dai_cpu(props, i, dai) {
355 		struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, i);
356 
357 		if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(cpu_dai))
358 			snd_soc_dai_set_sysclk(cpu_dai,
359 					       0, 0, SND_SOC_CLOCK_OUT);
360 
361 		asoc_simple_clk_disable(dai);
362 	}
363 	for_each_prop_dai_codec(props, i, dai) {
364 		struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, i);
365 
366 		if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(codec_dai))
367 			snd_soc_dai_set_sysclk(codec_dai,
368 					       0, 0, SND_SOC_CLOCK_IN);
369 
370 		asoc_simple_clk_disable(dai);
371 	}
372 }
373 EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
374 
375 static int asoc_simple_set_clk_rate(struct device *dev,
376 				    struct asoc_simple_dai *simple_dai,
377 				    unsigned long rate)
378 {
379 	if (!simple_dai)
380 		return 0;
381 
382 	if (simple_dai->clk_fixed && rate != simple_dai->sysclk) {
383 		dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate);
384 		return -EINVAL;
385 	}
386 
387 	if (!simple_dai->clk)
388 		return 0;
389 
390 	if (clk_get_rate(simple_dai->clk) == rate)
391 		return 0;
392 
393 	return clk_set_rate(simple_dai->clk, rate);
394 }
395 
396 static int asoc_simple_set_tdm(struct snd_soc_dai *dai,
397 				struct asoc_simple_dai *simple_dai,
398 				struct snd_pcm_hw_params *params)
399 {
400 	int sample_bits = params_width(params);
401 	int slot_width, slot_count;
402 	int i, ret;
403 
404 	if (!simple_dai || !simple_dai->tdm_width_map)
405 		return 0;
406 
407 	slot_width = simple_dai->slot_width;
408 	slot_count = simple_dai->slots;
409 
410 	if (slot_width == 0)
411 		slot_width = sample_bits;
412 
413 	for (i = 0; i < simple_dai->n_tdm_widths; ++i) {
414 		if (simple_dai->tdm_width_map[i].sample_bits == sample_bits) {
415 			slot_width = simple_dai->tdm_width_map[i].slot_width;
416 			slot_count = simple_dai->tdm_width_map[i].slot_count;
417 			break;
418 		}
419 	}
420 
421 	ret = snd_soc_dai_set_tdm_slot(dai,
422 				       simple_dai->tx_slot_mask,
423 				       simple_dai->rx_slot_mask,
424 				       slot_count,
425 				       slot_width);
426 	if (ret && ret != -ENOTSUPP) {
427 		dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret);
428 		return ret;
429 	}
430 
431 	return 0;
432 }
433 
434 int asoc_simple_hw_params(struct snd_pcm_substream *substream,
435 			  struct snd_pcm_hw_params *params)
436 {
437 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
438 	struct asoc_simple_dai *pdai;
439 	struct snd_soc_dai *sdai;
440 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
441 	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
442 	unsigned int mclk, mclk_fs = 0;
443 	int i, ret;
444 
445 	if (props->mclk_fs)
446 		mclk_fs = props->mclk_fs;
447 
448 	if (mclk_fs) {
449 		struct snd_soc_component *component;
450 		mclk = params_rate(params) * mclk_fs;
451 
452 		for_each_prop_dai_codec(props, i, pdai) {
453 			ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
454 			if (ret < 0)
455 				return ret;
456 		}
457 
458 		for_each_prop_dai_cpu(props, i, pdai) {
459 			ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
460 			if (ret < 0)
461 				return ret;
462 		}
463 
464 		/* Ensure sysclk is set on all components in case any
465 		 * (such as platform components) are missed by calls to
466 		 * snd_soc_dai_set_sysclk.
467 		 */
468 		for_each_rtd_components(rtd, i, component) {
469 			ret = snd_soc_component_set_sysclk(component, 0, 0,
470 							   mclk, SND_SOC_CLOCK_IN);
471 			if (ret && ret != -ENOTSUPP)
472 				return ret;
473 		}
474 
475 		for_each_rtd_codec_dais(rtd, i, sdai) {
476 			ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN);
477 			if (ret && ret != -ENOTSUPP)
478 				return ret;
479 		}
480 
481 		for_each_rtd_cpu_dais(rtd, i, sdai) {
482 			ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT);
483 			if (ret && ret != -ENOTSUPP)
484 				return ret;
485 		}
486 	}
487 
488 	for_each_prop_dai_codec(props, i, pdai) {
489 		sdai = asoc_rtd_to_codec(rtd, i);
490 		ret = asoc_simple_set_tdm(sdai, pdai, params);
491 		if (ret < 0)
492 			return ret;
493 	}
494 
495 	for_each_prop_dai_cpu(props, i, pdai) {
496 		sdai = asoc_rtd_to_cpu(rtd, i);
497 		ret = asoc_simple_set_tdm(sdai, pdai, params);
498 		if (ret < 0)
499 			return ret;
500 	}
501 
502 	return 0;
503 }
504 EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
505 
506 int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
507 				   struct snd_pcm_hw_params *params)
508 {
509 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
510 	struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
511 
512 	asoc_simple_convert_fixup(&dai_props->adata, params);
513 
514 	return 0;
515 }
516 EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup);
517 
518 static int asoc_simple_init_dai(struct snd_soc_dai *dai,
519 				     struct asoc_simple_dai *simple_dai)
520 {
521 	int ret;
522 
523 	if (!simple_dai)
524 		return 0;
525 
526 	if (simple_dai->sysclk) {
527 		ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
528 					     simple_dai->clk_direction);
529 		if (ret && ret != -ENOTSUPP) {
530 			dev_err(dai->dev, "simple-card: set_sysclk error\n");
531 			return ret;
532 		}
533 	}
534 
535 	if (simple_dai->slots) {
536 		ret = snd_soc_dai_set_tdm_slot(dai,
537 					       simple_dai->tx_slot_mask,
538 					       simple_dai->rx_slot_mask,
539 					       simple_dai->slots,
540 					       simple_dai->slot_width);
541 		if (ret && ret != -ENOTSUPP) {
542 			dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
543 			return ret;
544 		}
545 	}
546 
547 	return 0;
548 }
549 
550 static inline int asoc_simple_component_is_codec(struct snd_soc_component *component)
551 {
552 	return component->driver->endianness;
553 }
554 
555 static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
556 					    struct simple_dai_props *dai_props)
557 {
558 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
559 	struct snd_soc_component *component;
560 	struct snd_soc_pcm_stream *params;
561 	struct snd_pcm_hardware hw;
562 	int i, ret, stream;
563 
564 	/* Do nothing if it already has Codec2Codec settings */
565 	if (dai_link->params)
566 		return 0;
567 
568 	/* Do nothing if it was DPCM :: BE */
569 	if (dai_link->no_pcm)
570 		return 0;
571 
572 	/* Only Codecs */
573 	for_each_rtd_components(rtd, i, component) {
574 		if (!asoc_simple_component_is_codec(component))
575 			return 0;
576 	}
577 
578 	/* Assumes the capabilities are the same for all supported streams */
579 	for_each_pcm_streams(stream) {
580 		ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
581 		if (ret == 0)
582 			break;
583 	}
584 
585 	if (ret < 0) {
586 		dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
587 		return ret;
588 	}
589 
590 	params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL);
591 	if (!params)
592 		return -ENOMEM;
593 
594 	params->formats = hw.formats;
595 	params->rates = hw.rates;
596 	params->rate_min = hw.rate_min;
597 	params->rate_max = hw.rate_max;
598 	params->channels_min = hw.channels_min;
599 	params->channels_max = hw.channels_max;
600 
601 	dai_link->params = params;
602 	dai_link->num_params = 1;
603 
604 	return 0;
605 }
606 
607 int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
608 {
609 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
610 	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
611 	struct asoc_simple_dai *dai;
612 	int i, ret;
613 
614 	for_each_prop_dai_codec(props, i, dai) {
615 		ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
616 		if (ret < 0)
617 			return ret;
618 	}
619 	for_each_prop_dai_cpu(props, i, dai) {
620 		ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
621 		if (ret < 0)
622 			return ret;
623 	}
624 
625 	ret = asoc_simple_init_for_codec2codec(rtd, props);
626 	if (ret < 0)
627 		return ret;
628 
629 	return 0;
630 }
631 EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
632 
633 void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
634 				       struct snd_soc_dai_link_component *cpus)
635 {
636 	/* Assumes platform == cpu */
637 	if (!platforms->of_node)
638 		platforms->of_node = cpus->of_node;
639 }
640 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
641 
642 void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
643 				  int is_single_links)
644 {
645 	/*
646 	 * In soc_bind_dai_link() will check cpu name after
647 	 * of_node matching if dai_link has cpu_dai_name.
648 	 * but, it will never match if name was created by
649 	 * fmt_single_name() remove cpu_dai_name if cpu_args
650 	 * was 0. See:
651 	 *	fmt_single_name()
652 	 *	fmt_multiple_name()
653 	 */
654 	if (is_single_links)
655 		cpus->dai_name = NULL;
656 }
657 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
658 
659 void asoc_simple_clean_reference(struct snd_soc_card *card)
660 {
661 	struct snd_soc_dai_link *dai_link;
662 	struct snd_soc_dai_link_component *cpu;
663 	struct snd_soc_dai_link_component *codec;
664 	int i, j;
665 
666 	for_each_card_prelinks(card, i, dai_link) {
667 		for_each_link_cpus(dai_link, j, cpu)
668 			of_node_put(cpu->of_node);
669 		for_each_link_codecs(dai_link, j, codec)
670 			of_node_put(codec->of_node);
671 	}
672 }
673 EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
674 
675 int asoc_simple_parse_routing(struct snd_soc_card *card,
676 			      char *prefix)
677 {
678 	struct device_node *node = card->dev->of_node;
679 	char prop[128];
680 
681 	if (!prefix)
682 		prefix = "";
683 
684 	snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
685 
686 	if (!of_property_read_bool(node, prop))
687 		return 0;
688 
689 	return snd_soc_of_parse_audio_routing(card, prop);
690 }
691 EXPORT_SYMBOL_GPL(asoc_simple_parse_routing);
692 
693 int asoc_simple_parse_widgets(struct snd_soc_card *card,
694 			      char *prefix)
695 {
696 	struct device_node *node = card->dev->of_node;
697 	char prop[128];
698 
699 	if (!prefix)
700 		prefix = "";
701 
702 	snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
703 
704 	if (of_property_read_bool(node, prop))
705 		return snd_soc_of_parse_audio_simple_widgets(card, prop);
706 
707 	/* no widgets is not error */
708 	return 0;
709 }
710 EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets);
711 
712 int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
713 				   char *prefix)
714 {
715 	char prop[128];
716 
717 	if (!prefix)
718 		prefix = "";
719 
720 	snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
721 
722 	return snd_soc_of_parse_pin_switches(card, prop);
723 }
724 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
725 
726 int asoc_simple_init_jack(struct snd_soc_card *card,
727 			  struct asoc_simple_jack *sjack,
728 			  int is_hp, char *prefix,
729 			  char *pin)
730 {
731 	struct device *dev = card->dev;
732 	enum of_gpio_flags flags;
733 	char prop[128];
734 	char *pin_name;
735 	char *gpio_name;
736 	int mask;
737 	int det;
738 
739 	if (!prefix)
740 		prefix = "";
741 
742 	sjack->gpio.gpio = -ENOENT;
743 
744 	if (is_hp) {
745 		snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
746 		pin_name	= pin ? pin : "Headphones";
747 		gpio_name	= "Headphone detection";
748 		mask		= SND_JACK_HEADPHONE;
749 	} else {
750 		snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
751 		pin_name	= pin ? pin : "Mic Jack";
752 		gpio_name	= "Mic detection";
753 		mask		= SND_JACK_MICROPHONE;
754 	}
755 
756 	det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
757 	if (det == -EPROBE_DEFER)
758 		return -EPROBE_DEFER;
759 
760 	if (gpio_is_valid(det)) {
761 		sjack->pin.pin		= pin_name;
762 		sjack->pin.mask		= mask;
763 
764 		sjack->gpio.name	= gpio_name;
765 		sjack->gpio.report	= mask;
766 		sjack->gpio.gpio	= det;
767 		sjack->gpio.invert	= !!(flags & OF_GPIO_ACTIVE_LOW);
768 		sjack->gpio.debounce_time = 150;
769 
770 		snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack,
771 					   &sjack->pin, 1);
772 
773 		snd_soc_jack_add_gpios(&sjack->jack, 1,
774 				       &sjack->gpio);
775 	}
776 
777 	return 0;
778 }
779 EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
780 
781 int asoc_simple_init_priv(struct asoc_simple_priv *priv,
782 			  struct link_info *li)
783 {
784 	struct snd_soc_card *card = simple_priv_to_card(priv);
785 	struct device *dev = simple_priv_to_dev(priv);
786 	struct snd_soc_dai_link *dai_link;
787 	struct simple_dai_props *dai_props;
788 	struct asoc_simple_dai *dais;
789 	struct snd_soc_dai_link_component *dlcs;
790 	struct snd_soc_codec_conf *cconf = NULL;
791 	int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
792 
793 	dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
794 	dai_link  = devm_kcalloc(dev, li->link, sizeof(*dai_link),  GFP_KERNEL);
795 	if (!dai_props || !dai_link)
796 		return -ENOMEM;
797 
798 	/*
799 	 * dais (= CPU+Codec)
800 	 * dlcs (= CPU+Codec+Platform)
801 	 */
802 	for (i = 0; i < li->link; i++) {
803 		int cc = li->num[i].cpus + li->num[i].codecs;
804 
805 		dai_num += cc;
806 		dlc_num += cc + li->num[i].platforms;
807 
808 		if (!li->num[i].cpus)
809 			cnf_num += li->num[i].codecs;
810 	}
811 
812 	dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
813 	dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL);
814 	if (!dais || !dlcs)
815 		return -ENOMEM;
816 
817 	if (cnf_num) {
818 		cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
819 		if (!cconf)
820 			return -ENOMEM;
821 	}
822 
823 	dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
824 		li->link, dai_num, cnf_num);
825 
826 	/* dummy CPU/Codec */
827 	priv->dummy.of_node	= NULL;
828 	priv->dummy.dai_name	= "snd-soc-dummy-dai";
829 	priv->dummy.name	= "snd-soc-dummy";
830 
831 	priv->dai_props		= dai_props;
832 	priv->dai_link		= dai_link;
833 	priv->dais		= dais;
834 	priv->dlcs		= dlcs;
835 	priv->codec_conf	= cconf;
836 
837 	card->dai_link		= priv->dai_link;
838 	card->num_links		= li->link;
839 	card->codec_conf	= cconf;
840 	card->num_configs	= cnf_num;
841 
842 	for (i = 0; i < li->link; i++) {
843 		if (li->num[i].cpus) {
844 			/* Normal CPU */
845 			dai_props[i].cpus	=
846 			dai_link[i].cpus	= dlcs;
847 			dai_props[i].num.cpus	=
848 			dai_link[i].num_cpus	= li->num[i].cpus;
849 			dai_props[i].cpu_dai	= dais;
850 
851 			dlcs += li->num[i].cpus;
852 			dais += li->num[i].cpus;
853 		} else {
854 			/* DPCM Be's CPU = dummy */
855 			dai_props[i].cpus	=
856 			dai_link[i].cpus	= &priv->dummy;
857 			dai_props[i].num.cpus	=
858 			dai_link[i].num_cpus	= 1;
859 		}
860 
861 		if (li->num[i].codecs) {
862 			/* Normal Codec */
863 			dai_props[i].codecs	=
864 			dai_link[i].codecs	= dlcs;
865 			dai_props[i].num.codecs	=
866 			dai_link[i].num_codecs	= li->num[i].codecs;
867 			dai_props[i].codec_dai	= dais;
868 
869 			dlcs += li->num[i].codecs;
870 			dais += li->num[i].codecs;
871 
872 			if (!li->num[i].cpus) {
873 				/* DPCM Be's Codec */
874 				dai_props[i].codec_conf = cconf;
875 				cconf += li->num[i].codecs;
876 			}
877 		} else {
878 			/* DPCM Fe's Codec = dummy */
879 			dai_props[i].codecs	=
880 			dai_link[i].codecs	= &priv->dummy;
881 			dai_props[i].num.codecs	=
882 			dai_link[i].num_codecs	= 1;
883 		}
884 
885 		if (li->num[i].platforms) {
886 			/* Have Platform */
887 			dai_props[i].platforms		=
888 			dai_link[i].platforms		= dlcs;
889 			dai_props[i].num.platforms	=
890 			dai_link[i].num_platforms	= li->num[i].platforms;
891 
892 			dlcs += li->num[i].platforms;
893 		} else {
894 			/* Doesn't have Platform */
895 			dai_props[i].platforms		=
896 			dai_link[i].platforms		= NULL;
897 			dai_props[i].num.platforms	=
898 			dai_link[i].num_platforms	= 0;
899 		}
900 	}
901 
902 	return 0;
903 }
904 EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
905 
906 int asoc_simple_remove(struct platform_device *pdev)
907 {
908 	struct snd_soc_card *card = platform_get_drvdata(pdev);
909 
910 	asoc_simple_clean_reference(card);
911 
912 	return 0;
913 }
914 EXPORT_SYMBOL_GPL(asoc_simple_remove);
915 
916 int asoc_graph_card_probe(struct snd_soc_card *card)
917 {
918 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
919 	int ret;
920 
921 	ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
922 	if (ret < 0)
923 		return ret;
924 
925 	ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
926 	if (ret < 0)
927 		return ret;
928 
929 	return 0;
930 }
931 EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
932 
933 int asoc_graph_is_ports0(struct device_node *np)
934 {
935 	struct device_node *port, *ports, *ports0, *top;
936 	int ret;
937 
938 	/* np is "endpoint" or "port" */
939 	if (of_node_name_eq(np, "endpoint")) {
940 		port = of_get_parent(np);
941 	} else {
942 		port = np;
943 		of_node_get(port);
944 	}
945 
946 	ports	= of_get_parent(port);
947 	top	= of_get_parent(ports);
948 	ports0	= of_get_child_by_name(top, "ports");
949 
950 	ret = ports0 == ports;
951 
952 	of_node_put(port);
953 	of_node_put(ports);
954 	of_node_put(ports0);
955 	of_node_put(top);
956 
957 	return ret;
958 }
959 EXPORT_SYMBOL_GPL(asoc_graph_is_ports0);
960 
961 /* Module information */
962 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
963 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
964 MODULE_LICENSE("GPL v2");
965