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