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

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
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -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
+131 −56
Original line number Original line Diff line number Diff line
@@ -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,
			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,


			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,


			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,
	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,
	 * 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,


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);
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);
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,
	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,11 +1912,6 @@ 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);
	widget->value = val;

	change = snd_soc_test_bits(widget->codec, reg, mask, val);
	if (change) {
	if (val)
	if (val)
		/* new connection */
		/* new connection */
		connect = invert ? 0 : 1;
		connect = invert ? 0 : 1;
@@ -1888,6 +1919,15 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
		/* old connection must be powered down */
		/* old connection must be powered down */
		connect = invert ? 1 : 0;
		connect = invert ? 1 : 0;


	mutex_lock(&codec->mutex);

	change = snd_soc_test_bits(widget->codec, reg, mask, val);
	if (change) {
		for (wi = 0; wi < wlist->num_widgets; wi++) {
			widget = wlist->widgets[wi];

			widget->value = val;

			update.kcontrol = kcontrol;
			update.kcontrol = kcontrol;
			update.widget = widget;
			update.widget = widget;
			update.reg = reg;
			update.reg = reg;
@@ -1899,8 +1939,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,


			widget->dapm->update = NULL;
			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);
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);
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,9 +2010,14 @@ 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];

			widget->value = val;


			update.kcontrol = kcontrol;
			update.kcontrol = kcontrol;
			update.widget = widget;
			update.widget = widget;
@@ -1979,8 +2029,10 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
			dapm_mux_update_power(widget, kcontrol, change, mux, e);
			dapm_mux_update_power(widget, kcontrol, change, mux, e);


			widget->dapm->update = NULL;
			widget->dapm->update = NULL;
		}
	}


	mutex_unlock(&widget->codec->mutex);
	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);
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);
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];
	if (change) {
		for (wi = 0; wi < wlist->num_widgets; wi++) {
			widget = wlist->widgets[wi];

			widget->value = ucontrol->value.enumerated.item[0];
			widget->value = ucontrol->value.enumerated.item[0];
	dapm_mux_update_power(widget, kcontrol, change, widget->value, e);


	mutex_unlock(&widget->codec->mutex);
			dapm_mux_update_power(widget, kcontrol, change,
					      widget->value, e);
		}
	}

	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);
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);
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,9 +2175,14 @@ 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];

			widget->value = val;


			update.kcontrol = kcontrol;
			update.kcontrol = kcontrol;
			update.widget = widget;
			update.widget = widget;
@@ -2121,8 +2194,10 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
			dapm_mux_update_power(widget, kcontrol, change, mux, e);
			dapm_mux_update_power(widget, kcontrol, change, mux, e);


			widget->dapm->update = NULL;
			widget->dapm->update = NULL;
		}
	}


	mutex_unlock(&widget->codec->mutex);
	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);