Skip to content

Commit 1a7dd6e

Browse files
mengdonglinbroonie
authored andcommitted
ASoC: topology: Allow a widget to have multiple enum controls
This patch can create multiple enumerated mixer controls for a widget. Previously topology kernel driver assumes a widget can have only one emumerated mixer control. We need to remove this restriction for Broxton. Its firmware modules (widgets) may need multiple enum controls based on the channel and MIC combination. No ABI change is needed. The ABI allows a widget to embed multiple controls. Reported-by: G Kranthi <[email protected]> Signed-off-by: Mengdong Lin <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 17e593e commit 1a7dd6e

File tree

1 file changed

+87
-76
lines changed

1 file changed

+87
-76
lines changed

sound/soc/soc-topology.c

Lines changed: 87 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -486,21 +486,24 @@ static void remove_widget(struct snd_soc_component *comp,
486486
dobj->ops->widget_unload(comp, dobj);
487487

488488
/*
489-
* Dynamic Widgets either have 1 enum kcontrol or 1..N mixers.
489+
* Dynamic Widgets either have 1..N enum kcontrols or mixers.
490490
* The enum may either have an array of values or strings.
491491
*/
492492
if (dobj->widget.kcontrol_enum) {
493493
/* enumerated widget mixer */
494-
struct soc_enum *se =
495-
(struct soc_enum *)w->kcontrols[0]->private_value;
494+
for (i = 0; i < w->num_kcontrols; i++) {
495+
struct snd_kcontrol *kcontrol = w->kcontrols[i];
496+
struct soc_enum *se =
497+
(struct soc_enum *)kcontrol->private_value;
496498

497-
snd_ctl_remove(card, w->kcontrols[0]);
499+
snd_ctl_remove(card, kcontrol);
498500

499-
kfree(se->dobj.control.dvalues);
500-
for (i = 0; i < se->items; i++)
501-
kfree(se->dobj.control.dtexts[i]);
501+
kfree(se->dobj.control.dvalues);
502+
for (i = 0; i < se->items; i++)
503+
kfree(se->dobj.control.dtexts[i]);
502504

503-
kfree(se);
505+
kfree(se);
506+
}
504507
kfree(w->kcontrol_news);
505508
} else {
506509
/* non enumerated widget mixer */
@@ -1256,98 +1259,105 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
12561259
}
12571260

12581261
static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
1259-
struct soc_tplg *tplg)
1262+
struct soc_tplg *tplg, int num_kcontrols)
12601263
{
12611264
struct snd_kcontrol_new *kc;
12621265
struct snd_soc_tplg_enum_control *ec;
12631266
struct soc_enum *se;
1264-
int i, err;
1265-
1266-
ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
1267-
tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1268-
ec->priv.size);
1269-
1270-
/* validate kcontrol */
1271-
if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1272-
SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1273-
return NULL;
1267+
int i, j, err;
12741268

1275-
kc = kzalloc(sizeof(*kc), GFP_KERNEL);
1269+
kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
12761270
if (kc == NULL)
12771271
return NULL;
12781272

1279-
se = kzalloc(sizeof(*se), GFP_KERNEL);
1280-
if (se == NULL)
1281-
goto err;
1273+
for (i = 0; i < num_kcontrols; i++) {
1274+
ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
1275+
/* validate kcontrol */
1276+
if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1277+
SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1278+
return NULL;
1279+
1280+
se = kzalloc(sizeof(*se), GFP_KERNEL);
1281+
if (se == NULL)
1282+
goto err;
12821283

1283-
dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
1284-
ec->hdr.name);
1284+
dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
1285+
ec->hdr.name);
12851286

1286-
kc->name = ec->hdr.name;
1287-
kc->private_value = (long)se;
1288-
kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1289-
kc->access = ec->hdr.access;
1287+
kc[i].name = ec->hdr.name;
1288+
kc[i].private_value = (long)se;
1289+
kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1290+
kc[i].access = ec->hdr.access;
12901291

1291-
/* we only support FL/FR channel mapping atm */
1292-
se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
1293-
se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL);
1294-
se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR);
1292+
/* we only support FL/FR channel mapping atm */
1293+
se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
1294+
se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
1295+
SNDRV_CHMAP_FL);
1296+
se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
1297+
SNDRV_CHMAP_FR);
12951298

