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