Skip to content

Commit bc0821a

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 bc0821a

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

sound/soc/sdw_utils/soc_sdw_utils.c

Lines changed: 119 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,104 @@ 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 function 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
1169+
is_sdca_endpoint_present(struct device *dev,
1170+
struct asoc_sdw_codec_info *codec_info,
1171+
const struct snd_soc_acpi_link_adr *adr_link,
1172+
int adr_index,int end_index)
1173+
{
1174+
const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index];
1175+
const struct snd_soc_acpi_endpoint *adr_end;
1176+
const struct asoc_sdw_dai_info *dai_info;
1177+
struct snd_soc_dai_link_component dlc;
1178+
struct snd_soc_dai *codec_dai;
1179+
struct sdw_slave *slave;
1180+
struct device *sdw_dev;
1181+
const char *sdw_codec_name;
1182+
int i;
1183+
1184+
adr_end = &adr_dev->endpoints[end_index];
1185+
dai_info = &codec_info->dais[adr_end->num];
1186+
1187+
dlc.dai_name = dai_info->dai_name;
1188+
codec_dai = snd_soc_find_dai_with_mutex(&dlc);
1189+
if (!codec_dai) {
1190+
dev_warn(dev, "codec dai %s not registered yet\n", dlc.dai_name);
1191+
return -EPROBE_DEFER;
1192+
}
1193+
1194+
sdw_codec_name = _asoc_sdw_get_codec_name(dev, codec_info,
1195+
adr_link, adr_index);
1196+
if (!sdw_codec_name)
1197+
return -ENOMEM;
1198+
1199+
sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
1200+
if (!sdw_dev) {
1201+
dev_err(dev, "codec %s not found\n", sdw_codec_name);
1202+
return -EINVAL;
1203+
}
1204+
1205+
slave = dev_to_sdw_dev(sdw_dev);
1206+
if (!slave)
1207+
return -EINVAL;
1208+
1209+
/* Make sure BIOS provides SDCA properties */
1210+
if (!slave->sdca_data.interface_revision) {
1211+
dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n");
1212+
return 1;
1213+
}
1214+
1215+
for (i = 0; i < slave->sdca_data.num_functions; i++) {
1216+
int dai_type = asoc_sdw_get_dai_type(
1217+
slave->sdca_data.function[i].type);
1218+
1219+
if (dai_type == dai_info->dai_type) {
1220+
dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n",
1221+
dai_type, slave->sdca_data.function[i].name);
1222+
return 1;
1223+
}
1224+
}
1225+
1226+
dev_dbg(&slave->dev,
1227+
"SDCA device function for DAI type %d not supported, skip endpoint\n",
1228+
dai_info->dai_type);
1229+
1230+
return 0;
1231+
}
1232+
11341233
int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
11351234
struct asoc_sdw_dailink *soc_dais,
11361235
struct asoc_sdw_endpoint *soc_ends,
@@ -1159,6 +1258,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
11591258
const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
11601259
struct asoc_sdw_codec_info *codec_info;
11611260
const char *codec_name;
1261+
bool check_sdca = false;
11621262

11631263
if (!adr_dev->name_prefix) {
11641264
dev_err(dev, "codec 0x%llx does not have a name prefix\n",
@@ -1189,6 +1289,9 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
11891289
soc_end->include_sidecar = true;
11901290
}
11911291

1292+
if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1)
1293+
check_sdca = true;
1294+
11921295
for (j = 0; j < adr_dev->num_endpoints; j++) {
11931296
const struct snd_soc_acpi_endpoint *adr_end;
11941297
const struct asoc_sdw_dai_info *dai_info;
@@ -1203,6 +1306,22 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
12031306
!(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk)))
12041307
continue;
12051308

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

0 commit comments

Comments
 (0)