Commit e6d50e47 authored by Amadeusz Sławiński's avatar Amadeusz Sławiński Committed by Mark Brown

ASoC: Intel: avs: Improve topology parsing of dynamic strings

Current mechanism replaces "%d" present in some routes and widget names
with SSP number. However there are also configurations which make use of
TDM number, in which case expected behavior would be to have string in
form of SSP:TDM - see implementation of avs_i2s_platform_register() in
sound/soc/intel/avs/pcm.c.

Implement custom function, which parses string and make use of it when
parsing topology. While at it make sure that we generate dynamic names
only if there is no multiple SSPs or TDMs defined.
Signed-off-by: default avatarAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Link: https://lore.kernel.org/r/20231012083514.492626-4-amadeuszx.slawinski@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 7a6debe0
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "avs.h" #include "avs.h"
#include "control.h" #include "control.h"
#include "topology.h" #include "topology.h"
#include "utils.h"
/* Get pointer to vendor array at the specified offset. */ /* Get pointer to vendor array at the specified offset. */
#define avs_tplg_vendor_array_at(array, offset) \ #define avs_tplg_vendor_array_at(array, offset) \
...@@ -371,22 +372,50 @@ parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *ob ...@@ -371,22 +372,50 @@ parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *ob
return 0; return 0;
} }
static int avs_ssp_sprint(char *buf, size_t size, const char *fmt, int port, int tdm)
{
char *needle = strstr(fmt, "%d");
int retsize;
/*
* If there is %d present in fmt string it should be replaced by either
* SSP or SSP:TDM, where SSP and TDM are numbers, all other formatting
* will be ignored.
*/
if (needle) {
retsize = scnprintf(buf, min_t(size_t, size, needle - fmt + 1), "%s", fmt);
retsize += scnprintf(buf + retsize, size - retsize, "%d", port);
if (tdm)
retsize += scnprintf(buf + retsize, size - retsize, ":%d", tdm);
retsize += scnprintf(buf + retsize, size - retsize, "%s", needle + 2);
return retsize;
}
return snprintf(buf, size, "%s", fmt);
}
static int parse_link_formatted_string(struct snd_soc_component *comp, void *elem, static int parse_link_formatted_string(struct snd_soc_component *comp, void *elem,
void *object, u32 offset) void *object, u32 offset)
{ {
struct snd_soc_tplg_vendor_string_elem *tuple = elem; struct snd_soc_tplg_vendor_string_elem *tuple = elem;
struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev); struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
char *val = (char *)((u8 *)object + offset); char *val = (char *)((u8 *)object + offset);
int ssp_port, tdm_slot;
/* /*
* Dynamic naming - string formats, e.g.: ssp%d - supported only for * Dynamic naming - string formats, e.g.: ssp%d - supported only for
* topologies describing single device e.g.: an I2S codec on SSP0. * topologies describing single device e.g.: an I2S codec on SSP0.
*/ */
if (hweight_long(mach->mach_params.i2s_link_mask) != 1) if (!avs_mach_singular_ssp(mach))
return avs_parse_string_token(comp, elem, object, offset);
ssp_port = avs_mach_ssp_port(mach);
if (!avs_mach_singular_tdm(mach, ssp_port))
return avs_parse_string_token(comp, elem, object, offset); return avs_parse_string_token(comp, elem, object, offset);
snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string, tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
__ffs(mach->mach_params.i2s_link_mask));
avs_ssp_sprint(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string, ssp_port, tdm_slot);
return 0; return 0;
} }
...@@ -813,6 +842,7 @@ static void ...@@ -813,6 +842,7 @@ static void
assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg) assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg)
{ {
struct snd_soc_acpi_mach *mach; struct snd_soc_acpi_mach *mach;
int ssp_port, tdm_slot;
if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID)) if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
return; return;
...@@ -826,11 +856,22 @@ assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf ...@@ -826,11 +856,22 @@ assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf
return; return;
} }
/* If topology sets value don't overwrite it */
if (cfg->copier.vindex.i2s.instance)
return;
mach = dev_get_platdata(comp->card->dev); mach = dev_get_platdata(comp->card->dev);
/* Automatic assignment only when board describes single SSP. */ if (!avs_mach_singular_ssp(mach))
if (hweight_long(mach->mach_params.i2s_link_mask) == 1 && !cfg->copier.vindex.i2s.instance) return;
cfg->copier.vindex.i2s.instance = __ffs(mach->mach_params.i2s_link_mask); ssp_port = avs_mach_ssp_port(mach);
if (!avs_mach_singular_tdm(mach, ssp_port))
return;
tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
cfg->copier.vindex.i2s.instance = ssp_port;
cfg->copier.vindex.i2s.time_slot = tdm_slot;
} }
static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp, static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
...@@ -1381,20 +1422,24 @@ static int avs_route_load(struct snd_soc_component *comp, int index, ...@@ -1381,20 +1422,24 @@ static int avs_route_load(struct snd_soc_component *comp, int index,
struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev); struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN; size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
u32 port; int ssp_port, tdm_slot;
/* See parse_link_formatted_string() for dynamic naming when(s). */ /* See parse_link_formatted_string() for dynamic naming when(s). */
if (hweight_long(mach->mach_params.i2s_link_mask) == 1) { if (!avs_mach_singular_ssp(mach))
port = __ffs(mach->mach_params.i2s_link_mask); return 0;
ssp_port = avs_mach_ssp_port(mach);
snprintf(buf, len, route->source, port);
strscpy((char *)route->source, buf, len); if (!avs_mach_singular_tdm(mach, ssp_port))
snprintf(buf, len, route->sink, port); return 0;
strscpy((char *)route->sink, buf, len); tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
if (route->control) {
snprintf(buf, len, route->control, port); avs_ssp_sprint(buf, len, route->source, ssp_port, tdm_slot);
strscpy((char *)route->control, buf, len); strscpy((char *)route->source, buf, len);
} avs_ssp_sprint(buf, len, route->sink, ssp_port, tdm_slot);
strscpy((char *)route->sink, buf, len);
if (route->control) {
avs_ssp_sprint(buf, len, route->control, ssp_port, tdm_slot);
strscpy((char *)route->control, buf, len);
} }
return 0; return 0;
...@@ -1408,6 +1453,7 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, ...@@ -1408,6 +1453,7 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
struct avs_tplg_path_template *template; struct avs_tplg_path_template *template;
struct avs_soc_component *acomp = to_avs_soc_component(comp); struct avs_soc_component *acomp = to_avs_soc_component(comp);
struct avs_tplg *tplg; struct avs_tplg *tplg;
int ssp_port, tdm_slot;
if (!le32_to_cpu(dw->priv.size)) if (!le32_to_cpu(dw->priv.size))
return 0; return 0;
...@@ -1419,16 +1465,28 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, ...@@ -1419,16 +1465,28 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
tplg = acomp->tplg; tplg = acomp->tplg;
mach = dev_get_platdata(comp->card->dev); mach = dev_get_platdata(comp->card->dev);
if (!avs_mach_singular_ssp(mach))
goto static_name;
ssp_port = avs_mach_ssp_port(mach);
/* See parse_link_formatted_string() for dynamic naming when(s). */ /* See parse_link_formatted_string() for dynamic naming when(s). */
if (hweight_long(mach->mach_params.i2s_link_mask) == 1) { if (avs_mach_singular_tdm(mach, ssp_port)) {
/* size is based on possible %d -> SSP:TDM, where SSP and TDM < 10 + '\0' */
size_t size = strlen(dw->name) + 2;
char *buf;
tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
buf = kmalloc(size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
avs_ssp_sprint(buf, size, dw->name, ssp_port, tdm_slot);
kfree(w->name); kfree(w->name);
/* w->name is freed later by soc_tplg_dapm_widget_create() */ /* w->name is freed later by soc_tplg_dapm_widget_create() */
w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask)); w->name = buf;
if (!w->name)
return -ENOMEM;
} }
static_name:
template = avs_tplg_path_template_create(comp, tplg, dw->priv.array, template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
le32_to_cpu(dw->priv.size)); le32_to_cpu(dw->priv.size));
if (IS_ERR(template)) { if (IS_ERR(template)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment