Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 139 additions & 12 deletions sound/soc/sdw_utils/soc_sdw_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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);
Expand All @@ -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");

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
68 changes: 62 additions & 6 deletions sound/soc/soc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down
Loading