From 4183eed288f31c3b9142476915e842f879f36b8e Mon Sep 17 00:00:00 2001 From: Kristoffer KARLSSON Date: Fri, 20 Apr 2012 11:32:13 +0200 Subject: ASoC: core: Add signed multi register control Added control type that can span multiple consecutive codec registers forming a single signed value in a MSB/LSB manner. The control dynamically adjusts to the register word size configured in driver. Added convenience macro. SOC_SINGLE_XR_SX Added accessor implementations. snd_soc_info_xr_sx snd_soc_get_xr_sx snd_soc_put_xr_sx Signed-off-by: Kristoffer KARLSSON Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5d308e92f9b..01bbd86cf27 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2891,6 +2891,124 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_bytes_put); +/** + * snd_soc_info_xr_sx - signed multi register info callback + * @kcontrol: mreg control + * @uinfo: control element information + * + * Callback to provide information of a control that can + * span multiple codec registers which together + * forms a single signed value in a MSB/LSB manner. + * + * Returns 0 for success. + */ +int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = mc->min; + uinfo->value.integer.max = mc->max; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); + +/** + * snd_soc_get_xr_sx - signed multi register get callback + * @kcontrol: mreg control + * @ucontrol: control element information + * + * Callback to get the value of a control that can span + * multiple codec registers which together forms a single + * signed value in a MSB/LSB manner. The control supports + * specifying total no of bits used to allow for bitfields + * across the multiple codec registers. + * + * Returns 0 for success. + */ +int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int regbase = mc->regbase; + unsigned int regcount = mc->regcount; + unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE; + unsigned int regwmask = (1<invert; + unsigned long mask = (1UL<nbits)-1; + long min = mc->min; + long max = mc->max; + long val = 0; + unsigned long regval; + unsigned int i; + + for (i = 0; i < regcount; i++) { + regval = snd_soc_read(codec, regbase+i) & regwmask; + val |= regval << (regwshift*(regcount-i-1)); + } + val &= mask; + if (min < 0 && val > max) + val |= ~mask; + if (invert) + val = max - val; + ucontrol->value.integer.value[0] = val; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); + +/** + * snd_soc_put_xr_sx - signed multi register get callback + * @kcontrol: mreg control + * @ucontrol: control element information + * + * Callback to set the value of a control that can span + * multiple codec registers which together forms a single + * signed value in a MSB/LSB manner. The control supports + * specifying total no of bits used to allow for bitfields + * across the multiple codec registers. + * + * Returns 0 for success. + */ +int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int regbase = mc->regbase; + unsigned int regcount = mc->regcount; + unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE; + unsigned int regwmask = (1<invert; + unsigned long mask = (1UL<nbits)-1; + long min = mc->min; + long max = mc->max; + long val = ucontrol->value.integer.value[0]; + unsigned int i, regval, regmask; + int err; + + if (invert) + val = max - val; + val &= mask; + for (i = 0; i < regcount; i++) { + regval = (val >> (regwshift*(regcount-i-1))) & regwmask; + regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; + err = snd_soc_update_bits_locked(codec, regbase+i, + regmask, regval); + if (err < 0) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); + /** * snd_soc_dai_set_sysclk - configure DAI system or master clock. * @dai: DAI -- cgit v1.2.3-70-g09d2