Commit fafd2176 authored by Stephen Warren's avatar Stephen Warren Committed by Mark Brown

ASoC: Store a list of widgets in a DAPM mux/mixer kcontrol

A future change will allow multiple widgets to be affected by the same
control. For example, a single register bit that controls separate muxes
in both the L and R audio paths.

This change updates the code that handles relevant controls to be able
to iterate over a list of affected widgets. Note that only the put
functions need significant modification to implement the iteration; the
get functions do not need to iterate, nor unify the results, since all
affected widgets reference the same kcontrol.

When creating the list of widgets, always create a 1-sized list, since
the control sharing is not implemented in this change.
Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarLiam Girdwood <lrg@ti.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent fad59888
...@@ -518,4 +518,10 @@ struct snd_soc_dapm_context { ...@@ -518,4 +518,10 @@ struct snd_soc_dapm_context {
#endif #endif
}; };
/* A list of widgets associated with an object, typically a snd_kcontrol */
struct snd_soc_dapm_widget_list {
int num_widgets;
struct snd_soc_dapm_widget *widgets[0];
};
#endif #endif
...@@ -333,6 +333,8 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, ...@@ -333,6 +333,8 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_path *path; struct snd_soc_dapm_path *path;
struct snd_card *card = dapm->card->snd_card; struct snd_card *card = dapm->card->snd_card;
const char *prefix; const char *prefix;
struct snd_soc_dapm_widget_list *wlist;
size_t wlistsize;
if (dapm->codec) if (dapm->codec)
prefix = dapm->codec->name_prefix; prefix = dapm->codec->name_prefix;
...@@ -354,6 +356,18 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, ...@@ -354,6 +356,18 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
if (path->name != (char *)w->kcontrol_news[i].name) if (path->name != (char *)w->kcontrol_news[i].name)
continue; continue;
wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
sizeof(struct snd_soc_dapm_widget *),
wlist = kzalloc(wlistsize, GFP_KERNEL);
if (wlist == NULL) {
dev_err(dapm->dev,
"asoc: can't allocate widget list for %s\n",
w->name);
return -ENOMEM;
}
wlist->num_widgets = 1;
wlist->widgets[0] = w;
/* add dapm control with long name. /* add dapm control with long name.
* for dapm_mixer this is the concatenation of the * for dapm_mixer this is the concatenation of the
* mixer and kcontrol name. * mixer and kcontrol name.
...@@ -366,8 +380,10 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, ...@@ -366,8 +380,10 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
path->long_name = kmalloc(name_len, GFP_KERNEL); path->long_name = kmalloc(name_len, GFP_KERNEL);
if (path->long_name == NULL) if (path->long_name == NULL) {
kfree(wlist);
return -ENOMEM; return -ENOMEM;
}
switch (w->id) { switch (w->id) {
default: default:
...@@ -389,13 +405,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, ...@@ -389,13 +405,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
path->long_name[name_len - 1] = '\0'; path->long_name[name_len - 1] = '\0';
path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w, path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
path->long_name, prefix); wlist, path->long_name,
prefix);
ret = snd_ctl_add(card, path->kcontrol); ret = snd_ctl_add(card, path->kcontrol);
if (ret < 0) { if (ret < 0) {
dev_err(dapm->dev, dev_err(dapm->dev,
"asoc: failed to add dapm kcontrol %s: %d\n", "asoc: failed to add dapm kcontrol %s: %d\n",
path->long_name, ret); path->long_name, ret);
kfree(wlist);
kfree(path->long_name); kfree(path->long_name);
path->long_name = NULL; path->long_name = NULL;
return ret; return ret;
...@@ -416,12 +434,25 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, ...@@ -416,12 +434,25 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
const char *prefix; const char *prefix;
size_t prefix_len; size_t prefix_len;
int ret = 0; int ret = 0;
struct snd_soc_dapm_widget_list *wlist;
size_t wlistsize;
if (!w->num_kcontrols) { if (!w->num_kcontrols) {
dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name); dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name);
return -EINVAL; return -EINVAL;
} }
wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
sizeof(struct snd_soc_dapm_widget *),
wlist = kzalloc(wlistsize, GFP_KERNEL);
if (wlist == NULL) {
dev_err(dapm->dev,
"asoc: can't allocate widget list for %s\n", w->name);
return -ENOMEM;
}
wlist->num_widgets = 1;
wlist->widgets[0] = w;
if (dapm->codec) if (dapm->codec)
prefix = dapm->codec->name_prefix; prefix = dapm->codec->name_prefix;
else else
...@@ -436,8 +467,8 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, ...@@ -436,8 +467,8 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
* process but we're also using the same prefix for widgets so * process but we're also using the same prefix for widgets so
* cut the prefix off the front of the widget name. * cut the prefix off the front of the widget name.
*/ */
kcontrol = snd_soc_cnew(&w->kcontrol_news[0], w, w->name + prefix_len, kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
prefix); w->name + prefix_len, prefix);
ret = snd_ctl_add(card, kcontrol); ret = snd_ctl_add(card, kcontrol);
if (ret < 0) if (ret < 0)
...@@ -452,6 +483,7 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, ...@@ -452,6 +483,7 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
err: err:
dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name); dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name);
kfree(wlist);
return ret; return ret;
} }
...@@ -1818,7 +1850,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); ...@@ -1818,7 +1850,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct soc_mixer_control *mc = struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg; unsigned int reg = mc->reg;
...@@ -1857,7 +1890,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); ...@@ -1857,7 +1890,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct soc_mixer_control *mc = struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg; unsigned int reg = mc->reg;
...@@ -1868,6 +1903,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -1868,6 +1903,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val; unsigned int val;
int connect, change; int connect, change;
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int wi;
val = (ucontrol->value.integer.value[0] & mask); val = (ucontrol->value.integer.value[0] & mask);
...@@ -1876,31 +1912,36 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -1876,31 +1912,36 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mask = mask << shift; mask = mask << shift;
val = val << shift; val = val << shift;
mutex_lock(&widget->codec->mutex); if (val)
widget->value = val; /* new connection */
connect = invert ? 0 : 1;
else
/* old connection must be powered down */
connect = invert ? 1 : 0;
mutex_lock(&codec->mutex);
change = snd_soc_test_bits(widget->codec, reg, mask, val); change = snd_soc_test_bits(widget->codec, reg, mask, val);
if (change) { if (change) {
if (val) for (wi = 0; wi < wlist->num_widgets; wi++) {
/* new connection */ widget = wlist->widgets[wi];
connect = invert ? 0:1;
else
/* old connection must be powered down */
connect = invert ? 1:0;
update.kcontrol = kcontrol; widget->value = val;
update.widget = widget;
update.reg = reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
dapm_mixer_update_power(widget, kcontrol, connect); update.kcontrol = kcontrol;
update.widget = widget;
update.reg = reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
widget->dapm->update = NULL; dapm_mixer_update_power(widget, kcontrol, connect);
widget->dapm->update = NULL;
}
} }
mutex_unlock(&widget->codec->mutex); mutex_unlock(&codec->mutex);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
...@@ -1917,7 +1958,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); ...@@ -1917,7 +1958,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, bitmask; unsigned int val, bitmask;
...@@ -1945,11 +1987,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); ...@@ -1945,11 +1987,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change; unsigned int val, mux, change;
unsigned int mask, bitmask; unsigned int mask, bitmask;
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int wi;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1) for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
; ;
...@@ -1965,22 +2010,29 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, ...@@ -1965,22 +2010,29 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
mask |= (bitmask - 1) << e->shift_r; mask |= (bitmask - 1) << e->shift_r;
} }
mutex_lock(&widget->codec->mutex); mutex_lock(&codec->mutex);
widget->value = val;
change = snd_soc_test_bits(widget->codec, e->reg, mask, val); change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
for (wi = 0; wi < wlist->num_widgets; wi++) {
widget = wlist->widgets[wi];
update.kcontrol = kcontrol; widget->value = val;
update.widget = widget;
update.reg = e->reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
dapm_mux_update_power(widget, kcontrol, change, mux, e); update.kcontrol = kcontrol;
update.widget = widget;
update.reg = e->reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
widget->dapm->update = NULL; dapm_mux_update_power(widget, kcontrol, change, mux, e);
mutex_unlock(&widget->codec->mutex); widget->dapm->update = NULL;
}
}
mutex_unlock(&codec->mutex);
return change; return change;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
...@@ -1995,7 +2047,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); ...@@ -1995,7 +2047,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
ucontrol->value.enumerated.item[0] = widget->value; ucontrol->value.enumerated.item[0] = widget->value;
...@@ -2013,22 +2066,33 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); ...@@ -2013,22 +2066,33 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct soc_enum *e = struct soc_enum *e =
(struct soc_enum *)kcontrol->private_value; (struct soc_enum *)kcontrol->private_value;
int change; int change;
int ret = 0; int ret = 0;
int wi;
if (ucontrol->value.enumerated.item[0] >= e->max) if (ucontrol->value.enumerated.item[0] >= e->max)
return -EINVAL; return -EINVAL;
mutex_lock(&widget->codec->mutex); mutex_lock(&codec->mutex);
change = widget->value != ucontrol->value.enumerated.item[0]; change = widget->value != ucontrol->value.enumerated.item[0];
widget->value = ucontrol->value.enumerated.item[0]; if (change) {
dapm_mux_update_power(widget, kcontrol, change, widget->value, e); for (wi = 0; wi < wlist->num_widgets; wi++) {
widget = wlist->widgets[wi];
widget->value = ucontrol->value.enumerated.item[0];
dapm_mux_update_power(widget, kcontrol, change,
widget->value, e);
}
}
mutex_unlock(&widget->codec->mutex); mutex_unlock(&codec->mutex);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
...@@ -2049,7 +2113,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); ...@@ -2049,7 +2113,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg_val, val, mux; unsigned int reg_val, val, mux;
...@@ -2089,11 +2154,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); ...@@ -2089,11 +2154,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change; unsigned int val, mux, change;
unsigned int mask; unsigned int mask;
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int wi;
if (ucontrol->value.enumerated.item[0] > e->max - 1) if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL; return -EINVAL;
...@@ -2107,22 +2175,29 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, ...@@ -2107,22 +2175,29 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
mask |= e->mask << e->shift_r; mask |= e->mask << e->shift_r;
} }
mutex_lock(&widget->codec->mutex); mutex_lock(&codec->mutex);
widget->value = val;
change = snd_soc_test_bits(widget->codec, e->reg, mask, val); change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
for (wi = 0; wi < wlist->num_widgets; wi++) {
widget = wlist->widgets[wi];
update.kcontrol = kcontrol; widget->value = val;
update.widget = widget;
update.reg = e->reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
dapm_mux_update_power(widget, kcontrol, change, mux, e); update.kcontrol = kcontrol;
update.widget = widget;
update.reg = e->reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
widget->dapm->update = NULL; dapm_mux_update_power(widget, kcontrol, change, mux, e);
mutex_unlock(&widget->codec->mutex); widget->dapm->update = NULL;
}
}
mutex_unlock(&codec->mutex);
return change; return change;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
......
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