Lines Matching +full:dai +full:- +full:link
1 // SPDX-License-Identifier: GPL-2.0-only
5 * sof_sdw - ASOC Machine driver for Intel SoundWire platforms
14 #include <sound/soc-acpi.h>
18 static int quirk_override = -1;
20 MODULE_PARM_DESC(quirk, "Board-specific quirk override");
22 #define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0) argument
27 dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", in log_quirks()
46 sof_sdw_quirk = (unsigned long)id->driver_data; in sof_sdw_quirk_cb()
150 .name = "dmic-codec",
151 .dai_name = "dmic-hifi",
172 struct snd_soc_dai *dai; in sdw_prepare() local
174 /* Find stream from first CPU DAI */ in sdw_prepare()
175 dai = asoc_rtd_to_cpu(rtd, 0); in sdw_prepare()
177 sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); in sdw_prepare()
180 dev_err(rtd->dev, "no stream found for DAI %s", dai->name); in sdw_prepare()
191 struct snd_soc_dai *dai; in sdw_trigger() local
194 /* Find stream from first CPU DAI */ in sdw_trigger()
195 dai = asoc_rtd_to_cpu(rtd, 0); in sdw_trigger()
197 sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); in sdw_trigger()
200 dev_err(rtd->dev, "no stream found for DAI %s", dai->name); in sdw_trigger()
217 ret = -EINVAL; in sdw_trigger()
222 dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret); in sdw_trigger()
231 struct snd_soc_dai *dai; in sdw_hw_free() local
233 /* Find stream from first CPU DAI */ in sdw_hw_free()
234 dai = asoc_rtd_to_cpu(rtd, 0); in sdw_hw_free()
236 sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); in sdw_hw_free()
239 dev_err(rtd->dev, "no stream found for DAI %s", dai->name); in sdw_hw_free()
263 .dai_name = "rt700-aif1",
270 .dai_name = "rt711-sdca-aif1",
278 .dai_name = "rt711-aif1",
286 .dai_name = "rt1308-aif",
293 .dai_name = "rt1316-aif",
300 .dai_name = "rt715-aif2",
307 .dai_name = "rt715-aif2",
314 .dai_name = "rt715-aif2",
321 .dai_name = "rt715-aif2",
327 .dai_name = "max98373-aif1",
334 .dai_name = "rt5682-sdw",
356 return -EINVAL; in find_codec_info_part()
365 return -EINVAL; in find_codec_info_acpi()
373 return -EINVAL; in find_codec_info_acpi()
379 * get BE dailink number and CPU DAI number based on sdw link adr.
380 * Since some sdw slaves may be aggregated, the CPU DAI number
386 const struct snd_soc_acpi_link_adr *link; in get_sdw_dailink_info() local
396 return -EINVAL; in get_sdw_dailink_info()
401 for (link = links; link->num_adr; link++) { in get_sdw_dailink_info()
407 adr = link->adr_d->adr; in get_sdw_dailink_info()
412 endpoint = link->adr_d->endpoints; in get_sdw_dailink_info()
414 /* count DAI number for playback and capture */ in get_sdw_dailink_info()
421 /* count BE for each non-aggregated slave or group */ in get_sdw_dailink_info()
422 if (!endpoint->aggregated || no_aggregation || in get_sdw_dailink_info()
423 !group_visited[endpoint->group_id]) in get_sdw_dailink_info()
427 if (endpoint->aggregated) in get_sdw_dailink_info()
428 group_visited[endpoint->group_id] = true; in get_sdw_dailink_info()
443 dai_links->id = be_id; in init_dai_link()
444 dai_links->name = name; in init_dai_link()
445 dai_links->platforms = platform_component; in init_dai_link()
446 dai_links->num_platforms = ARRAY_SIZE(platform_component); in init_dai_link()
447 dai_links->nonatomic = true; in init_dai_link()
448 dai_links->no_pcm = 1; in init_dai_link()
449 dai_links->cpus = cpus; in init_dai_link()
450 dai_links->num_cpus = cpus_num; in init_dai_link()
451 dai_links->codecs = codecs; in init_dai_link()
452 dai_links->num_codecs = codecs_num; in init_dai_link()
453 dai_links->dpcm_playback = playback; in init_dai_link()
454 dai_links->dpcm_capture = capture; in init_dai_link()
455 dai_links->init = init; in init_dai_link()
456 dai_links->ops = ops; in init_dai_link()
459 static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, in is_unique_device() argument
469 for (i = 0; i < link->num_adr; i++) { in is_unique_device()
477 adr = link->adr_d[i].adr; in is_unique_device()
495 const struct snd_soc_acpi_link_adr *link, in create_codec_dai_name() argument
505 if (*codec_conf_index + link->num_adr > codec_count) { in create_codec_dai_name()
506 dev_err(dev, "codec_conf: out-of-bounds access requested\n"); in create_codec_dai_name()
507 return -EINVAL; in create_codec_dai_name()
510 for (i = 0; i < link->num_adr; i++) { in create_codec_dai_name()
517 adr = link->adr_d[i].adr; in create_codec_dai_name()
527 if (is_unique_device(link, sdw_version, mfg_id, part_id, in create_codec_dai_name()
543 return -ENOMEM; in create_codec_dai_name()
553 codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix; in create_codec_dai_name()
561 static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link, in set_codec_init_func() argument
573 for (i = 0; i < link->num_adr; i++) { in set_codec_init_func()
576 codec_index = find_codec_info_part(link->adr_d[i].adr); in set_codec_init_func()
581 if (link->adr_d[i].endpoints->group_id != group_id) in set_codec_init_func()
584 codec_info_list[codec_index].init(link, in set_codec_init_func()
589 link++; in set_codec_init_func()
590 } while (link->mask && group_id); in set_codec_init_func()
596 * check endpoint status in slaves and gather link ID for all slaves in
597 * the same group to generate different CPU DAI. Now only support
598 * one sdw link with all slaves set with only single group id.
600 * one slave on one sdw link with aggregated = 0
601 * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI
603 * two or more slaves on one sdw link with aggregated = 0
604 * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs
607 * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs
620 *codec_num = adr_link->num_adr; in get_slave_info()
621 adr_d = adr_link->adr_d; in get_slave_info()
623 /* make sure the link mask has a single bit set */ in get_slave_info()
624 if (!is_power_of_2(adr_link->mask)) in get_slave_info()
625 return -EINVAL; in get_slave_info()
627 cpu_dai_id[index++] = ffs(adr_link->mask) - 1; in get_slave_info()
628 if (!adr_d->endpoints->aggregated || no_aggregation) { in get_slave_info()
634 *group_id = adr_d->endpoints->group_id; in get_slave_info()
636 /* gather other link ID of slaves in the same group */ in get_slave_info()
637 for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; in get_slave_info()
641 endpoint = adr_next->adr_d->endpoints; in get_slave_info()
642 if (!endpoint->aggregated || in get_slave_info()
643 endpoint->group_id != *group_id) in get_slave_info()
646 /* make sure the link mask has a single bit set */ in get_slave_info()
647 if (!is_power_of_2(adr_next->mask)) in get_slave_info()
648 return -EINVAL; in get_slave_info()
652 return -EINVAL; in get_slave_info()
655 cpu_dai_id[index++] = ffs(adr_next->mask) - 1; in get_slave_info()
656 *codec_num += adr_next->num_adr; in get_slave_info()
673 const struct snd_soc_acpi_link_adr *link, in create_sdw_dailink() argument
692 ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, in create_sdw_dailink()
699 return -ENOMEM; in create_sdw_dailink()
702 for (link_next = link; link_next && link_next->num_adr && in create_sdw_dailink()
706 endpoints = link_next->adr_d->endpoints; in create_sdw_dailink()
707 if (group_id && (!endpoints->aggregated || in create_sdw_dailink()
708 endpoints->group_id != group_id)) in create_sdw_dailink()
711 /* skip the link excluded by this processed group */ in create_sdw_dailink()
712 if (cpu_dai_id[i] != ffs(link_next->mask) - 1) in create_sdw_dailink()
720 /* check next link to create codec dai in the processed group */ in create_sdw_dailink()
722 codec_idx += link_next->num_adr; in create_sdw_dailink()
725 /* find codec info to create BE DAI */ in create_sdw_dailink()
726 codec_index = find_codec_info_part(link->adr_d[0].adr); in create_sdw_dailink()
735 "SDW%d-Playback", in create_sdw_dailink()
736 "SDW%d-Capture", in create_sdw_dailink()
742 /* create stream name according to first link id */ in create_sdw_dailink()
746 return -ENOMEM; in create_sdw_dailink()
749 * generate CPU DAI name base on the sdw link ID and in create_sdw_dailink()
750 * PIN ID with offset of 2 according to sdw dai driver. in create_sdw_dailink()
757 return -ENOMEM; in create_sdw_dailink()
760 dev_err(dev, "invalid cpu dai index %d", in create_sdw_dailink()
762 return -EINVAL; in create_sdw_dailink()
769 dev_err(dev, " invalid be dai index %d", *be_index); in create_sdw_dailink()
770 return -EINVAL; in create_sdw_dailink()
774 dev_err(dev, " invalid cpu dai index %d", *cpu_id); in create_sdw_dailink()
775 return -EINVAL; in create_sdw_dailink()
786 ret = set_codec_init_func(link, dai_links + (*be_index)++, in create_sdw_dailink()
801 * DAI link ID of SSP & DMIC & HDMI are based on last
802 * link ID used by sdw link. Since be_id may be changed
808 return links[be_id - 1].id + 1; in get_next_be_id()
823 adr_link = mach_params->links; in sof_card_codec_conf_alloc()
825 return -EINVAL; in sof_card_codec_conf_alloc()
827 /* generate DAI links by each sdw link */ in sof_card_codec_conf_alloc()
828 for (; adr_link->num_adr; adr_link++) { in sof_card_codec_conf_alloc()
829 for (i = 0; i < adr_link->num_adr; i++) { in sof_card_codec_conf_alloc()
830 if (!adr_link->adr_d[i].name_prefix) { in sof_card_codec_conf_alloc()
832 adr_link->adr_d[i].adr); in sof_card_codec_conf_alloc()
833 return -EINVAL; in sof_card_codec_conf_alloc()
836 num_codecs += adr_link->num_adr; in sof_card_codec_conf_alloc()
841 return -ENOMEM; in sof_card_codec_conf_alloc()
875 mach_params = &mach->mach_params; in sof_card_dai_links_create()
898 ssp_codec_index = find_codec_info_acpi(mach->id); in sof_card_dai_links_create()
902 ret = get_sdw_dailink_info(mach_params->links, in sof_card_dai_links_create()
905 dev_err(dev, "failed to get sdw link info %d", ret); in sof_card_dai_links_create()
909 if (mach_params->codec_mask & IDISP_CODEC_MASK) in sof_card_dai_links_create()
910 ctx->idisp_codec = true; in sof_card_dai_links_create()
917 dmic_num, ctx->idisp_codec ? hdmi_num : 0); in sof_card_dai_links_create()
929 return -ENOMEM; in sof_card_dai_links_create()
935 adr_link = mach_params->links; in sof_card_dai_links_create()
937 return -EINVAL; in sof_card_dai_links_create()
947 /* generate DAI links by each sdw link */ in sof_card_dai_links_create()
948 for (; adr_link->num_adr; adr_link++) { in sof_card_dai_links_create()
951 endpoint = adr_link->adr_d->endpoints; in sof_card_dai_links_create()
952 if (endpoint->aggregated && !endpoint->group_id) { in sof_card_dai_links_create()
953 dev_err(dev, "invalid group id on link %x", in sof_card_dai_links_create()
954 adr_link->mask); in sof_card_dai_links_create()
959 if (endpoint->aggregated && in sof_card_dai_links_create()
960 group_generated[endpoint->group_id]) in sof_card_dai_links_create()
969 dev_err(dev, "failed to create dai link %d", be_id); in sof_card_dai_links_create()
970 return -ENOMEM; in sof_card_dai_links_create()
974 /* non-sdw DAI follows sdw DAI */ in sof_card_dai_links_create()
977 /* get BE ID for non-sdw DAI */ in sof_card_dai_links_create()
994 "SSP%d-Codec", i); in sof_card_dai_links_create()
996 return -ENOMEM; in sof_card_dai_links_create()
1000 return -ENOMEM; in sof_card_dai_links_create()
1005 return -ENOMEM; in sof_card_dai_links_create()
1008 codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", in sof_card_dai_links_create()
1009 info->acpi_id, j++); in sof_card_dai_links_create()
1011 return -ENOMEM; in sof_card_dai_links_create()
1013 ssp_components->name = codec_name; in sof_card_dai_links_create()
1014 ssp_components->dai_name = info->dai_name; in sof_card_dai_links_create()
1017 playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK]; in sof_card_dai_links_create()
1018 capture = info->direction[SNDRV_PCM_STREAM_CAPTURE]; in sof_card_dai_links_create()
1023 NULL, info->ops); in sof_card_dai_links_create()
1025 ret = info->init(NULL, links + link_id, info, 0); in sof_card_dai_links_create()
1059 return -ENOMEM; in sof_card_dai_links_create()
1066 return -ENOMEM; in sof_card_dai_links_create()
1068 if (ctx->idisp_codec) { in sof_card_dai_links_create()
1072 "intel-hdmi-hifi%d", in sof_card_dai_links_create()
1075 return -ENOMEM; in sof_card_dai_links_create()
1077 idisp_components[i].name = "snd-soc-dummy"; in sof_card_dai_links_create()
1078 idisp_components[i].dai_name = "snd-soc-dummy-dai"; in sof_card_dai_links_create()
1084 return -ENOMEM; in sof_card_dai_links_create()
1095 card->dai_link = links; in sof_card_dai_links_create()
1096 card->num_links = num_links; in sof_card_dai_links_create()
1098 card->codec_conf = codec_conf; in sof_card_dai_links_create()
1099 card->num_configs = codec_conf_count; in sof_card_dai_links_create()
1137 dev_dbg(&pdev->dev, "Entry %s\n", __func__); in mc_probe()
1139 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); in mc_probe()
1141 return -ENOMEM; in mc_probe()
1145 if (quirk_override != -1) { in mc_probe()
1146 dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", in mc_probe()
1150 log_quirks(&pdev->dev); in mc_probe()
1152 INIT_LIST_HEAD(&ctx->hdmi_pcm_list); in mc_probe()
1154 card->dev = &pdev->dev; in mc_probe()
1157 mach = pdev->dev.platform_data; in mc_probe()
1158 ret = sof_card_dai_links_create(&pdev->dev, mach, in mc_probe()
1163 ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; in mc_probe()
1173 card->components = devm_kasprintf(card->dev, GFP_KERNEL, in mc_probe()
1174 "cfg-spk:%d cfg-amp:%d", in mc_probe()
1177 if (!card->components) in mc_probe()
1178 return -ENOMEM; in mc_probe()
1180 card->long_name = sdw_card_long_name; in mc_probe()
1183 ret = devm_snd_soc_register_card(&pdev->dev, card); in mc_probe()
1185 dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); in mc_probe()
1197 struct snd_soc_dai_link *link; in mc_remove() local
1206 * dai link found. in mc_remove()
1208 for_each_card_prelinks(card, j, link) { in mc_remove()
1209 if (!strcmp(link->codecs[0].dai_name, in mc_remove()
1211 ret = codec_info_list[i].exit(&pdev->dev, link); in mc_remove()
1213 dev_warn(&pdev->dev, in mc_remove()
1236 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1238 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");