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