Lines Matching +full:dai +full:- +full:tdm +full:- +full:slot +full:- +full:width
1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2017-2021 NXP
15 #include <sound/soc-dapm.h>
32 * Mapping LRCK fs and frame width, table 3 & 4 in datasheet
46 * Mapping TDM mode and frame width
55 * struct imx_card_plat_data - specific info for codecs
58 * @tdm_fs_mul: ratio of mclk/fs for tdm mode
60 * @support_tdm_rates: supported sample rate for tdm mode
62 * @support_tdm_channels: supported channels for tdm mode
89 * struct dai_link_data - specific info for dai link
91 * @slots: slot number
92 * @slot_width: slot width value
93 * @cpu_sysclk_id: sysclk id for cpu dai
104 * struct imx_card_data - platform device data
108 * @link_data: private data for dai link
143 * Table 13 - Audio Interface Format
144 * For TDM mode, MCLK should is set to
154 * Table 7 - mapping multiplier and speed mode
155 * Tables 8 & 9 - mapping speed mode and LRCK fs
179 * MCLK and BCLK selection based on TDM mode
232 if (link_data->slots > 2) in format_is_tdm()
256 struct snd_soc_pcm_runtime *rtd = substream->private_data; in akcodec_get_mclk_rate()
257 struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card); in akcodec_get_mclk_rate()
258 const struct imx_card_plat_data *plat_data = data->plat_data; in akcodec_get_mclk_rate()
259 struct dai_link_data *link_data = &data->link_data[rtd->num]; in akcodec_get_mclk_rate()
260 unsigned int width = slots * slot_width; in akcodec_get_mclk_rate() local
265 for (i = 0; i < plat_data->num_tdm_fs_mul; i++) { in akcodec_get_mclk_rate()
267 if (width != plat_data->tdm_fs_mul[i].min) in akcodec_get_mclk_rate()
269 return rate * plat_data->tdm_fs_mul[i].mul; in akcodec_get_mclk_rate()
272 for (i = 0; i < plat_data->num_fs_mul; i++) { in akcodec_get_mclk_rate()
273 if (rate >= plat_data->fs_mul[i].rmin && in akcodec_get_mclk_rate()
274 rate <= plat_data->fs_mul[i].rmax) { in akcodec_get_mclk_rate()
275 width = max(width, plat_data->fs_mul[i].wmin); in akcodec_get_mclk_rate()
276 width = min(width, plat_data->fs_mul[i].wmax); in akcodec_get_mclk_rate()
279 width *= link_data->one2one_ratio ? 1 : 2; in akcodec_get_mclk_rate()
281 return rate * width; in akcodec_get_mclk_rate()
286 /* Let DAI manage clk frequency by default */ in akcodec_get_mclk_rate()
293 struct snd_soc_pcm_runtime *rtd = substream->private_data; in imx_aif_hw_params()
295 struct snd_soc_card *card = rtd->card; in imx_aif_hw_params()
297 struct dai_link_data *link_data = &data->link_data[rtd->num]; in imx_aif_hw_params()
298 struct imx_card_plat_data *plat_data = data->plat_data; in imx_aif_hw_params()
299 struct device *dev = card->dev; in imx_aif_hw_params()
302 unsigned int fmt = rtd->dai_link->dai_fmt; in imx_aif_hw_params()
306 slots = link_data->slots; in imx_aif_hw_params()
307 slot_width = link_data->slot_width; in imx_aif_hw_params()
313 fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | in imx_aif_hw_params()
318 fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | in imx_aif_hw_params()
324 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
325 dev_err(dev, "failed to set cpu dai fmt: %d\n", ret); in imx_aif_hw_params()
329 BIT(slots) - 1, in imx_aif_hw_params()
330 BIT(slots) - 1, in imx_aif_hw_params()
332 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
333 dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret); in imx_aif_hw_params()
339 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
340 dev_err(dev, "failed to set codec dai[%d] fmt: %d\n", i, ret); in imx_aif_hw_params()
345 BIT(slots) - 1, in imx_aif_hw_params()
346 BIT(slots) - 1, in imx_aif_hw_params()
348 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
349 dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); in imx_aif_hw_params()
355 if (codec_is_akcodec(plat_data->type)) in imx_aif_hw_params()
368 ret = snd_soc_dai_set_sysclk(cpu_dai, link_data->cpu_sysclk_id, mclk_freq, in imx_aif_hw_params()
370 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
371 dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret); in imx_aif_hw_params()
380 struct dai_link_data *link_data = r->private; in ak5558_hw_rule_rate()
386 fs = hw_param_interval(p, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; in ak5558_hw_rule_rate()
387 fs *= link_data->slots; in ak5558_hw_rule_rate()
393 mclk_freq *= link_data->one2one_ratio ? 1 : 2; in ak5558_hw_rule_rate()
403 return snd_interval_refine(hw_param_interval(p, r->var), &t); in ak5558_hw_rule_rate()
408 struct snd_pcm_runtime *runtime = substream->runtime; in imx_aif_startup()
409 struct snd_soc_pcm_runtime *rtd = substream->private_data; in imx_aif_startup()
410 struct snd_soc_card *card = rtd->card; in imx_aif_startup()
412 struct dai_link_data *link_data = &data->link_data[rtd->num]; in imx_aif_startup()
418 constraint_channels.list = data->plat_data->support_tdm_channels; in imx_aif_startup()
419 constraint_channels.count = data->plat_data->num_tdm_channels; in imx_aif_startup()
420 constraint_rates.list = data->plat_data->support_tdm_rates; in imx_aif_startup()
421 constraint_rates.count = data->plat_data->num_tdm_rates; in imx_aif_startup()
423 constraint_channels.list = data->plat_data->support_channels; in imx_aif_startup()
424 constraint_channels.count = data->plat_data->num_channels; in imx_aif_startup()
425 constraint_rates.list = data->plat_data->support_rates; in imx_aif_startup()
426 constraint_rates.count = data->plat_data->num_rates; in imx_aif_startup()
445 if (data->plat_data->type == CODEC_AK5558) in imx_aif_startup()
446 ret = snd_pcm_hw_rule_add(substream->runtime, 0, in imx_aif_startup()
449 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); in imx_aif_startup()
466 struct snd_soc_card *card = rtd->card; in be_hw_params_fixup()
472 rate->max = data->asrc_rate; in be_hw_params_fixup()
473 rate->min = data->asrc_rate; in be_hw_params_fixup()
477 snd_mask_set(mask, (__force unsigned int)data->asrc_format); in be_hw_params_fixup()
484 struct imx_card_plat_data *plat_data = data->plat_data; in imx_card_parse_of()
485 struct snd_soc_card *card = &data->card; in imx_card_parse_of()
491 struct device *dev = card->dev; in imx_card_parse_of()
497 u32 width; in imx_card_parse_of() local
506 if (of_property_read_bool(dev->of_node, "audio-routing")) { in imx_card_parse_of()
507 ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); in imx_card_parse_of()
513 num_links = of_get_child_count(dev->of_node); in imx_card_parse_of()
515 /* Allocate the DAI link array */ in imx_card_parse_of()
516 card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); in imx_card_parse_of()
517 if (!card->dai_link) in imx_card_parse_of()
518 return -ENOMEM; in imx_card_parse_of()
520 data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); in imx_card_parse_of()
521 if (!data->link_data) in imx_card_parse_of()
522 return -ENOMEM; in imx_card_parse_of()
524 card->num_links = num_links; in imx_card_parse_of()
525 link = card->dai_link; in imx_card_parse_of()
526 link_data = data->link_data; in imx_card_parse_of()
528 for_each_child_of_node(dev->of_node, np) { in imx_card_parse_of()
531 ret = -ENOMEM; in imx_card_parse_of()
535 link->cpus = &dlc[0]; in imx_card_parse_of()
536 link->platforms = &dlc[1]; in imx_card_parse_of()
538 link->num_cpus = 1; in imx_card_parse_of()
539 link->num_platforms = 1; in imx_card_parse_of()
541 ret = of_property_read_string(np, "link-name", &link->name); in imx_card_parse_of()
543 dev_err(card->dev, "error getting codec dai_link name\n"); in imx_card_parse_of()
549 dev_err(dev, "%s: Can't find cpu DT node\n", link->name); in imx_card_parse_of()
550 ret = -EINVAL; in imx_card_parse_of()
554 ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); in imx_card_parse_of()
556 dev_err_probe(card->dev, ret, in imx_card_parse_of()
557 "%s: error getting cpu dai info\n", link->name); in imx_card_parse_of()
563 link_data->cpu_sysclk_id = FSL_SAI_CLK_MAST1; in imx_card_parse_of()
566 if (of_property_read_bool(np, "fsl,mclk-equal-bclk")) { in imx_card_parse_of()
567 link_data->one2one_ratio = true; in imx_card_parse_of()
585 link->platforms->of_node = link->cpus->of_node; in imx_card_parse_of()
586 link->id = args.args[0]; in imx_card_parse_of()
592 dev_err_probe(dev, ret, "%s: codec dai not found\n", in imx_card_parse_of()
593 link->name); in imx_card_parse_of()
597 plat_data->num_codecs = link->num_codecs; in imx_card_parse_of()
600 if (!strcmp(link->codecs->dai_name, "ak4458-aif")) in imx_card_parse_of()
601 plat_data->type = CODEC_AK4458; in imx_card_parse_of()
602 else if (!strcmp(link->codecs->dai_name, "ak4497-aif")) in imx_card_parse_of()
603 plat_data->type = CODEC_AK4497; in imx_card_parse_of()
604 else if (!strcmp(link->codecs->dai_name, "ak5558-aif")) in imx_card_parse_of()
605 plat_data->type = CODEC_AK5558; in imx_card_parse_of()
606 else if (!strcmp(link->codecs->dai_name, "ak5552-aif")) in imx_card_parse_of()
607 plat_data->type = CODEC_AK5552; in imx_card_parse_of()
610 link->codecs = &asoc_dummy_dlc; in imx_card_parse_of()
611 link->num_codecs = 1; in imx_card_parse_of()
614 if (!strncmp(link->name, "HiFi-ASRC-FE", 12)) { in imx_card_parse_of()
616 link->dynamic = 1; in imx_card_parse_of()
617 link->dpcm_merged_chan = 1; in imx_card_parse_of()
619 ret = of_property_read_u32(args.np, "fsl,asrc-rate", &data->asrc_rate); in imx_card_parse_of()
622 ret = -EINVAL; in imx_card_parse_of()
626 ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt); in imx_card_parse_of()
627 data->asrc_format = (__force snd_pcm_format_t)asrc_fmt; in imx_card_parse_of()
630 ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); in imx_card_parse_of()
637 if (width == 24) in imx_card_parse_of()
638 data->asrc_format = SNDRV_PCM_FORMAT_S24_LE; in imx_card_parse_of()
640 data->asrc_format = SNDRV_PCM_FORMAT_S16_LE; in imx_card_parse_of()
642 } else if (!strncmp(link->name, "HiFi-ASRC-BE", 12)) { in imx_card_parse_of()
644 link->no_pcm = 1; in imx_card_parse_of()
645 link->platforms->of_node = NULL; in imx_card_parse_of()
646 link->platforms->name = "snd-soc-dummy"; in imx_card_parse_of()
648 link->be_hw_params_fixup = be_hw_params_fixup; in imx_card_parse_of()
649 link->ops = &imx_aif_ops_be; in imx_card_parse_of()
651 link->ops = &imx_aif_ops; in imx_card_parse_of()
654 if (link->no_pcm || link->dynamic) in imx_card_parse_of()
657 /* Get dai fmt */ in imx_card_parse_of()
659 NULL, &link->dai_fmt); in imx_card_parse_of()
661 link->dai_fmt = SND_SOC_DAIFMT_NB_NF | in imx_card_parse_of()
665 /* Get tdm slot */ in imx_card_parse_of()
667 &link_data->slots, in imx_card_parse_of()
668 &link_data->slot_width); in imx_card_parse_of()
670 if (!link_data->slots) in imx_card_parse_of()
671 link_data->slots = 2; in imx_card_parse_of()
673 if (!link_data->slot_width) in imx_card_parse_of()
674 link_data->slot_width = 32; in imx_card_parse_of()
676 link->ignore_pmdown_time = 1; in imx_card_parse_of()
677 link->stream_name = link->name; in imx_card_parse_of()
707 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); in imx_card_probe()
709 return -ENOMEM; in imx_card_probe()
711 plat_data = devm_kzalloc(&pdev->dev, sizeof(*plat_data), GFP_KERNEL); in imx_card_probe()
713 return -ENOMEM; in imx_card_probe()
715 data->plat_data = plat_data; in imx_card_probe()
716 data->card.dev = &pdev->dev; in imx_card_probe()
718 dev_set_drvdata(&pdev->dev, &data->card); in imx_card_probe()
719 snd_soc_card_set_drvdata(&data->card, data); in imx_card_probe()
724 data->num_dapm_routes = plat_data->num_codecs + 1; in imx_card_probe()
725 data->dapm_routes = devm_kcalloc(&pdev->dev, data->num_dapm_routes, in imx_card_probe()
728 if (!data->dapm_routes) in imx_card_probe()
729 return -ENOMEM; in imx_card_probe()
732 switch (plat_data->type) { in imx_card_probe()
735 if (plat_data->num_codecs == 1) { in imx_card_probe()
736 data->dapm_routes[0].sink = "Playback"; in imx_card_probe()
737 data->dapm_routes[0].source = "CPU-Playback"; in imx_card_probe()
740 for (i = 0; i < plat_data->num_codecs; i++) { in imx_card_probe()
741 data->dapm_routes[i].sink = in imx_card_probe()
742 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", in imx_card_probe()
744 data->dapm_routes[i].source = "CPU-Playback"; in imx_card_probe()
747 data->dapm_routes[i].sink = "CPU-Playback"; in imx_card_probe()
748 data->dapm_routes[i].source = "ASRC-Playback"; in imx_card_probe()
752 if (plat_data->num_codecs == 1) { in imx_card_probe()
753 data->dapm_routes[0].sink = "CPU-Capture"; in imx_card_probe()
754 data->dapm_routes[0].source = "Capture"; in imx_card_probe()
757 for (i = 0; i < plat_data->num_codecs; i++) { in imx_card_probe()
758 data->dapm_routes[i].source = in imx_card_probe()
759 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", in imx_card_probe()
761 data->dapm_routes[i].sink = "CPU-Capture"; in imx_card_probe()
764 data->dapm_routes[i].sink = "ASRC-Capture"; in imx_card_probe()
765 data->dapm_routes[i].source = "CPU-Capture"; in imx_card_probe()
772 if (codec_is_akcodec(plat_data->type)) { in imx_card_probe()
773 plat_data->support_rates = akcodec_rates; in imx_card_probe()
774 plat_data->num_rates = ARRAY_SIZE(akcodec_rates); in imx_card_probe()
775 plat_data->support_tdm_rates = akcodec_tdm_rates; in imx_card_probe()
776 plat_data->num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates); in imx_card_probe()
778 switch (plat_data->type) { in imx_card_probe()
780 plat_data->fs_mul = ak4458_fs_mul; in imx_card_probe()
781 plat_data->num_fs_mul = ARRAY_SIZE(ak4458_fs_mul); in imx_card_probe()
782 plat_data->tdm_fs_mul = ak4458_tdm_fs_mul; in imx_card_probe()
783 plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak4458_tdm_fs_mul); in imx_card_probe()
784 plat_data->support_channels = ak4458_channels; in imx_card_probe()
785 plat_data->num_channels = ARRAY_SIZE(ak4458_channels); in imx_card_probe()
786 plat_data->support_tdm_channels = ak4458_tdm_channels; in imx_card_probe()
787 plat_data->num_tdm_channels = ARRAY_SIZE(ak4458_tdm_channels); in imx_card_probe()
790 plat_data->fs_mul = ak4497_fs_mul; in imx_card_probe()
791 plat_data->num_fs_mul = ARRAY_SIZE(ak4497_fs_mul); in imx_card_probe()
792 plat_data->support_channels = ak4458_channels; in imx_card_probe()
793 plat_data->num_channels = ARRAY_SIZE(ak4458_channels); in imx_card_probe()
797 plat_data->fs_mul = ak5558_fs_mul; in imx_card_probe()
798 plat_data->num_fs_mul = ARRAY_SIZE(ak5558_fs_mul); in imx_card_probe()
799 plat_data->tdm_fs_mul = ak5558_tdm_fs_mul; in imx_card_probe()
800 plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak5558_tdm_fs_mul); in imx_card_probe()
801 plat_data->support_channels = ak5558_channels; in imx_card_probe()
802 plat_data->num_channels = ARRAY_SIZE(ak5558_channels); in imx_card_probe()
803 plat_data->support_tdm_channels = ak5558_tdm_channels; in imx_card_probe()
804 plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels); in imx_card_probe()
812 if (data->card.num_links == 3) { in imx_card_probe()
813 data->card.dapm_routes = data->dapm_routes; in imx_card_probe()
814 data->card.num_dapm_routes = data->num_dapm_routes; in imx_card_probe()
815 for_each_card_prelinks(&data->card, i, link) { in imx_card_probe()
816 if (link->no_pcm == 1) in imx_card_probe()
819 for_each_card_prelinks(&data->card, i, link) { in imx_card_probe()
820 if (link->dynamic == 1 && link_be) { in imx_card_probe()
821 link->dpcm_playback = link_be->dpcm_playback; in imx_card_probe()
822 link->dpcm_capture = link_be->dpcm_capture; in imx_card_probe()
827 ret = devm_snd_soc_register_card(&pdev->dev, &data->card); in imx_card_probe()
829 return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); in imx_card_probe()
835 { .compatible = "fsl,imx-audio-card", },
842 .name = "imx-card",
852 MODULE_ALIAS("platform:imx-card");