Skip to content

Commit eae45e1

Browse files
committed
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>
1 parent b50fa21 commit eae45e1

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

sound/soc/sdw_utils/soc_sdw_utils.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/module.h>
1111
#include <linux/soundwire/sdw.h>
1212
#include <linux/soundwire/sdw_type.h>
13+
#include <sound/sdca_function.h>
1314
#include <sound/soc_sdw_utils.h>
1415

1516
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
11311132
}
11321133
EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS");
11331134

1135+
static int asoc_sdw_get_dai_type(u32 type)
1136+
{
1137+
switch (type) {
1138+
case SDCA_FUNCTION_TYPE_SMART_AMP:
1139+
case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
1140+
return SOC_SDW_DAI_TYPE_AMP;
1141+
case SDCA_FUNCTION_TYPE_SMART_MIC:
1142+
case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
1143+
case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
1144+
return SOC_SDW_DAI_TYPE_MIC;
1145+
case SDCA_FUNCTION_TYPE_UAJ:
1146+
case SDCA_FUNCTION_TYPE_RJ:
1147+
case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
1148+
return SOC_SDW_DAI_TYPE_JACK;
1149+
default:
1150+
return -EINVAL;
1151+
}
1152+
}
1153+
1154+
/*
1155+
* Check if the SDCA endpoint is present by the SDW peripheral
1156+
*
1157+
* @dev: Device pointer
1158+
* @codec_info: Codec info pointer
1159+
* @adr_link: ACPI link address
1160+
* @adr_index: Index of the ACPI link address
1161+
* @end_index: Index of the endpoint
1162+
*
1163+
* Return: 1 if the endpoint is present,
1164+
* 0 if the endpoint is not present,
1165+
* negative error code.
1166+
*/
1167+
1168+
static int is_sdca_endpoint_present(struct device *dev,
1169+
struct asoc_sdw_codec_info *codec_info,
1170+
const struct snd_soc_acpi_link_adr *adr_link,
1171+
int adr_index, int end_index)
1172+
{
1173+
const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index];
1174+
const struct snd_soc_acpi_endpoint *adr_end;
1175+
const struct asoc_sdw_dai_info *dai_info;
1176+
struct snd_soc_dai_link_component *dlc;
1177+
struct snd_soc_dai *codec_dai;
1178+
struct sdw_slave *slave;
1179+
struct device *sdw_dev;
1180+
const char *sdw_codec_name;
1181+
int i;
1182+
1183+
dlc = kzalloc(sizeof(*dlc), GFP_KERNEL);
1184+
1185+
adr_end = &adr_dev->endpoints[end_index];
1186+
dai_info = &codec_info->dais[adr_end->num];
1187+
1188+
dlc->dai_name = dai_info->dai_name;
1189+
codec_dai = snd_soc_find_dai_with_mutex(dlc);
1190+
if (!codec_dai) {
1191+
dev_warn(dev, "codec dai %s not registered yet\n", dlc->dai_name);
1192+
kfree(dlc);
1193+
return -EPROBE_DEFER;
1194+
}
1195+
kfree(dlc);
1196+
1197+
sdw_codec_name = _asoc_sdw_get_codec_name(dev, codec_info,
1198+
adr_link, adr_index);
1199+
if (!sdw_codec_name)
1200+
return -ENOMEM;
1201+
1202+
sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
1203+
if (!sdw_dev) {
1204+
dev_err(dev, "codec %s not found\n", sdw_codec_name);
1205+
return -EINVAL;
1206+
}
1207+
1208+
slave = dev_to_sdw_dev(sdw_dev);
1209+
if (!slave)
1210+
return -EINVAL;
1211+
1212+
/* Make sure BIOS provides SDCA properties */
1213+
if (!slave->sdca_data.interface_revision) {
1214+
dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n");
1215+
return 1;
1216+
}
1217+
1218+
for (i = 0; i < slave->sdca_data.num_functions; i++) {
1219+
int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type);
1220+
1221+
if (dai_type == dai_info->dai_type) {
1222+
dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n",
1223+
dai_type, slave->sdca_data.function[i].name);
1224+
return 1;
1225+
}
1226+
}
1227+
1228+
dev_dbg(&slave->dev,
1229+
"SDCA device function for DAI type %d not supported, skip endpoint\n",
1230+
dai_info->dai_type);
1231+
1232+
return 0;
1233+
}
1234+
11341235
int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
11351236
struct asoc_sdw_dailink *soc_dais,
11361237
struct asoc_sdw_endpoint *soc_ends,
@@ -1159,6 +1260,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
11591260
const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
11601261
struct asoc_sdw_codec_info *codec_info;
11611262
const char *codec_name;
1263+
bool check_sdca = false;
11621264

11631265
if (!adr_dev->name_prefix) {
11641266
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,
11891291
soc_end->include_sidecar = true;
11901292
}
11911293

1294+
if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1)
1295+
check_sdca = true;
1296+
11921297
for (j = 0; j < adr_dev->num_endpoints; j++) {
11931298
const struct snd_soc_acpi_endpoint *adr_end;
11941299
const struct asoc_sdw_dai_info *dai_info;
@@ -1203,6 +1308,22 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
12031308
!(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk)))
12041309
continue;
12051310

1311+
/*
1312+
* Skip the sdca endpoint presence check if machine quirk is set.
1313+
* In other words, quirk should have higher priority than the sdca
1314+
* properties in the BIOS.
1315+
*/
1316+
if (check_sdca && !(dai_info->quirk & ctx->mc_quirk)) {
1317+
ret = is_sdca_endpoint_present(dev, codec_info,
1318+
adr_link, i, j);
1319+
if (ret < 0)
1320+
return ret;
1321+
1322+
/* The endpoint is not present, skip */
1323+
if (!ret)
1324+
continue;
1325+
}
1326+
12061327
dev_dbg(dev,
12071328
"Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n",
12081329
ffs(adr_link->mask) - 1, adr_dev->adr,

0 commit comments

Comments
 (0)