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
14 #include <sound/soc-dapm.h>
33 * Mapping LRCK fs and frame width, table 3 & 4 in datasheet
47 * Mapping TDM mode and frame width
56 * struct imx_card_plat_data - specific info for codecs
59 * @tdm_fs_mul: ratio of mclk/fs for tdm mode
61 * @support_tdm_rates: supported sample rate for tdm mode
63 * @support_tdm_channels: supported channels for tdm mode
90 * struct dai_link_data - specific info for dai link
92 * @slots: slot number
93 * @slot_width: slot width value
94 * @cpu_sysclk_id: sysclk id for cpu dai
105 * struct imx_card_data - platform device data
109 * @link_data: private data for dai link
144 * Table 13 - Audio Interface Format
145 * For TDM mode, MCLK should is set to
155 * Table 7 - mapping multiplier and speed mode
156 * Tables 8 & 9 - mapping speed mode and LRCK fs
180 * MCLK and BCLK selection based on TDM mode
262 if (link_data->slots > 2) in format_is_tdm()
289 struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card); in akcodec_get_mclk_rate()
290 const struct imx_card_plat_data *plat_data = data->plat_data; in akcodec_get_mclk_rate()
291 struct dai_link_data *link_data = &data->link_data[rtd->id]; in akcodec_get_mclk_rate()
292 unsigned int width = slots * slot_width; in akcodec_get_mclk_rate() local
297 for (i = 0; i < plat_data->num_tdm_fs_mul; i++) { in akcodec_get_mclk_rate()
299 if (width != plat_data->tdm_fs_mul[i].min) in akcodec_get_mclk_rate()
301 return rate * plat_data->tdm_fs_mul[i].mul; in akcodec_get_mclk_rate()
304 for (i = 0; i < plat_data->num_fs_mul; i++) { in akcodec_get_mclk_rate()
305 if (rate >= plat_data->fs_mul[i].rmin && in akcodec_get_mclk_rate()
306 rate <= plat_data->fs_mul[i].rmax) { in akcodec_get_mclk_rate()
307 width = max(width, plat_data->fs_mul[i].wmin); in akcodec_get_mclk_rate()
308 width = min(width, plat_data->fs_mul[i].wmax); in akcodec_get_mclk_rate()
311 width *= link_data->one2one_ratio ? 1 : 2; in akcodec_get_mclk_rate()
313 return rate * width; in akcodec_get_mclk_rate()
318 /* Let DAI manage clk frequency by default */ in akcodec_get_mclk_rate()
327 struct snd_soc_card *card = rtd->card; in imx_aif_hw_params()
329 struct dai_link_data *link_data = &data->link_data[rtd->id]; in imx_aif_hw_params()
330 struct imx_card_plat_data *plat_data = data->plat_data; in imx_aif_hw_params()
331 struct device *dev = card->dev; in imx_aif_hw_params()
334 unsigned int fmt = rtd->dai_link->dai_fmt; in imx_aif_hw_params()
338 slots = link_data->slots; in imx_aif_hw_params()
339 slot_width = link_data->slot_width; in imx_aif_hw_params()
345 fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | in imx_aif_hw_params()
350 fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | in imx_aif_hw_params()
356 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
357 dev_err(dev, "failed to set cpu dai fmt: %d\n", ret); in imx_aif_hw_params()
361 BIT(slots) - 1, in imx_aif_hw_params()
362 BIT(slots) - 1, in imx_aif_hw_params()
364 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
365 dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret); in imx_aif_hw_params()
371 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
372 dev_err(dev, "failed to set codec dai[%d] fmt: %d\n", i, ret); in imx_aif_hw_params()
378 BIT(slots) - 1, in imx_aif_hw_params()
379 BIT(slots) - 1, in imx_aif_hw_params()
381 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
382 dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); in imx_aif_hw_params()
389 if (codec_is_akcodec(plat_data->type)) in imx_aif_hw_params()
402 ret = snd_soc_dai_set_sysclk(cpu_dai, link_data->cpu_sysclk_id, mclk_freq, in imx_aif_hw_params()
404 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
405 dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret); in imx_aif_hw_params()
409 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
410 dev_err(dev, "failed to set codec dai mclk rate (%lu): %d\n", mclk_freq, ret); in imx_aif_hw_params()
419 struct dai_link_data *link_data = r->private; in ak5558_hw_rule_rate()
425 fs = hw_param_interval(p, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; in ak5558_hw_rule_rate()
426 fs *= link_data->slots; in ak5558_hw_rule_rate()
432 mclk_freq *= link_data->one2one_ratio ? 1 : 2; in ak5558_hw_rule_rate()
442 return snd_interval_refine(hw_param_interval(p, r->var), &t); in ak5558_hw_rule_rate()
447 struct snd_pcm_runtime *runtime = substream->runtime; in imx_aif_startup()
449 struct snd_soc_card *card = rtd->card; in imx_aif_startup()
451 struct dai_link_data *link_data = &data->link_data[rtd->id]; in imx_aif_startup()
457 constraint_channels.list = data->plat_data->support_tdm_channels; in imx_aif_startup()
458 constraint_channels.count = data->plat_data->num_tdm_channels; in imx_aif_startup()
459 constraint_rates.list = data->plat_data->support_tdm_rates; in imx_aif_startup()
460 constraint_rates.count = data->plat_data->num_tdm_rates; in imx_aif_startup()
462 constraint_channels.list = data->plat_data->support_channels; in imx_aif_startup()
463 constraint_channels.count = data->plat_data->num_channels; in imx_aif_startup()
464 constraint_rates.list = data->plat_data->support_rates; in imx_aif_startup()
465 constraint_rates.count = data->plat_data->num_rates; in imx_aif_startup()
484 if (data->plat_data->type == CODEC_AK5558) in imx_aif_startup()
485 ret = snd_pcm_hw_rule_add(substream->runtime, 0, in imx_aif_startup()
488 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); in imx_aif_startup()
520 struct snd_soc_card *card = rtd->card; in be_hw_params_fixup()
526 rate->max = data->asrc_rate; in be_hw_params_fixup()
527 rate->min = data->asrc_rate; in be_hw_params_fixup()
531 snd_mask_set(mask, (__force unsigned int)data->asrc_format); in be_hw_params_fixup()
538 struct imx_card_plat_data *plat_data = data->plat_data; in imx_card_parse_of()
539 struct snd_soc_card *card = &data->card; in imx_card_parse_of()
544 struct device *dev = card->dev; in imx_card_parse_of()
551 u32 width; in imx_card_parse_of() local
560 if (of_property_present(dev->of_node, "audio-routing")) { in imx_card_parse_of()
561 ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); in imx_card_parse_of()
567 num_links = of_get_child_count(dev->of_node); in imx_card_parse_of()
569 /* Allocate the DAI link array */ in imx_card_parse_of()
570 card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); in imx_card_parse_of()
571 if (!card->dai_link) in imx_card_parse_of()
572 return -ENOMEM; in imx_card_parse_of()
574 data->link_data = devm_kcalloc(dev, num_links, sizeof(*link_data), GFP_KERNEL); in imx_card_parse_of()
575 if (!data->link_data) in imx_card_parse_of()
576 return -ENOMEM; in imx_card_parse_of()
578 card->num_links = num_links; in imx_card_parse_of()
579 link = card->dai_link; in imx_card_parse_of()
580 link_data = data->link_data; in imx_card_parse_of()
582 for_each_child_of_node_scoped(dev->of_node, np) { in imx_card_parse_of()
585 return -ENOMEM; in imx_card_parse_of()
588 link->cpus = &dlc[0]; in imx_card_parse_of()
589 link->platforms = &dlc[1]; in imx_card_parse_of()
591 link->num_cpus = 1; in imx_card_parse_of()
592 link->num_platforms = 1; in imx_card_parse_of()
594 ret = of_property_read_string(np, "link-name", &link->name); in imx_card_parse_of()
596 return dev_err_probe(card->dev, ret, in imx_card_parse_of()
602 dev_err(dev, "%s: Can't find cpu DT node\n", link->name); in imx_card_parse_of()
603 ret = -EINVAL; in imx_card_parse_of()
607 ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); in imx_card_parse_of()
609 dev_err_probe(card->dev, ret, in imx_card_parse_of()
610 "%s: error getting cpu dai info\n", link->name); in imx_card_parse_of()
616 link_data->cpu_sysclk_id = FSL_SAI_CLK_MAST1; in imx_card_parse_of()
619 if (of_property_read_bool(np, "fsl,mclk-equal-bclk")) { in imx_card_parse_of()
620 link_data->one2one_ratio = true; in imx_card_parse_of()
638 link->platforms->of_node = link->cpus->of_node; in imx_card_parse_of()
639 link->id = args.args[0]; in imx_card_parse_of()
645 dev_err_probe(dev, ret, "%s: codec dai not found\n", in imx_card_parse_of()
646 link->name); in imx_card_parse_of()
650 plat_data->num_codecs = link->num_codecs; in imx_card_parse_of()
653 if (!strcmp(link->codecs->dai_name, "ak4458-aif")) in imx_card_parse_of()
654 plat_data->type = CODEC_AK4458; in imx_card_parse_of()
655 else if (!strcmp(link->codecs->dai_name, "ak4497-aif")) in imx_card_parse_of()
656 plat_data->type = CODEC_AK4497; in imx_card_parse_of()
657 else if (!strcmp(link->codecs->dai_name, "ak5558-aif")) in imx_card_parse_of()
658 plat_data->type = CODEC_AK5558; in imx_card_parse_of()
659 else if (!strcmp(link->codecs->dai_name, "ak5552-aif")) in imx_card_parse_of()
660 plat_data->type = CODEC_AK5552; in imx_card_parse_of()
661 else if (!strcmp(link->codecs->dai_name, "cs42888")) in imx_card_parse_of()
662 plat_data->type = CODEC_CS42888; in imx_card_parse_of()
663 else if (!strcmp(link->codecs->dai_name, "wm8524-hifi")) in imx_card_parse_of()
664 plat_data->type = CODEC_WM8524; in imx_card_parse_of()
667 link->codecs = &snd_soc_dummy_dlc; in imx_card_parse_of()
668 link->num_codecs = 1; in imx_card_parse_of()
671 if (!strncmp(link->name, "HiFi-ASRC-FE", 12)) { in imx_card_parse_of()
673 link->dynamic = 1; in imx_card_parse_of()
674 link->dpcm_merged_chan = 1; in imx_card_parse_of()
676 ret = of_property_read_u32(args.np, "fsl,asrc-rate", &data->asrc_rate); in imx_card_parse_of()
679 ret = -EINVAL; in imx_card_parse_of()
683 ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt); in imx_card_parse_of()
684 data->asrc_format = (__force snd_pcm_format_t)asrc_fmt; in imx_card_parse_of()
687 ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); in imx_card_parse_of()
694 if (width == 24) in imx_card_parse_of()
695 data->asrc_format = SNDRV_PCM_FORMAT_S24_LE; in imx_card_parse_of()
697 data->asrc_format = SNDRV_PCM_FORMAT_S16_LE; in imx_card_parse_of()
699 } else if (!strncmp(link->name, "HiFi-ASRC-BE", 12)) { in imx_card_parse_of()
702 * No need to have link->platforms. alloced dlc[1] will be just wasted, in imx_card_parse_of()
705 link->no_pcm = 1; in imx_card_parse_of()
706 link->platforms = NULL; in imx_card_parse_of()
708 link->be_hw_params_fixup = be_hw_params_fixup; in imx_card_parse_of()
709 link->ops = &imx_aif_ops_be; in imx_card_parse_of()
711 link->ops = &imx_aif_ops; in imx_card_parse_of()
715 link->playback_only = playback_only; in imx_card_parse_of()
716 link->capture_only = capture_only; in imx_card_parse_of()
718 /* Get dai fmt */ in imx_card_parse_of()
720 NULL, &link->dai_fmt); in imx_card_parse_of()
722 link->dai_fmt = SND_SOC_DAIFMT_NB_NF | in imx_card_parse_of()
726 /* Get tdm slot */ in imx_card_parse_of()
728 &link_data->slots, in imx_card_parse_of()
729 &link_data->slot_width); in imx_card_parse_of()
731 if (!link_data->slots) in imx_card_parse_of()
732 link_data->slots = 2; in imx_card_parse_of()
734 if (!link_data->slot_width) in imx_card_parse_of()
735 link_data->slot_width = 32; in imx_card_parse_of()
737 link->ignore_pmdown_time = 1; in imx_card_parse_of()
738 link->stream_name = link->name; in imx_card_parse_of()
767 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); in imx_card_probe()
769 return -ENOMEM; in imx_card_probe()
771 plat_data = devm_kzalloc(&pdev->dev, sizeof(*plat_data), GFP_KERNEL); in imx_card_probe()
773 return -ENOMEM; in imx_card_probe()
775 data->plat_data = plat_data; in imx_card_probe()
776 data->card.dev = &pdev->dev; in imx_card_probe()
777 data->card.owner = THIS_MODULE; in imx_card_probe()
779 dev_set_drvdata(&pdev->dev, &data->card); in imx_card_probe()
780 snd_soc_card_set_drvdata(&data->card, data); in imx_card_probe()
785 data->num_dapm_routes = plat_data->num_codecs + 1; in imx_card_probe()
786 data->dapm_routes = devm_kcalloc(&pdev->dev, data->num_dapm_routes, in imx_card_probe()
789 if (!data->dapm_routes) in imx_card_probe()
790 return -ENOMEM; in imx_card_probe()
793 switch (plat_data->type) { in imx_card_probe()
796 if (plat_data->num_codecs == 1) { in imx_card_probe()
797 data->dapm_routes[0].sink = "Playback"; in imx_card_probe()
798 data->dapm_routes[0].source = "CPU-Playback"; in imx_card_probe()
801 for (i = 0; i < plat_data->num_codecs; i++) { in imx_card_probe()
802 data->dapm_routes[i].sink = in imx_card_probe()
803 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", in imx_card_probe()
805 if (!data->dapm_routes[i].sink) in imx_card_probe()
806 return -ENOMEM; in imx_card_probe()
807 data->dapm_routes[i].source = "CPU-Playback"; in imx_card_probe()
810 data->dapm_routes[i].sink = "CPU-Playback"; in imx_card_probe()
811 data->dapm_routes[i].source = "ASRC-Playback"; in imx_card_probe()
815 if (plat_data->num_codecs == 1) { in imx_card_probe()
816 data->dapm_routes[0].sink = "CPU-Capture"; in imx_card_probe()
817 data->dapm_routes[0].source = "Capture"; in imx_card_probe()
820 for (i = 0; i < plat_data->num_codecs; i++) { in imx_card_probe()
821 data->dapm_routes[i].source = in imx_card_probe()
822 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", in imx_card_probe()
824 if (!data->dapm_routes[i].source) in imx_card_probe()
825 return -ENOMEM; in imx_card_probe()
826 data->dapm_routes[i].sink = "CPU-Capture"; in imx_card_probe()
829 data->dapm_routes[i].sink = "ASRC-Capture"; in imx_card_probe()
830 data->dapm_routes[i].source = "CPU-Capture"; in imx_card_probe()
833 data->dapm_routes[0].sink = "Playback"; in imx_card_probe()
834 data->dapm_routes[0].source = "CPU-Playback"; in imx_card_probe()
835 data->dapm_routes[1].sink = "CPU-Capture"; in imx_card_probe()
836 data->dapm_routes[1].source = "Capture"; in imx_card_probe()
839 data->dapm_routes[0].sink = "Playback"; in imx_card_probe()
840 data->dapm_routes[0].source = "CPU-Playback"; in imx_card_probe()
847 if (codec_is_akcodec(plat_data->type)) { in imx_card_probe()
848 plat_data->support_rates = akcodec_rates; in imx_card_probe()
849 plat_data->num_rates = ARRAY_SIZE(akcodec_rates); in imx_card_probe()
850 plat_data->support_tdm_rates = akcodec_tdm_rates; in imx_card_probe()
851 plat_data->num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates); in imx_card_probe()
853 switch (plat_data->type) { in imx_card_probe()
855 plat_data->fs_mul = ak4458_fs_mul; in imx_card_probe()
856 plat_data->num_fs_mul = ARRAY_SIZE(ak4458_fs_mul); in imx_card_probe()
857 plat_data->tdm_fs_mul = ak4458_tdm_fs_mul; in imx_card_probe()
858 plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak4458_tdm_fs_mul); in imx_card_probe()
859 plat_data->support_channels = ak4458_channels; in imx_card_probe()
860 plat_data->num_channels = ARRAY_SIZE(ak4458_channels); in imx_card_probe()
861 plat_data->support_tdm_channels = ak4458_tdm_channels; in imx_card_probe()
862 plat_data->num_tdm_channels = ARRAY_SIZE(ak4458_tdm_channels); in imx_card_probe()
865 plat_data->fs_mul = ak4497_fs_mul; in imx_card_probe()
866 plat_data->num_fs_mul = ARRAY_SIZE(ak4497_fs_mul); in imx_card_probe()
867 plat_data->support_channels = ak4458_channels; in imx_card_probe()
868 plat_data->num_channels = ARRAY_SIZE(ak4458_channels); in imx_card_probe()
872 plat_data->fs_mul = ak5558_fs_mul; in imx_card_probe()
873 plat_data->num_fs_mul = ARRAY_SIZE(ak5558_fs_mul); in imx_card_probe()
874 plat_data->tdm_fs_mul = ak5558_tdm_fs_mul; in imx_card_probe()
875 plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak5558_tdm_fs_mul); in imx_card_probe()
876 plat_data->support_channels = ak5558_channels; in imx_card_probe()
877 plat_data->num_channels = ARRAY_SIZE(ak5558_channels); in imx_card_probe()
878 plat_data->support_tdm_channels = ak5558_tdm_channels; in imx_card_probe()
879 plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels); in imx_card_probe()
882 plat_data->fs_mul = cs42888_fs_mul; in imx_card_probe()
883 plat_data->num_fs_mul = ARRAY_SIZE(cs42888_fs_mul); in imx_card_probe()
884 plat_data->tdm_fs_mul = cs42888_tdm_fs_mul; in imx_card_probe()
885 plat_data->num_tdm_fs_mul = ARRAY_SIZE(cs42888_tdm_fs_mul); in imx_card_probe()
886 plat_data->support_channels = cs42888_channels; in imx_card_probe()
887 plat_data->num_channels = ARRAY_SIZE(cs42888_channels); in imx_card_probe()
888 plat_data->support_tdm_channels = cs42888_tdm_channels; in imx_card_probe()
889 plat_data->num_tdm_channels = ARRAY_SIZE(cs42888_tdm_channels); in imx_card_probe()
892 plat_data->fs_mul = wm8524_fs_mul; in imx_card_probe()
893 plat_data->num_fs_mul = ARRAY_SIZE(wm8524_fs_mul); in imx_card_probe()
894 plat_data->support_channels = wm8524_channels; in imx_card_probe()
895 plat_data->num_channels = ARRAY_SIZE(wm8524_channels); in imx_card_probe()
903 if (data->card.num_links == 3) { in imx_card_probe()
904 data->card.dapm_routes = data->dapm_routes; in imx_card_probe()
905 data->card.num_dapm_routes = data->num_dapm_routes; in imx_card_probe()
906 for_each_card_prelinks(&data->card, i, link) { in imx_card_probe()
907 if (link->no_pcm == 1) in imx_card_probe()
910 for_each_card_prelinks(&data->card, i, link) { in imx_card_probe()
911 if (link->dynamic == 1 && link_be) { in imx_card_probe()
912 link->playback_only = link_be->playback_only; in imx_card_probe()
913 link->capture_only = link_be->capture_only; in imx_card_probe()
918 ret = devm_snd_soc_register_card(&pdev->dev, &data->card); in imx_card_probe()
920 return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); in imx_card_probe()
926 { .compatible = "fsl,imx-audio-card", },
933 .name = "imx-card",
943 MODULE_ALIAS("platform:imx-card");