mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
ASoC: sdw_utils/intel: move soundwire endpoint parsing helper functions
Move SoundWire endpoint parsing helper functions to common place holder. These functions will be used by other platform machine driver code. Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://patch.msgid.link/20240913090631.1834543-5-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
7860df5b29
commit
13b24f8478
@ -161,6 +161,16 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d
|
|||||||
int (*init)(struct snd_soc_pcm_runtime *rtd),
|
int (*init)(struct snd_soc_pcm_runtime *rtd),
|
||||||
const struct snd_soc_ops *ops);
|
const struct snd_soc_ops *ops);
|
||||||
|
|
||||||
|
int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends);
|
||||||
|
|
||||||
|
struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
|
||||||
|
const struct snd_soc_acpi_endpoint *new);
|
||||||
|
|
||||||
|
int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
|
||||||
|
struct asoc_sdw_dailink *soc_dais,
|
||||||
|
struct asoc_sdw_endpoint *soc_ends,
|
||||||
|
int *num_devs);
|
||||||
|
|
||||||
int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd);
|
int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd);
|
||||||
|
|
||||||
/* DMIC support */
|
/* DMIC support */
|
||||||
|
@ -619,164 +619,6 @@ static const struct snd_soc_ops sdw_ops = {
|
|||||||
|
|
||||||
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
|
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
|
||||||
|
|
||||||
static int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends)
|
|
||||||
{
|
|
||||||
struct device *dev = card->dev;
|
|
||||||
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
|
|
||||||
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
|
|
||||||
const struct snd_soc_acpi_link_adr *adr_link;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
|
|
||||||
*num_devs += adr_link->num_adr;
|
|
||||||
|
|
||||||
for (i = 0; i < adr_link->num_adr; i++)
|
|
||||||
*num_ends += adr_link->adr_d[i].num_endpoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
|
|
||||||
const struct snd_soc_acpi_endpoint *new)
|
|
||||||
{
|
|
||||||
while (dailinks->initialised) {
|
|
||||||
if (new->aggregated && dailinks->group_id == new->group_id)
|
|
||||||
return dailinks;
|
|
||||||
|
|
||||||
dailinks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dailinks->endpoints);
|
|
||||||
dailinks->group_id = new->group_id;
|
|
||||||
dailinks->initialised = true;
|
|
||||||
|
|
||||||
return dailinks;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
|
|
||||||
struct asoc_sdw_dailink *sof_dais,
|
|
||||||
struct asoc_sdw_endpoint *sof_ends,
|
|
||||||
int *num_devs)
|
|
||||||
{
|
|
||||||
struct device *dev = card->dev;
|
|
||||||
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
|
|
||||||
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
|
|
||||||
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
|
|
||||||
const struct snd_soc_acpi_link_adr *adr_link;
|
|
||||||
struct asoc_sdw_endpoint *sof_end = sof_ends;
|
|
||||||
int num_dais = 0;
|
|
||||||
int i, j;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
|
|
||||||
int num_link_dailinks = 0;
|
|
||||||
|
|
||||||
if (!is_power_of_2(adr_link->mask)) {
|
|
||||||
dev_err(dev, "link with multiple mask bits: 0x%x\n",
|
|
||||||
adr_link->mask);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < adr_link->num_adr; i++) {
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (!adr_dev->name_prefix) {
|
|
||||||
dev_err(dev, "codec 0x%llx does not have a name prefix\n",
|
|
||||||
adr_dev->adr);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
|
|
||||||
if (!codec_info)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
|
|
||||||
|
|
||||||
codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i);
|
|
||||||
if (!codec_name)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
dev_dbg(dev, "Adding prefix %s for %s\n",
|
|
||||||
adr_dev->name_prefix, codec_name);
|
|
||||||
|
|
||||||
sof_end->name_prefix = adr_dev->name_prefix;
|
|
||||||
|
|
||||||
if (codec_info->count_sidecar && codec_info->add_sidecar) {
|
|
||||||
ret = codec_info->count_sidecar(card, &num_dais, num_devs);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
sof_end->include_sidecar = 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;
|
|
||||||
struct asoc_sdw_dailink *sof_dai;
|
|
||||||
int stream;
|
|
||||||
|
|
||||||
adr_end = &adr_dev->endpoints[j];
|
|
||||||
dai_info = &codec_info->dais[adr_end->num];
|
|
||||||
sof_dai = asoc_sdw_find_dailink(sof_dais, adr_end);
|
|
||||||
|
|
||||||
if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dev_dbg(dev,
|
|
||||||
"Add dev: %d, 0x%llx end: %d, %s, %c/%c to %s: %d\n",
|
|
||||||
ffs(adr_link->mask) - 1, adr_dev->adr,
|
|
||||||
adr_end->num, type_strings[dai_info->dai_type],
|
|
||||||
dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
|
|
||||||
dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
|
|
||||||
adr_end->aggregated ? "group" : "solo",
|
|
||||||
adr_end->group_id);
|
|
||||||
|
|
||||||
if (adr_end->num >= codec_info->dai_num) {
|
|
||||||
dev_err(dev,
|
|
||||||
"%d is too many endpoints for codec: 0x%x\n",
|
|
||||||
adr_end->num, codec_info->part_id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_each_pcm_streams(stream) {
|
|
||||||
if (dai_info->direction[stream] &&
|
|
||||||
dai_info->dailink[stream] < 0) {
|
|
||||||
dev_err(dev,
|
|
||||||
"Invalid dailink id %d for codec: 0x%x\n",
|
|
||||||
dai_info->dailink[stream],
|
|
||||||
codec_info->part_id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dai_info->direction[stream]) {
|
|
||||||
num_dais += !sof_dai->num_devs[stream];
|
|
||||||
sof_dai->num_devs[stream]++;
|
|
||||||
sof_dai->link_mask[stream] |= adr_link->mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
num_link_dailinks += !!list_empty(&sof_dai->endpoints);
|
|
||||||
list_add_tail(&sof_end->list, &sof_dai->endpoints);
|
|
||||||
|
|
||||||
sof_end->link_mask = adr_link->mask;
|
|
||||||
sof_end->codec_name = codec_name;
|
|
||||||
sof_end->codec_info = codec_info;
|
|
||||||
sof_end->dai_info = dai_info;
|
|
||||||
sof_end++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->append_dai_type |= (num_link_dailinks > 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return num_dais;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_sdw_dailink(struct snd_soc_card *card,
|
static int create_sdw_dailink(struct snd_soc_card *card,
|
||||||
struct asoc_sdw_dailink *sof_dai,
|
struct asoc_sdw_dailink *sof_dai,
|
||||||
struct snd_soc_dai_link **dai_links,
|
struct snd_soc_dai_link **dai_links,
|
||||||
|
@ -1005,5 +1005,166 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, SND_SOC_SDW_UTILS);
|
EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, SND_SOC_SDW_UTILS);
|
||||||
|
|
||||||
|
int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends)
|
||||||
|
{
|
||||||
|
struct device *dev = card->dev;
|
||||||
|
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
|
||||||
|
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
|
||||||
|
const struct snd_soc_acpi_link_adr *adr_link;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
|
||||||
|
*num_devs += adr_link->num_adr;
|
||||||
|
|
||||||
|
for (i = 0; i < adr_link->num_adr; i++)
|
||||||
|
*num_ends += adr_link->adr_d[i].num_endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, SND_SOC_SDW_UTILS);
|
||||||
|
|
||||||
|
struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
|
||||||
|
const struct snd_soc_acpi_endpoint *new)
|
||||||
|
{
|
||||||
|
while (dailinks->initialised) {
|
||||||
|
if (new->aggregated && dailinks->group_id == new->group_id)
|
||||||
|
return dailinks;
|
||||||
|
|
||||||
|
dailinks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&dailinks->endpoints);
|
||||||
|
dailinks->group_id = new->group_id;
|
||||||
|
dailinks->initialised = true;
|
||||||
|
|
||||||
|
return dailinks;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, SND_SOC_SDW_UTILS);
|
||||||
|
|
||||||
|
int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
|
||||||
|
struct asoc_sdw_dailink *soc_dais,
|
||||||
|
struct asoc_sdw_endpoint *soc_ends,
|
||||||
|
int *num_devs)
|
||||||
|
{
|
||||||
|
struct device *dev = card->dev;
|
||||||
|
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||||
|
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
|
||||||
|
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
|
||||||
|
const struct snd_soc_acpi_link_adr *adr_link;
|
||||||
|
struct asoc_sdw_endpoint *soc_end = soc_ends;
|
||||||
|
int num_dais = 0;
|
||||||
|
int i, j;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
|
||||||
|
int num_link_dailinks = 0;
|
||||||
|
|
||||||
|
if (!is_power_of_2(adr_link->mask)) {
|
||||||
|
dev_err(dev, "link with multiple mask bits: 0x%x\n",
|
||||||
|
adr_link->mask);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < adr_link->num_adr; i++) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!adr_dev->name_prefix) {
|
||||||
|
dev_err(dev, "codec 0x%llx does not have a name prefix\n",
|
||||||
|
adr_dev->adr);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
|
||||||
|
if (!codec_info)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
|
||||||
|
|
||||||
|
codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i);
|
||||||
|
if (!codec_name)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dev_dbg(dev, "Adding prefix %s for %s\n",
|
||||||
|
adr_dev->name_prefix, codec_name);
|
||||||
|
|
||||||
|
soc_end->name_prefix = adr_dev->name_prefix;
|
||||||
|
|
||||||
|
if (codec_info->count_sidecar && codec_info->add_sidecar) {
|
||||||
|
ret = codec_info->count_sidecar(card, &num_dais, num_devs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
soc_end->include_sidecar = 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;
|
||||||
|
struct asoc_sdw_dailink *soc_dai;
|
||||||
|
int stream;
|
||||||
|
|
||||||
|
adr_end = &adr_dev->endpoints[j];
|
||||||
|
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 & ctx->mc_quirk))
|
||||||
|
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,
|
||||||
|
adr_end->num, dai_info->dai_type,
|
||||||
|
dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
|
||||||
|
dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
|
||||||
|
adr_end->aggregated ? "group" : "solo",
|
||||||
|
adr_end->group_id);
|
||||||
|
|
||||||
|
if (adr_end->num >= codec_info->dai_num) {
|
||||||
|
dev_err(dev,
|
||||||
|
"%d is too many endpoints for codec: 0x%x\n",
|
||||||
|
adr_end->num, codec_info->part_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_pcm_streams(stream) {
|
||||||
|
if (dai_info->direction[stream] &&
|
||||||
|
dai_info->dailink[stream] < 0) {
|
||||||
|
dev_err(dev,
|
||||||
|
"Invalid dailink id %d for codec: 0x%x\n",
|
||||||
|
dai_info->dailink[stream],
|
||||||
|
codec_info->part_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dai_info->direction[stream]) {
|
||||||
|
num_dais += !soc_dai->num_devs[stream];
|
||||||
|
soc_dai->num_devs[stream]++;
|
||||||
|
soc_dai->link_mask[stream] |= adr_link->mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
num_link_dailinks += !!list_empty(&soc_dai->endpoints);
|
||||||
|
list_add_tail(&soc_end->list, &soc_dai->endpoints);
|
||||||
|
|
||||||
|
soc_end->link_mask = adr_link->mask;
|
||||||
|
soc_end->codec_name = codec_name;
|
||||||
|
soc_end->codec_info = codec_info;
|
||||||
|
soc_end->dai_info = dai_info;
|
||||||
|
soc_end++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->append_dai_type |= (num_link_dailinks > 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_dais;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, SND_SOC_SDW_UTILS);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("SoundWire ASoC helpers");
|
MODULE_DESCRIPTION("SoundWire ASoC helpers");
|
||||||
|
Loading…
Reference in New Issue
Block a user