Lines Matching +full:fe +full:- +full:dai +full:- +full:link
1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2017-2021 NXP
14 #include <sound/soc-dapm.h>
55 * struct imx_card_plat_data - specific info for codecs
89 * struct dai_link_data - specific info for dai link
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
154 * Table 7 - mapping multiplier and speed mode
155 * Tables 8 & 9 - mapping speed mode and LRCK fs
250 if (link_data->slots > 2) in format_is_tdm()
276 struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card); in akcodec_get_mclk_rate()
277 const struct imx_card_plat_data *plat_data = data->plat_data; in akcodec_get_mclk_rate()
278 struct dai_link_data *link_data = &data->link_data[rtd->id]; in akcodec_get_mclk_rate()
284 for (i = 0; i < plat_data->num_tdm_fs_mul; i++) { in akcodec_get_mclk_rate()
286 if (width != plat_data->tdm_fs_mul[i].min) in akcodec_get_mclk_rate()
288 return rate * plat_data->tdm_fs_mul[i].mul; in akcodec_get_mclk_rate()
291 for (i = 0; i < plat_data->num_fs_mul; i++) { in akcodec_get_mclk_rate()
292 if (rate >= plat_data->fs_mul[i].rmin && in akcodec_get_mclk_rate()
293 rate <= plat_data->fs_mul[i].rmax) { in akcodec_get_mclk_rate()
294 width = max(width, plat_data->fs_mul[i].wmin); in akcodec_get_mclk_rate()
295 width = min(width, plat_data->fs_mul[i].wmax); in akcodec_get_mclk_rate()
298 width *= link_data->one2one_ratio ? 1 : 2; in akcodec_get_mclk_rate()
305 /* Let DAI manage clk frequency by default */ in akcodec_get_mclk_rate()
314 struct snd_soc_card *card = rtd->card; in imx_aif_hw_params()
316 struct dai_link_data *link_data = &data->link_data[rtd->id]; in imx_aif_hw_params()
317 struct imx_card_plat_data *plat_data = data->plat_data; in imx_aif_hw_params()
318 struct device *dev = card->dev; in imx_aif_hw_params()
321 unsigned int fmt = rtd->dai_link->dai_fmt; in imx_aif_hw_params()
325 slots = link_data->slots; in imx_aif_hw_params()
326 slot_width = link_data->slot_width; in imx_aif_hw_params()
332 fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | in imx_aif_hw_params()
337 fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | in imx_aif_hw_params()
343 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
344 dev_err(dev, "failed to set cpu dai fmt: %d\n", ret); in imx_aif_hw_params()
348 BIT(slots) - 1, in imx_aif_hw_params()
349 BIT(slots) - 1, in imx_aif_hw_params()
351 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
352 dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret); in imx_aif_hw_params()
358 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
359 dev_err(dev, "failed to set codec dai[%d] fmt: %d\n", i, ret); in imx_aif_hw_params()
365 BIT(slots) - 1, in imx_aif_hw_params()
366 BIT(slots) - 1, in imx_aif_hw_params()
368 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
369 dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); in imx_aif_hw_params()
376 if (codec_is_akcodec(plat_data->type)) in imx_aif_hw_params()
389 ret = snd_soc_dai_set_sysclk(cpu_dai, link_data->cpu_sysclk_id, mclk_freq, in imx_aif_hw_params()
391 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
392 dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret); in imx_aif_hw_params()
396 if (ret && ret != -ENOTSUPP) { in imx_aif_hw_params()
397 dev_err(dev, "failed to set codec dai mclk rate (%lu): %d\n", mclk_freq, ret); in imx_aif_hw_params()
406 struct dai_link_data *link_data = r->private; in ak5558_hw_rule_rate()
412 fs = hw_param_interval(p, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; in ak5558_hw_rule_rate()
413 fs *= link_data->slots; in ak5558_hw_rule_rate()
419 mclk_freq *= link_data->one2one_ratio ? 1 : 2; in ak5558_hw_rule_rate()
429 return snd_interval_refine(hw_param_interval(p, r->var), &t); in ak5558_hw_rule_rate()
434 struct snd_pcm_runtime *runtime = substream->runtime; in imx_aif_startup()
436 struct snd_soc_card *card = rtd->card; in imx_aif_startup()
438 struct dai_link_data *link_data = &data->link_data[rtd->id]; in imx_aif_startup()
444 constraint_channels.list = data->plat_data->support_tdm_channels; in imx_aif_startup()
445 constraint_channels.count = data->plat_data->num_tdm_channels; in imx_aif_startup()
446 constraint_rates.list = data->plat_data->support_tdm_rates; in imx_aif_startup()
447 constraint_rates.count = data->plat_data->num_tdm_rates; in imx_aif_startup()
449 constraint_channels.list = data->plat_data->support_channels; in imx_aif_startup()
450 constraint_channels.count = data->plat_data->num_channels; in imx_aif_startup()
451 constraint_rates.list = data->plat_data->support_rates; in imx_aif_startup()
452 constraint_rates.count = data->plat_data->num_rates; in imx_aif_startup()
471 if (data->plat_data->type == CODEC_AK5558) in imx_aif_startup()
472 ret = snd_pcm_hw_rule_add(substream->runtime, 0, in imx_aif_startup()
475 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); in imx_aif_startup()
492 struct snd_soc_card *card = rtd->card; in be_hw_params_fixup()
498 rate->max = data->asrc_rate; in be_hw_params_fixup()
499 rate->min = data->asrc_rate; in be_hw_params_fixup()
503 snd_mask_set(mask, (__force unsigned int)data->asrc_format); in be_hw_params_fixup()
510 struct imx_card_plat_data *plat_data = data->plat_data; in imx_card_parse_of()
511 struct snd_soc_card *card = &data->card; in imx_card_parse_of()
517 struct device *dev = card->dev; in imx_card_parse_of()
518 struct snd_soc_dai_link *link; in imx_card_parse_of() local
532 if (of_property_read_bool(dev->of_node, "audio-routing")) { in imx_card_parse_of()
533 ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); in imx_card_parse_of()
539 num_links = of_get_child_count(dev->of_node); in imx_card_parse_of()
541 /* Allocate the DAI link array */ in imx_card_parse_of()
542 card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); in imx_card_parse_of()
543 if (!card->dai_link) in imx_card_parse_of()
544 return -ENOMEM; in imx_card_parse_of()
546 data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); in imx_card_parse_of()
547 if (!data->link_data) in imx_card_parse_of()
548 return -ENOMEM; in imx_card_parse_of()
550 card->num_links = num_links; in imx_card_parse_of()
551 link = card->dai_link; in imx_card_parse_of()
552 link_data = data->link_data; in imx_card_parse_of()
554 for_each_child_of_node(dev->of_node, np) { in imx_card_parse_of()
557 ret = -ENOMEM; in imx_card_parse_of()
561 link->cpus = &dlc[0]; in imx_card_parse_of()
562 link->platforms = &dlc[1]; in imx_card_parse_of()
564 link->num_cpus = 1; in imx_card_parse_of()
565 link->num_platforms = 1; in imx_card_parse_of()
567 ret = of_property_read_string(np, "link-name", &link->name); in imx_card_parse_of()
569 dev_err(card->dev, "error getting codec dai_link name\n"); in imx_card_parse_of()
575 dev_err(dev, "%s: Can't find cpu DT node\n", link->name); in imx_card_parse_of()
576 ret = -EINVAL; in imx_card_parse_of()
580 ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); in imx_card_parse_of()
582 dev_err_probe(card->dev, ret, in imx_card_parse_of()
583 "%s: error getting cpu dai info\n", link->name); in imx_card_parse_of()
589 link_data->cpu_sysclk_id = FSL_SAI_CLK_MAST1; in imx_card_parse_of()
592 if (of_property_read_bool(np, "fsl,mclk-equal-bclk")) { in imx_card_parse_of()
593 link_data->one2one_ratio = true; in imx_card_parse_of()
611 link->platforms->of_node = link->cpus->of_node; in imx_card_parse_of()
612 link->id = args.args[0]; in imx_card_parse_of()
616 ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); in imx_card_parse_of()
618 dev_err_probe(dev, ret, "%s: codec dai not found\n", in imx_card_parse_of()
619 link->name); in imx_card_parse_of()
623 plat_data->num_codecs = link->num_codecs; in imx_card_parse_of()
626 if (!strcmp(link->codecs->dai_name, "ak4458-aif")) in imx_card_parse_of()
627 plat_data->type = CODEC_AK4458; in imx_card_parse_of()
628 else if (!strcmp(link->codecs->dai_name, "ak4497-aif")) in imx_card_parse_of()
629 plat_data->type = CODEC_AK4497; in imx_card_parse_of()
630 else if (!strcmp(link->codecs->dai_name, "ak5558-aif")) in imx_card_parse_of()
631 plat_data->type = CODEC_AK5558; in imx_card_parse_of()
632 else if (!strcmp(link->codecs->dai_name, "ak5552-aif")) in imx_card_parse_of()
633 plat_data->type = CODEC_AK5552; in imx_card_parse_of()
634 else if (!strcmp(link->codecs->dai_name, "cs42888")) in imx_card_parse_of()
635 plat_data->type = CODEC_CS42888; in imx_card_parse_of()
638 link->codecs = &snd_soc_dummy_dlc; in imx_card_parse_of()
639 link->num_codecs = 1; in imx_card_parse_of()
642 if (!strncmp(link->name, "HiFi-ASRC-FE", 12)) { in imx_card_parse_of()
644 link->dynamic = 1; in imx_card_parse_of()
645 link->dpcm_merged_chan = 1; in imx_card_parse_of()
647 ret = of_property_read_u32(args.np, "fsl,asrc-rate", &data->asrc_rate); in imx_card_parse_of()
650 ret = -EINVAL; in imx_card_parse_of()
654 ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt); in imx_card_parse_of()
655 data->asrc_format = (__force snd_pcm_format_t)asrc_fmt; in imx_card_parse_of()
658 ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); in imx_card_parse_of()
666 data->asrc_format = SNDRV_PCM_FORMAT_S24_LE; in imx_card_parse_of()
668 data->asrc_format = SNDRV_PCM_FORMAT_S16_LE; in imx_card_parse_of()
670 } else if (!strncmp(link->name, "HiFi-ASRC-BE", 12)) { in imx_card_parse_of()
672 link->no_pcm = 1; in imx_card_parse_of()
673 link->platforms->of_node = NULL; in imx_card_parse_of()
674 link->platforms->name = "snd-soc-dummy"; in imx_card_parse_of()
676 link->be_hw_params_fixup = be_hw_params_fixup; in imx_card_parse_of()
677 link->ops = &imx_aif_ops_be; in imx_card_parse_of()
679 link->ops = &imx_aif_ops; in imx_card_parse_of()
682 /* Get dai fmt */ in imx_card_parse_of()
684 NULL, &link->dai_fmt); in imx_card_parse_of()
686 link->dai_fmt = SND_SOC_DAIFMT_NB_NF | in imx_card_parse_of()
692 &link_data->slots, in imx_card_parse_of()
693 &link_data->slot_width); in imx_card_parse_of()
695 if (!link_data->slots) in imx_card_parse_of()
696 link_data->slots = 2; in imx_card_parse_of()
698 if (!link_data->slot_width) in imx_card_parse_of()
699 link_data->slot_width = 32; in imx_card_parse_of()
701 link->ignore_pmdown_time = 1; in imx_card_parse_of()
702 link->stream_name = link->name; in imx_card_parse_of()
703 link++; in imx_card_parse_of()
727 struct snd_soc_dai_link *link_be = NULL, *link; in imx_card_probe() local
732 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); in imx_card_probe()
734 return -ENOMEM; in imx_card_probe()
736 plat_data = devm_kzalloc(&pdev->dev, sizeof(*plat_data), GFP_KERNEL); in imx_card_probe()
738 return -ENOMEM; in imx_card_probe()
740 data->plat_data = plat_data; in imx_card_probe()
741 data->card.dev = &pdev->dev; in imx_card_probe()
742 data->card.owner = THIS_MODULE; in imx_card_probe()
744 dev_set_drvdata(&pdev->dev, &data->card); in imx_card_probe()
745 snd_soc_card_set_drvdata(&data->card, data); in imx_card_probe()
750 data->num_dapm_routes = plat_data->num_codecs + 1; in imx_card_probe()
751 data->dapm_routes = devm_kcalloc(&pdev->dev, data->num_dapm_routes, in imx_card_probe()
754 if (!data->dapm_routes) in imx_card_probe()
755 return -ENOMEM; in imx_card_probe()
758 switch (plat_data->type) { in imx_card_probe()
761 if (plat_data->num_codecs == 1) { in imx_card_probe()
762 data->dapm_routes[0].sink = "Playback"; in imx_card_probe()
763 data->dapm_routes[0].source = "CPU-Playback"; in imx_card_probe()
766 for (i = 0; i < plat_data->num_codecs; i++) { in imx_card_probe()
767 data->dapm_routes[i].sink = in imx_card_probe()
768 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", in imx_card_probe()
770 data->dapm_routes[i].source = "CPU-Playback"; in imx_card_probe()
773 data->dapm_routes[i].sink = "CPU-Playback"; in imx_card_probe()
774 data->dapm_routes[i].source = "ASRC-Playback"; in imx_card_probe()
778 if (plat_data->num_codecs == 1) { in imx_card_probe()
779 data->dapm_routes[0].sink = "CPU-Capture"; in imx_card_probe()
780 data->dapm_routes[0].source = "Capture"; in imx_card_probe()
783 for (i = 0; i < plat_data->num_codecs; i++) { in imx_card_probe()
784 data->dapm_routes[i].source = in imx_card_probe()
785 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", in imx_card_probe()
787 data->dapm_routes[i].sink = "CPU-Capture"; in imx_card_probe()
790 data->dapm_routes[i].sink = "ASRC-Capture"; in imx_card_probe()
791 data->dapm_routes[i].source = "CPU-Capture"; in imx_card_probe()
794 data->dapm_routes[0].sink = "Playback"; in imx_card_probe()
795 data->dapm_routes[0].source = "CPU-Playback"; in imx_card_probe()
796 data->dapm_routes[1].sink = "CPU-Capture"; in imx_card_probe()
797 data->dapm_routes[1].source = "Capture"; in imx_card_probe()
804 if (codec_is_akcodec(plat_data->type)) { in imx_card_probe()
805 plat_data->support_rates = akcodec_rates; in imx_card_probe()
806 plat_data->num_rates = ARRAY_SIZE(akcodec_rates); in imx_card_probe()
807 plat_data->support_tdm_rates = akcodec_tdm_rates; in imx_card_probe()
808 plat_data->num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates); in imx_card_probe()
810 switch (plat_data->type) { in imx_card_probe()
812 plat_data->fs_mul = ak4458_fs_mul; in imx_card_probe()
813 plat_data->num_fs_mul = ARRAY_SIZE(ak4458_fs_mul); in imx_card_probe()
814 plat_data->tdm_fs_mul = ak4458_tdm_fs_mul; in imx_card_probe()
815 plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak4458_tdm_fs_mul); in imx_card_probe()
816 plat_data->support_channels = ak4458_channels; in imx_card_probe()
817 plat_data->num_channels = ARRAY_SIZE(ak4458_channels); in imx_card_probe()
818 plat_data->support_tdm_channels = ak4458_tdm_channels; in imx_card_probe()
819 plat_data->num_tdm_channels = ARRAY_SIZE(ak4458_tdm_channels); in imx_card_probe()
822 plat_data->fs_mul = ak4497_fs_mul; in imx_card_probe()
823 plat_data->num_fs_mul = ARRAY_SIZE(ak4497_fs_mul); in imx_card_probe()
824 plat_data->support_channels = ak4458_channels; in imx_card_probe()
825 plat_data->num_channels = ARRAY_SIZE(ak4458_channels); in imx_card_probe()
829 plat_data->fs_mul = ak5558_fs_mul; in imx_card_probe()
830 plat_data->num_fs_mul = ARRAY_SIZE(ak5558_fs_mul); in imx_card_probe()
831 plat_data->tdm_fs_mul = ak5558_tdm_fs_mul; in imx_card_probe()
832 plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak5558_tdm_fs_mul); in imx_card_probe()
833 plat_data->support_channels = ak5558_channels; in imx_card_probe()
834 plat_data->num_channels = ARRAY_SIZE(ak5558_channels); in imx_card_probe()
835 plat_data->support_tdm_channels = ak5558_tdm_channels; in imx_card_probe()
836 plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels); in imx_card_probe()
839 plat_data->fs_mul = cs42888_fs_mul; in imx_card_probe()
840 plat_data->num_fs_mul = ARRAY_SIZE(cs42888_fs_mul); in imx_card_probe()
841 plat_data->tdm_fs_mul = cs42888_tdm_fs_mul; in imx_card_probe()
842 plat_data->num_tdm_fs_mul = ARRAY_SIZE(cs42888_tdm_fs_mul); in imx_card_probe()
843 plat_data->support_channels = cs42888_channels; in imx_card_probe()
844 plat_data->num_channels = ARRAY_SIZE(cs42888_channels); in imx_card_probe()
845 plat_data->support_tdm_channels = cs42888_tdm_channels; in imx_card_probe()
846 plat_data->num_tdm_channels = ARRAY_SIZE(cs42888_tdm_channels); in imx_card_probe()
854 if (data->card.num_links == 3) { in imx_card_probe()
855 data->card.dapm_routes = data->dapm_routes; in imx_card_probe()
856 data->card.num_dapm_routes = data->num_dapm_routes; in imx_card_probe()
857 for_each_card_prelinks(&data->card, i, link) { in imx_card_probe()
858 if (link->no_pcm == 1) in imx_card_probe()
859 link_be = link; in imx_card_probe()
861 for_each_card_prelinks(&data->card, i, link) { in imx_card_probe()
862 if (link->dynamic == 1 && link_be) { in imx_card_probe()
863 link->playback_only = link_be->playback_only; in imx_card_probe()
864 link->capture_only = link_be->capture_only; in imx_card_probe()
869 ret = devm_snd_soc_register_card(&pdev->dev, &data->card); in imx_card_probe()
871 return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); in imx_card_probe()
877 { .compatible = "fsl,imx-audio-card", },
884 .name = "imx-card",
894 MODULE_ALIAS("platform:imx-card");