1296-
se->items = ec->items;
1297-
se->mask = ec->mask;
1298-
se->dobj.index = tplg->index;
1299+
se->items = ec->items;
1300+
se->mask = ec->mask;
1301+
se->dobj.index = tplg->index;
12991302

1300-
switch (ec->hdr.ops.info) {
1301-
case SND_SOC_TPLG_CTL_ENUM_VALUE:
1302-
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1303-
err = soc_tplg_denum_create_values(se, ec);
1304-
if (err < 0) {
1305-
dev_err(tplg->dev, "ASoC: could not create values for %s\n",
1306-
ec->hdr.name);
1303+
switch (ec->hdr.ops.info) {
1304+
case SND_SOC_TPLG_CTL_ENUM_VALUE:
1305+
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1306+
err = soc_tplg_denum_create_values(se, ec);
1307+
if (err < 0) {
1308+
dev_err(tplg->dev, "ASoC: could not create values for %s\n",
1309+
ec->hdr.name);
1310+
goto err_se;
1311+
}
1312+
/* fall through to create texts */
1313+
case SND_SOC_TPLG_CTL_ENUM:
1314+
case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1315+
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1316+
err = soc_tplg_denum_create_texts(se, ec);
1317+
if (err < 0) {
1318+
dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
1319+
ec->hdr.name);
1320+
goto err_se;
1321+
}
1322+
break;
1323+
default:
1324+
dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
1325+
ec->hdr.ops.info, ec->hdr.name);
13071326
goto err_se;
13081327
}
1309-
/* fall through to create texts */
1310-
case SND_SOC_TPLG_CTL_ENUM:
1311-
case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1312-
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1313-
err = soc_tplg_denum_create_texts(se, ec);
1328+
1329+
/* map io handlers */
1330+
err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc[i], tplg);
1331+
if (err) {
1332+
soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1333+
goto err_se;
1334+
}
1335+
1336+
/* pass control to driver for optional further init */
1337+
err = soc_tplg_init_kcontrol(tplg, &kc[i],
1338+
(struct snd_soc_tplg_ctl_hdr *)ec);
13141339
if (err < 0) {
1315-
dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
1340+
dev_err(tplg->dev, "ASoC: failed to init %s\n",
13161341
ec->hdr.name);
13171342
goto err_se;
13181343
}
1319-
break;
1320-
default:
1321-
dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
1322-
ec->hdr.ops.info, ec->hdr.name);
1323-
goto err_se;
1324-
}
13251344

1326-
/* map io handlers */
1327-
err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
1328-
if (err) {
1329-
soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1330-
goto err_se;
1331-
}
1332-
1333-
/* pass control to driver for optional further init */
1334-
err = soc_tplg_init_kcontrol(tplg, kc,
1335-
(struct snd_soc_tplg_ctl_hdr *)ec);
1336-
if (err < 0) {
1337-
dev_err(tplg->dev, "ASoC: failed to init %s\n",
1338-
ec->hdr.name);
1339-
goto err_se;
1345+
tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1346+
ec->priv.size);
13401347
}
13411348

13421349
return kc;
13431350

13441351
err_se:
1345-
/* free values and texts */
1346-
kfree(se->dobj.control.dvalues);
1347-
for (i = 0; i < ec->items; i++)
1348-
kfree(se->dobj.control.dtexts[i]);
1352+
for (; i >= 0; i--) {
1353+
/* free values and texts */
1354+
se = (struct soc_enum *)kc[i].private_value;
1355+
kfree(se->dobj.control.dvalues);
1356+
for (j = 0; j < ec->items; j++)
1357+
kfree(se->dobj.control.dtexts[j]);
13491358

1350-
kfree(se);
1359+
kfree(se);
1360+
}
13511361
err:
13521362
kfree(kc);
13531363

@@ -1499,9 +1509,10 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
14991509
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
15001510
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
15011511
template.dobj.widget.kcontrol_enum = 1;
1502-
template.num_kcontrols = 1;
1512+
template.num_kcontrols = w->num_kcontrols;
15031513
template.kcontrol_news =
1504-
soc_tplg_dapm_widget_denum_create(tplg);
1514+
soc_tplg_dapm_widget_denum_create(tplg,
1515+
template.num_kcontrols);
15051516
if (!template.kcontrol_news) {
15061517
ret = -ENOMEM;
15071518
goto hdr_err;

0 commit comments

Comments
 (0)