diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 5175818ff2c1f8..2c64a45b98993b 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -10,6 +10,7 @@ #include #include #include +#include #include static const struct snd_soc_dapm_widget generic_dmic_widgets[] = { @@ -934,10 +935,10 @@ static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_li return true; } -const char *asoc_sdw_get_codec_name(struct device *dev, - const struct asoc_sdw_codec_info *codec_info, - const struct snd_soc_acpi_link_adr *adr_link, - int adr_index) +static const char *_asoc_sdw_get_codec_name(struct device *dev, + const struct asoc_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index) { u64 adr = adr_link->adr_d[adr_index].adr; unsigned int sdw_version = SDW_VERSION(adr); @@ -947,17 +948,24 @@ const char *asoc_sdw_get_codec_name(struct device *dev, unsigned int part_id = SDW_PART_ID(adr); unsigned int class_id = SDW_CLASS_ID(adr); - if (codec_info->codec_name) - return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); - else if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id, - class_id, adr_index)) + if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id, + class_id, adr_index)) return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", link_id, mfg_id, part_id, class_id); - else - return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", - link_id, mfg_id, part_id, class_id, unique_id); - return NULL; + return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", + link_id, mfg_id, part_id, class_id, unique_id); +} + +const char *asoc_sdw_get_codec_name(struct device *dev, + const struct asoc_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index) +{ + if (codec_info->codec_name) + return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); + + return _asoc_sdw_get_codec_name(dev, codec_info, adr_link, adr_index); } EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS"); @@ -1124,6 +1132,118 @@ struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks } EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS"); +static int asoc_sdw_get_dai_type(u32 type) +{ + switch (type) { + case SDCA_FUNCTION_TYPE_SMART_AMP: + case SDCA_FUNCTION_TYPE_SIMPLE_AMP: + return SOC_SDW_DAI_TYPE_AMP; + case SDCA_FUNCTION_TYPE_SMART_MIC: + case SDCA_FUNCTION_TYPE_SIMPLE_MIC: + case SDCA_FUNCTION_TYPE_SPEAKER_MIC: + return SOC_SDW_DAI_TYPE_MIC; + case SDCA_FUNCTION_TYPE_UAJ: + case SDCA_FUNCTION_TYPE_RJ: + case SDCA_FUNCTION_TYPE_SIMPLE_JACK: + return SOC_SDW_DAI_TYPE_JACK; + default: + return -EINVAL; + } +} + +/** + * Check if the SDCA function is present by the SDW peripheral + * + * @dev: Device pointer + * @codec_info: Codec info pointer + * @adr_link: ACPI link address + * @adr_index: Index of the ACPI link address + * @end_index: Index of the endpoint + * + * Return: 1 if the function is present or no need to check the function, + * 0 if the function is not present, or negative error code. + */ + +static int is_sdca_function_present(struct device *dev, struct asoc_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, int adr_index, + int end_index) +{ + const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index]; + const struct snd_soc_acpi_endpoint *adr_end; + const struct asoc_sdw_dai_info *dai_info; + struct snd_soc_dai_link_component dlc; + struct snd_soc_dai *codec_dai; + struct sdw_slave *slave; + struct device *sdw_dev; + const char *sdw_codec_name; + int i; + + adr_end = &adr_dev->endpoints[end_index]; + dai_info = &codec_info->dais[adr_end->num]; + + if (!SDW_CLASS_ID(adr_dev->adr)) { + dev_dbg(dev, "%#llx: in not a SDCA device\n", adr_dev->adr); + return 1; + } + + /* + * No need to check SDCA functions if there is only 1 endpoint + * present. + */ + if (adr_dev->num_endpoints == 1) { + dev_dbg(dev, "%#llx: Only 1 endpoint with DAI type %d is found\n", + adr_dev->adr, dai_info->dai_type); + return 1; + } + + dlc.dai_name = dai_info->dai_name; + pr_info("bard: start find %s\n", dlc.dai_name); + codec_dai = snd_soc_find_dai_with_mutex(&dlc); + pr_info("bard: end find %s\n", dlc.dai_name); + if (!codec_dai) { + dev_warn(dev, "codec dai %s not registered yet\n", dlc.dai_name); + return -EPROBE_DEFER; + } + + sdw_codec_name = _asoc_sdw_get_codec_name(dev, codec_info, + adr_link, adr_index); + if (!sdw_codec_name) + return -ENOMEM; + + sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); + if (!sdw_dev) { + dev_err(dev, "codec %s not found\n", sdw_codec_name); + return -EINVAL; + } + + slave = dev_to_sdw_dev(sdw_dev); + if (!slave) + return -EINVAL; + + /* Make sure BIOS provides SDCA properties */ + if (!slave->sdca_data.interface_revision) { + dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n"); + return 1; + } + + for (i = 0; i < slave->sdca_data.num_functions; i++) { + int dai_type = asoc_sdw_get_dai_type( + slave->sdca_data.function[i].type); + + if (dai_type == dai_info->dai_type) { + dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n", + dai_type, slave->sdca_data.function[i].name); + return 1; + } + } + + dev_dbg(&slave->dev, + "SDCA device function for DAI type %d not supported, skip endpoint\n", + dai_info->dai_type); + + return 0; +} + int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, @@ -1196,6 +1316,13 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) continue; + ret = is_sdca_function_present(dev, codec_info, adr_link, i, j); + if (ret < 0) + return ret; + + if (!ret) + continue; + dev_dbg(dev, "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n", ffs(adr_link->mask) - 1, adr_dev->adr, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b628e3b5eb83cd..537329bdea25d9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -273,28 +273,56 @@ static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dl static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, struct snd_soc_dai *dai) { + bool trace = false; + + if (dlc && dlc->dai_name && strstr(dlc->dai_name, "rt722")) { + trace = true; + } + + if (trace) + pr_info("bard: %s %d dlc->dai_name %s dai->name %s\n", + __func__, __LINE__, dlc->dai_name, dai->name); + if (!dlc) return 0; + if (trace) + pr_info("bard: %s %d\n", __func__, __LINE__); + if (dlc->dai_args) return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args); + if (trace) + pr_info("bard: %s %d\n", __func__, __LINE__); + if (!dlc->dai_name) return 1; /* see snd_soc_dai_name_get() */ + if (trace) + pr_info("bard: %s %d\n", __func__, __LINE__); + if (dai->driver->name && strcmp(dlc->dai_name, dai->driver->name) == 0) return 1; + if (trace) + pr_info("bard: %s %d\n", __func__, __LINE__); + if (strcmp(dlc->dai_name, dai->name) == 0) return 1; + if (trace) + pr_info("bard: %s %d\n", __func__, __LINE__); + if (dai->component->name && strcmp(dlc->dai_name, dai->component->name) == 0) return 1; + if (trace) + pr_info("bard: %s %d\n", __func__, __LINE__); + return 0; } @@ -850,16 +878,29 @@ static int snd_soc_is_matching_component( struct snd_soc_component *component) { struct device_node *component_of_node; + bool trace = false; + + if (dlc && dlc->dai_name && strstr(dlc->dai_name, "rt722")) { + trace = true; + } + if (trace) + pr_info("bard: %s component %s\n", __func__, component->name); if (!dlc) return 0; + if (trace) + pr_info("bard: %s dlc %s\n", __func__, dlc->name); if (dlc->dai_args) { struct snd_soc_dai *dai; - for_each_component_dais(component, dai) - if (snd_soc_is_matching_dai(dlc, dai)) + for_each_component_dais(component, dai) { + if (trace) + pr_info("bard: %s dai %s\n", __func__, dai->name); + if (snd_soc_is_matching_dai(dlc, dai)) { return 1; + } + } return 0; } @@ -911,15 +952,29 @@ struct snd_soc_dai *snd_soc_find_dai( { struct snd_soc_component *component; struct snd_soc_dai *dai; + bool trace = false; + if (dlc && dlc->dai_name && strstr(dlc->dai_name, "rt722")) { + trace = true; + } lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs */ - for_each_component(component) - if (snd_soc_is_matching_component(dlc, component)) - for_each_component_dais(component, dai) - if (snd_soc_is_matching_dai(dlc, dai)) + for_each_component(component) { + if (trace) + pr_info("bard: %s component %s\n", __func__, component->name); + if (snd_soc_is_matching_component(dlc, component)) { + for_each_component_dais(component, dai) { + if (trace) + pr_info("bard: %s dai %s\n", __func__, dai->name); + if (snd_soc_is_matching_dai(dlc, dai)) { + if (trace) + pr_info("bard: %s found %s\n", __func__, dai->name); return dai; + } + } + } + } return NULL; } @@ -930,6 +985,7 @@ struct snd_soc_dai *snd_soc_find_dai_with_mutex( { struct snd_soc_dai *dai; + pr_info("bard: %s\n", __func__); mutex_lock(&client_mutex); dai = snd_soc_find_dai(dlc); mutex_unlock(&client_mutex);