ASoC: dapm: Add support for virtual mixer controls

This patch adds support for virtual DAPM mixer controls. They are similar to
virtual DAPM enums. There is no hardware register backing the control, so
changing the control's value wont have any direct effect on the hardware. But it
still influences the DAPM graph by causing the path it sits on to be connected
or disconnected. This in turn can cause power changes for some of the widgets on
the DAPM graph, which will then modify the hardware state.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Tested-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
Lars-Peter Clausen 2013-10-06 13:43:49 +02:00 коммит произвёл Mark Brown
Родитель da83fea612
Коммит 249ce1387b
3 изменённых файлов: 33 добавлений и 19 удалений

Просмотреть файл

@ -286,6 +286,8 @@ struct device;
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
#define SOC_DAPM_SINGLE_VIRT(xname, max) \
SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0)
#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
@ -300,6 +302,8 @@ struct device;
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
#define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \
SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array)
#define SOC_DAPM_ENUM(xname, xenum) \ #define SOC_DAPM_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \ .info = snd_soc_info_enum_double, \

Просмотреть файл

@ -1088,7 +1088,8 @@ struct snd_soc_pcm_runtime {
/* mixer control */ /* mixer control */
struct soc_mixer_control { struct soc_mixer_control {
int min, max, platform_max; int min, max, platform_max;
unsigned int reg, rreg, shift, rshift; int reg, rreg;
unsigned int shift, rshift;
unsigned int invert:1; unsigned int invert:1;
unsigned int autodisable:1; unsigned int autodisable:1;
}; };

Просмотреть файл

@ -499,18 +499,22 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
int val; int val;
struct soc_mixer_control *mc = (struct soc_mixer_control *) struct soc_mixer_control *mc = (struct soc_mixer_control *)
w->kcontrol_news[i].private_value; w->kcontrol_news[i].private_value;
unsigned int reg = mc->reg; int reg = mc->reg;
unsigned int shift = mc->shift; unsigned int shift = mc->shift;
int max = mc->max; int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1; unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert; unsigned int invert = mc->invert;
val = soc_widget_read(w, reg); if (reg != SND_SOC_NOPM) {
val = (val >> shift) & mask; val = soc_widget_read(w, reg);
if (invert) val = (val >> shift) & mask;
val = max - val; if (invert)
val = max - val;
p->connect = !!val;
} else {
p->connect = 0;
}
p->connect = !!val;
} }
break; break;
case snd_soc_dapm_mux: { case snd_soc_dapm_mux: {
@ -2792,7 +2796,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = codec->card; struct snd_soc_card *card = codec->card;
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; int reg = mc->reg;
unsigned int shift = mc->shift; unsigned int shift = mc->shift;
int max = mc->max; int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1; unsigned int mask = (1 << fls(max)) - 1;
@ -2805,7 +2809,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
kcontrol->id.name); kcontrol->id.name);
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
if (dapm_kcontrol_is_powered(kcontrol)) if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM)
val = (snd_soc_read(codec, reg) >> shift) & mask; val = (snd_soc_read(codec, reg) >> shift) & mask;
else else
val = dapm_kcontrol_get_value(kcontrol); val = dapm_kcontrol_get_value(kcontrol);
@ -2836,7 +2840,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = codec->card; struct snd_soc_card *card = codec->card;
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; int reg = mc->reg;
unsigned int shift = mc->shift; unsigned int shift = mc->shift;
int max = mc->max; int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1; unsigned int mask = (1 << fls(max)) - 1;
@ -2858,19 +2862,24 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
dapm_kcontrol_set_value(kcontrol, val); change = dapm_kcontrol_set_value(kcontrol, val);
mask = mask << shift; if (reg != SND_SOC_NOPM) {
val = val << shift; mask = mask << shift;
val = val << shift;
change = snd_soc_test_bits(codec, reg, mask, val);
}
change = snd_soc_test_bits(codec, reg, mask, val);
if (change) { if (change) {
update.kcontrol = kcontrol; if (reg != SND_SOC_NOPM) {
update.reg = reg; update.kcontrol = kcontrol;
update.mask = mask; update.reg = reg;
update.val = val; update.mask = mask;
update.val = val;
card->update = &update; card->update = &update;
}
soc_dapm_mixer_update_power(card, kcontrol, connect); soc_dapm_mixer_update_power(card, kcontrol, connect);