Commit 28a87eeb authored by Mengdong Lin's avatar Mengdong Lin Committed by Mark Brown

ASoC: topology: Update TLV support so we can support more TLV types

Currently the TLV topology structure is targeted at only supporting the
DB scale data. This patch extends support for the other TLV types so they
can be easily added at a later stage.

TLV structure is moved to common topology control header since it's a
common field for controls and can be processed in a general way.

Users must set a proper access flag for a control since it's used to
decide if the TLV field is valid and if a TLV callback is needed.

Removed the following fields from topology TLV struct:
- size/count: type can decide the size.
- numid: not needed to initialize TLV for kcontrol.
- data: replaced by the type specific struct.

Added TLV structure to generic control header and removed TLV structure
from mixer control.
Signed-off-by: default avatarMengdong Lin <mengdong.lin@intel.com>
Signed-off-by: default avatarLiam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 113adf21
...@@ -137,11 +137,19 @@ struct snd_soc_tplg_private { ...@@ -137,11 +137,19 @@ struct snd_soc_tplg_private {
/* /*
* Kcontrol TLV data. * Kcontrol TLV data.
*/ */
struct snd_soc_tplg_tlv_dbscale {
__le32 min;
__le32 step;
__le32 mute;
} __attribute__((packed));
struct snd_soc_tplg_ctl_tlv { struct snd_soc_tplg_ctl_tlv {
__le32 size; /* in bytes aligned to 4 */ __le32 size; /* in bytes of this structure */
__le32 numid; /* control element numeric identification */ __le32 type; /* SNDRV_CTL_TLVT_*, type of TLV */
__le32 count; /* number of elem in data array */ union {
__le32 data[SND_SOC_TPLG_TLV_SIZE]; __le32 data[SND_SOC_TPLG_TLV_SIZE];
struct snd_soc_tplg_tlv_dbscale scale;
};
} __attribute__((packed)); } __attribute__((packed));
/* /*
...@@ -172,7 +180,7 @@ struct snd_soc_tplg_ctl_hdr { ...@@ -172,7 +180,7 @@ struct snd_soc_tplg_ctl_hdr {
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le32 access; __le32 access;
struct snd_soc_tplg_kcontrol_ops_id ops; struct snd_soc_tplg_kcontrol_ops_id ops;
__le32 tlv_size; /* non zero means control has TLV data */ struct snd_soc_tplg_ctl_tlv tlv;
} __attribute__((packed)); } __attribute__((packed));
/* /*
...@@ -260,7 +268,6 @@ struct snd_soc_tplg_mixer_control { ...@@ -260,7 +268,6 @@ struct snd_soc_tplg_mixer_control {
__le32 invert; __le32 invert;
__le32 num_channels; __le32 num_channels;
struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN]; struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
struct snd_soc_tplg_ctl_tlv tlv;
struct snd_soc_tplg_private priv; struct snd_soc_tplg_private priv;
} __attribute__((packed)); } __attribute__((packed));
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/soc-dapm.h> #include <sound/soc-dapm.h>
#include <sound/soc-topology.h> #include <sound/soc-topology.h>
#include <sound/tlv.h>
/* /*
* We make several passes over the data (since it wont necessarily be ordered) * We make several passes over the data (since it wont necessarily be ordered)
...@@ -579,28 +580,51 @@ static int soc_tplg_init_kcontrol(struct soc_tplg *tplg, ...@@ -579,28 +580,51 @@ static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
return 0; return 0;
} }
static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
struct snd_kcontrol_new *kc, struct snd_soc_tplg_tlv_dbscale *scale)
{
unsigned int item_len = 2 * sizeof(unsigned int);
unsigned int *p;
p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
if (!p)
return -ENOMEM;
p[0] = SNDRV_CTL_TLVT_DB_SCALE;
p[1] = item_len;
p[2] = scale->min;
p[3] = (scale->step & TLV_DB_SCALE_MASK)
| (scale->mute ? TLV_DB_SCALE_MUTE : 0);
kc->tlv.p = (void *)p;
return 0;
}
static int soc_tplg_create_tlv(struct soc_tplg *tplg, static int soc_tplg_create_tlv(struct soc_tplg *tplg,
struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_tlv *tplg_tlv) struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc)
{ {
struct snd_ctl_tlv *tlv; struct snd_soc_tplg_ctl_tlv *tplg_tlv;
int size;
if (tplg_tlv->count == 0) if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
return 0; return 0;
size = ((tplg_tlv->count + (sizeof(unsigned int) - 1)) & if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
~(sizeof(unsigned int) - 1)); kc->tlv.c = snd_soc_bytes_tlv_callback;
tlv = kzalloc(sizeof(*tlv) + size, GFP_KERNEL); } else {
if (tlv == NULL) tplg_tlv = &tc->tlv;
return -ENOMEM; switch (tplg_tlv->type) {
case SNDRV_CTL_TLVT_DB_SCALE:
dev_dbg(tplg->dev, " created TLV type %d size %d bytes\n", return soc_tplg_create_tlv_db_scale(tplg, kc,
tplg_tlv->numid, size); &tplg_tlv->scale);
tlv->numid = tplg_tlv->numid; /* TODO: add support for other TLV types */
tlv->length = size; default:
memcpy(&tlv->tlv[0], tplg_tlv->data, size); dev_dbg(tplg->dev, "Unsupported TLV type %d\n",
kc->tlv.p = (void *)tlv; tplg_tlv->type);
return -EINVAL;
}
}
return 0; return 0;
} }
...@@ -772,7 +796,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, ...@@ -772,7 +796,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
} }
/* create any TLV data */ /* create any TLV data */
soc_tplg_create_tlv(tplg, &kc, &mc->tlv); soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
/* register control here */ /* register control here */
err = soc_tplg_add_kcontrol(tplg, &kc, err = soc_tplg_add_kcontrol(tplg, &kc,
......
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