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