mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-28 18:10:32 +00:00
ASoC: soc_sdw_utils: skip the endpoint that doesn't present
A codec endpoint may not be used. We could check the present SDCA functions to know if the endpoint is used or not. Skip the endpoint which is not used. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Link: https://patch.msgid.link/20250414063239.85200-12-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
6d893cfb3d
commit
4f8ef33dd4
@ -10,6 +10,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include <sound/sdca_function.h>
|
||||
#include <sound/soc_sdw_utils.h>
|
||||
|
||||
static const struct snd_soc_dapm_widget generic_dmic_widgets[] = {
|
||||
@ -1131,6 +1132,106 @@ 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 endpoint 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 endpoint is present,
|
||||
* 0 if the endpoint is not present,
|
||||
* negative error code.
|
||||
*/
|
||||
|
||||
static int is_sdca_endpoint_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;
|
||||
|
||||
dlc = kzalloc(sizeof(*dlc), GFP_KERNEL);
|
||||
|
||||
adr_end = &adr_dev->endpoints[end_index];
|
||||
dai_info = &codec_info->dais[adr_end->num];
|
||||
|
||||
dlc->dai_name = dai_info->dai_name;
|
||||
codec_dai = snd_soc_find_dai_with_mutex(dlc);
|
||||
if (!codec_dai) {
|
||||
dev_warn(dev, "codec dai %s not registered yet\n", dlc->dai_name);
|
||||
kfree(dlc);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
kfree(dlc);
|
||||
|
||||
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,
|
||||
@ -1159,6 +1260,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
|
||||
const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
|
||||
struct asoc_sdw_codec_info *codec_info;
|
||||
const char *codec_name;
|
||||
bool check_sdca = false;
|
||||
|
||||
if (!adr_dev->name_prefix) {
|
||||
dev_err(dev, "codec 0x%llx does not have a name prefix\n",
|
||||
@ -1189,6 +1291,9 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
|
||||
soc_end->include_sidecar = true;
|
||||
}
|
||||
|
||||
if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1)
|
||||
check_sdca = true;
|
||||
|
||||
for (j = 0; j < adr_dev->num_endpoints; j++) {
|
||||
const struct snd_soc_acpi_endpoint *adr_end;
|
||||
const struct asoc_sdw_dai_info *dai_info;
|
||||
@ -1199,9 +1304,35 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
|
||||
dai_info = &codec_info->dais[adr_end->num];
|
||||
soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end);
|
||||
|
||||
if (dai_info->quirk &&
|
||||
!(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk)))
|
||||
continue;
|
||||
/*
|
||||
* quirk should have higher priority than the sdca properties
|
||||
* in the BIOS. We can't always check the DAI quirk because we
|
||||
* will set the mc_quirk when the BIOS doesn't provide the right
|
||||
* information. The endpoint will be skipped if the dai_info->
|
||||
* quirk_exclude and mc_quirk are both not set if we always skip
|
||||
* the endpoint according to the quirk information. We need to
|
||||
* keep the endpoint if it is present in the BIOS. So, only
|
||||
* check the DAI quirk when the mc_quirk is set or SDCA endpoint
|
||||
* present check is not needed.
|
||||
*/
|
||||
if (dai_info->quirk & ctx->mc_quirk || !check_sdca) {
|
||||
/*
|
||||
* Check the endpoint if a matching quirk is set or SDCA
|
||||
* endpoint check is not necessary
|
||||
*/
|
||||
if (dai_info->quirk &&
|
||||
!(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk)))
|
||||
continue;
|
||||
} else {
|
||||
/* Check SDCA codec endpoint if there is no matching quirk */
|
||||
ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* The endpoint is not present, skip */
|
||||
if (!ret)
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_dbg(dev,
|
||||
"Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n",
|
||||
|
Loading…
Reference in New Issue
Block a user