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