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: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Link: https://lore.kernel.org/r/20231012083514.492626-4-amadeuszx.slawinski@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Amadeusz Sławiński 2023-10-12 10:35:01 +02:00 committed by Mark Brown
parent 7a6debe047
commit e6d50e474e
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View file

@ -15,6 +15,7 @@
#include "avs.h"
#include "control.h"
#include "topology.h"
#include "utils.h"
/* Get pointer to vendor array at the specified 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
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,
void *object, u32 offset)
{
struct snd_soc_tplg_vendor_string_elem *tuple = elem;
struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
char *val = (char *)((u8 *)object + offset);
int ssp_port, tdm_slot;
/*
* Dynamic naming - string formats, e.g.: ssp%d - supported only for
* 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);
snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string,
__ffs(mach->mach_params.i2s_link_mask));
ssp_port = avs_mach_ssp_port(mach);
if (!avs_mach_singular_tdm(mach, ssp_port))
return avs_parse_string_token(comp, elem, object, offset);
tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
avs_ssp_sprint(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string, ssp_port, tdm_slot);
return 0;
}
@ -813,6 +842,7 @@ static void
assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg)
{
struct snd_soc_acpi_mach *mach;
int ssp_port, tdm_slot;
if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
return;
@ -826,11 +856,22 @@ assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf
return;
}
/* If topology sets value don't overwrite it */
if (cfg->copier.vindex.i2s.instance)
return;
mach = dev_get_platdata(comp->card->dev);
/* Automatic assignment only when board describes single SSP. */
if (hweight_long(mach->mach_params.i2s_link_mask) == 1 && !cfg->copier.vindex.i2s.instance)
cfg->copier.vindex.i2s.instance = __ffs(mach->mach_params.i2s_link_mask);
if (!avs_mach_singular_ssp(mach))
return;
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,
@ -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);
size_t len = 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). */
if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
port = __ffs(mach->mach_params.i2s_link_mask);
if (!avs_mach_singular_ssp(mach))
return 0;
ssp_port = avs_mach_ssp_port(mach);
snprintf(buf, len, route->source, port);
strscpy((char *)route->source, buf, len);
snprintf(buf, len, route->sink, port);
strscpy((char *)route->sink, buf, len);
if (route->control) {
snprintf(buf, len, route->control, port);
strscpy((char *)route->control, buf, len);
}
if (!avs_mach_singular_tdm(mach, ssp_port))
return 0;
tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
avs_ssp_sprint(buf, len, route->source, ssp_port, tdm_slot);
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;
@ -1408,6 +1453,7 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
struct avs_tplg_path_template *template;
struct avs_soc_component *acomp = to_avs_soc_component(comp);
struct avs_tplg *tplg;
int ssp_port, tdm_slot;
if (!le32_to_cpu(dw->priv.size))
return 0;
@ -1419,16 +1465,28 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
tplg = acomp->tplg;
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). */
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);
/* 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));
if (!w->name)
return -ENOMEM;
w->name = buf;
}
static_name:
template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
le32_to_cpu(dw->priv.size));
if (IS_ERR(template)) {