Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 305653
b: refs/heads/master
c: 4183eed
h: refs/heads/master
i:
  305651: a75c13c
v: v3
  • Loading branch information
Kristoffer KARLSSON authored and Mark Brown committed Apr 23, 2012
1 parent 6693470 commit 7ce0438
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c1a4ecd921229a410b9a71cb7877250e85c26c1c
refs/heads/master: 4183eed288f31c3b9142476915e842f879f36b8e
22 changes: 21 additions & 1 deletion trunk/include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@
{.base = xbase, .num_regs = xregs, \
.mask = xmask }) }

#define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \
xmin, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_xr_sx, .get = snd_soc_get_xr_sx, \
.put = snd_soc_put_xr_sx, \
.private_value = (unsigned long)&(struct soc_mreg_control) \
{.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
.invert = xinvert, .min = xmin, .max = xmax} }

/*
* Simplified versions of above macros, declaring a struct and calculating
* ARRAY_SIZE internally
Expand Down Expand Up @@ -446,7 +455,12 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);

int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);

/**
* struct snd_soc_reg_access - Describes whether a given register is
Expand Down Expand Up @@ -932,6 +946,12 @@ struct soc_bytes {
u32 mask;
};

/* multi register control */
struct soc_mreg_control {
long min, max;
unsigned int regbase, regcount, nbits, invert;
};

/* enumerated kcontrol */
struct soc_enum {
unsigned short reg;
Expand Down
118 changes: 118 additions & 0 deletions trunk/sound/soc/soc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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<<regwshift)-1;
unsigned int invert = mc->invert;
unsigned long mask = (1UL<<mc->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<<regwshift)-1;
unsigned int invert = mc->invert;
unsigned long mask = (1UL<<mc->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
Expand Down

0 comments on commit 7ce0438

Please sign in to comment.