1 // SPDX-License-Identifier: GPL-2.0
5 // Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
8 #include <linux/gpio.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.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>
17 static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data,
18 struct snd_pcm_hw_params *params)
21 struct snd_mask *mask = hw_param_mask(params,
22 SNDRV_PCM_HW_PARAM_FORMAT);
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},
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)) {
38 snd_mask_set(mask, of_sample_fmt_table[i].val);
44 void asoc_simple_convert_fixup(struct asoc_simple_data *data,
45 struct snd_pcm_hw_params *params)
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);
52 if (data->convert_rate)
54 rate->max = data->convert_rate;
56 if (data->convert_channels)
58 channels->max = data->convert_channels;
60 if (data->convert_sample_format)
61 asoc_simple_fixup_sample_fmt(data, params);
63 EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
65 void asoc_simple_parse_convert(struct device_node *np,
67 struct asoc_simple_data *data)
74 /* sampling rate convert */
75 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
76 of_property_read_u32(np, prop, &data->convert_rate);
78 /* channels transfer */
79 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
80 of_property_read_u32(np, prop, &data->convert_channels);
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);
86 EXPORT_SYMBOL_GPL(asoc_simple_parse_convert);
88 int asoc_simple_parse_daifmt(struct device *dev,
89 struct device_node *node,
90 struct device_node *codec,
94 struct device_node *bitclkmaster = NULL;
95 struct device_node *framemaster = NULL;
98 daifmt = snd_soc_daifmt_parse_format(node, prefix);
100 snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster);
101 if (!bitclkmaster && !framemaster) {
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.
107 dev_dbg(dev, "Revert to legacy daifmt parsing\n");
109 daifmt |= snd_soc_daifmt_parse_clock_provider_as_flag(codec, NULL);
111 daifmt |= snd_soc_daifmt_clock_provider_from_bitmap(
112 ((codec == bitclkmaster) << 4) | (codec == framemaster));
115 of_node_put(bitclkmaster);
116 of_node_put(framemaster);
122 EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt);
124 int asoc_simple_parse_tdm_width_map(struct device *dev, struct device_node *np,
125 struct asoc_simple_dai *dai)
127 u32 *array_values, *p;
130 if (!of_property_read_bool(np, "dai-tdm-slot-width-map"))
133 n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32));
135 dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n");
139 dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL);
140 if (!dai->tdm_width_map)
143 array_values = kcalloc(n, sizeof(*array_values), GFP_KERNEL);
147 ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n);
149 dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret);
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++;
160 dai->n_tdm_widths = i;
167 EXPORT_SYMBOL_GPL(asoc_simple_parse_tdm_width_map);
169 int asoc_simple_set_dailink_name(struct device *dev,
170 struct snd_soc_dai_link *dai_link,
171 const char *fmt, ...)
178 name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
184 dai_link->name = name;
185 dai_link->stream_name = name;
190 EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name);
192 int asoc_simple_parse_card_name(struct snd_soc_card *card,
200 /* Parse the card name from DT */
201 ret = snd_soc_of_parse_card_name(card, "label");
202 if (ret < 0 || !card->name) {
205 snprintf(prop, sizeof(prop), "%sname", prefix);
206 ret = snd_soc_of_parse_card_name(card, prop);
211 if (!card->name && card->dai_link)
212 card->name = card->dai_link->name;
216 EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name);
218 static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
221 return clk_prepare_enable(dai->clk);
226 static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
229 clk_disable_unprepare(dai->clk);
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)
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.
246 clk = devm_get_clk_from_child(dev, node, NULL);
247 simple_dai->clk_fixed = of_property_read_bool(
248 node, "system-clock-fixed");
250 simple_dai->sysclk = clk_get_rate(clk);
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;
257 clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
259 simple_dai->sysclk = clk_get_rate(clk);
262 if (of_property_read_bool(node, "system-clock-direction-out"))
263 simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
267 EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
269 static int asoc_simple_check_fixed_sysclk(struct device *dev,
270 struct asoc_simple_dai *dai,
271 unsigned int *fixed_sysclk)
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);
279 *fixed_sysclk = dai->sysclk;
285 int asoc_simple_startup(struct snd_pcm_substream *substream)
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;
295 for_each_prop_dai_cpu(props, i1, dai) {
296 ret = asoc_simple_clk_enable(dai);
299 ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
304 for_each_prop_dai_codec(props, i2, dai) {
305 ret = asoc_simple_clk_enable(dai);
308 ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
313 if (fixed_sysclk && props->mclk_fs) {
314 unsigned int fixed_rate = fixed_sysclk / props->mclk_fs;
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);
321 ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
322 fixed_rate, fixed_rate);
330 for_each_prop_dai_codec(props, i, dai) {
333 asoc_simple_clk_disable(dai);
336 for_each_prop_dai_cpu(props, i, dai) {
339 asoc_simple_clk_disable(dai);
343 EXPORT_SYMBOL_GPL(asoc_simple_startup);
345 void asoc_simple_shutdown(struct snd_pcm_substream *substream)
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;
353 for_each_prop_dai_cpu(props, i, dai) {
354 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, i);
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);
360 asoc_simple_clk_disable(dai);
362 for_each_prop_dai_codec(props, i, dai) {
363 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, i);
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);
369 asoc_simple_clk_disable(dai);
372 EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
374 static int asoc_simple_set_clk_rate(struct device *dev,
375 struct asoc_simple_dai *simple_dai,
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);
386 if (!simple_dai->clk)
389 if (clk_get_rate(simple_dai->clk) == rate)
392 return clk_set_rate(simple_dai->clk, rate);
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)
399 int sample_bits = params_width(params);
400 int slot_width, slot_count;
403 if (!simple_dai || !simple_dai->tdm_width_map)
406 slot_width = simple_dai->slot_width;
407 slot_count = simple_dai->slots;
410 slot_width = sample_bits;
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;
420 ret = snd_soc_dai_set_tdm_slot(dai,
421 simple_dai->tx_slot_mask,
422 simple_dai->rx_slot_mask,
425 if (ret && ret != -ENOTSUPP) {
426 dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret);
433 int asoc_simple_hw_params(struct snd_pcm_substream *substream,
434 struct snd_pcm_hw_params *params)
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;
445 mclk_fs = props->mclk_fs;
448 struct snd_soc_component *component;
449 mclk = params_rate(params) * mclk_fs;
451 for_each_prop_dai_codec(props, i, pdai) {
452 ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
457 for_each_prop_dai_cpu(props, i, pdai) {
458 ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
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.
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)
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)
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)
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);
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);
503 EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
505 int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
506 struct snd_pcm_hw_params *params)
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);
511 asoc_simple_convert_fixup(&dai_props->adata, params);
515 EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup);
517 static int asoc_simple_init_dai(struct snd_soc_dai *dai,
518 struct asoc_simple_dai *simple_dai)
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");
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,
539 simple_dai->slot_width);
540 if (ret && ret != -ENOTSUPP) {
541 dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
549 static inline int asoc_simple_component_is_codec(struct snd_soc_component *component)
551 return component->driver->endianness;
554 static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
555 struct simple_dai_props *dai_props)
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;
563 /* Do nothing if it already has Codec2Codec settings */
564 if (dai_link->params)
567 /* Do nothing if it was DPCM :: BE */
568 if (dai_link->no_pcm)
572 for_each_rtd_components(rtd, i, component) {
573 if (!asoc_simple_component_is_codec(component))
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);
585 dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
589 params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL);
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;
600 dai_link->params = params;
601 dai_link->num_params = 1;
606 int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
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;
613 for_each_prop_dai_codec(props, i, dai) {
614 ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
618 for_each_prop_dai_cpu(props, i, dai) {
619 ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
624 ret = asoc_simple_init_for_codec2codec(rtd, props);
630 EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
632 void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
633 struct snd_soc_dai_link_component *cpus)
635 /* Assumes platform == cpu */
636 if (!platforms->of_node)
637 platforms->of_node = cpus->of_node;
639 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
641 void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
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
651 * fmt_multiple_name()
654 cpus->dai_name = NULL;
656 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
658 void asoc_simple_clean_reference(struct snd_soc_card *card)
660 struct snd_soc_dai_link *dai_link;
661 struct snd_soc_dai_link_component *cpu;
662 struct snd_soc_dai_link_component *codec;
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);
672 EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
674 int asoc_simple_parse_routing(struct snd_soc_card *card,
677 struct device_node *node = card->dev->of_node;
683 snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
685 if (!of_property_read_bool(node, prop))
688 return snd_soc_of_parse_audio_routing(card, prop);
690 EXPORT_SYMBOL_GPL(asoc_simple_parse_routing);
692 int asoc_simple_parse_widgets(struct snd_soc_card *card,
695 struct device_node *node = card->dev->of_node;
701 snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
703 if (of_property_read_bool(node, prop))
704 return snd_soc_of_parse_audio_simple_widgets(card, prop);
706 /* no widgets is not error */
709 EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets);
711 int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
719 snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
721 return snd_soc_of_parse_pin_switches(card, prop);
723 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
725 int asoc_simple_init_jack(struct snd_soc_card *card,
726 struct asoc_simple_jack *sjack,
727 int is_hp, char *prefix,
730 struct device *dev = card->dev;
731 struct gpio_desc *desc;
741 sjack->gpio.gpio = -ENOENT;
744 snprintf(prop, sizeof(prop), "%shp-det", prefix);
745 pin_name = pin ? pin : "Headphones";
746 gpio_name = "Headphone detection";
747 mask = SND_JACK_HEADPHONE;
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;
755 desc = gpiod_get_optional(dev, prop, GPIOD_IN);
756 error = PTR_ERR_OR_ZERO(desc);
761 error = gpiod_set_consumer_name(desc, gpio_name);
765 sjack->pin.pin = pin_name;
766 sjack->pin.mask = mask;
768 sjack->gpio.name = gpio_name;
769 sjack->gpio.report = mask;
770 sjack->gpio.desc = desc;
771 sjack->gpio.debounce_time = 150;
773 snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack,
776 snd_soc_jack_add_gpios(&sjack->jack, 1, &sjack->gpio);
781 EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
783 int asoc_simple_init_priv(struct asoc_simple_priv *priv,
784 struct link_info *li)
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;
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)
802 * dlcs (= CPU+Codec+Platform)
804 for (i = 0; i < li->link; i++) {
805 int cc = li->num[i].cpus + li->num[i].codecs;
808 dlc_num += cc + li->num[i].platforms;
810 if (!li->num[i].cpus)
811 cnf_num += li->num[i].codecs;
814 dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
815 dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL);
820 cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
825 dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
826 li->link, dai_num, cnf_num);
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";
833 priv->dai_props = dai_props;
834 priv->dai_link = dai_link;
837 priv->codec_conf = cconf;
839 card->dai_link = priv->dai_link;
840 card->num_links = li->link;
841 card->codec_conf = cconf;
842 card->num_configs = cnf_num;
844 for (i = 0; i < li->link; i++) {
845 if (li->num[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;
853 dlcs += li->num[i].cpus;
854 dais += li->num[i].cpus;
856 /* DPCM Be's CPU = dummy */
858 dai_link[i].cpus = &priv->dummy;
859 dai_props[i].num.cpus =
860 dai_link[i].num_cpus = 1;
863 if (li->num[i].codecs) {
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;
871 dlcs += li->num[i].codecs;
872 dais += li->num[i].codecs;
874 if (!li->num[i].cpus) {
875 /* DPCM Be's Codec */
876 dai_props[i].codec_conf = cconf;
877 cconf += li->num[i].codecs;
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;
887 if (li->num[i].platforms) {
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;
894 dlcs += li->num[i].platforms;
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;
906 EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
908 int asoc_simple_remove(struct platform_device *pdev)
910 struct snd_soc_card *card = platform_get_drvdata(pdev);
912 asoc_simple_clean_reference(card);
916 EXPORT_SYMBOL_GPL(asoc_simple_remove);
918 int asoc_graph_card_probe(struct snd_soc_card *card)
920 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
923 ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
927 ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
933 EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
935 int asoc_graph_is_ports0(struct device_node *np)
937 struct device_node *port, *ports, *ports0, *top;
940 /* np is "endpoint" or "port" */
941 if (of_node_name_eq(np, "endpoint")) {
942 port = of_get_parent(np);
948 ports = of_get_parent(port);
949 top = of_get_parent(ports);
950 ports0 = of_get_child_by_name(top, "ports");
952 ret = ports0 == ports;
961 EXPORT_SYMBOL_GPL(asoc_graph_is_ports0);
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");