[alsa-devel] [PATCH 0/3] Coefficient configuration support
This series is only compile tested as yet, I'll probably get a chance to test it shortly - it should work out so hopefully the review can overlap usefully with the testing.
Mark Brown (3): ASoC: core: Add SND_SOC_BYTES control for coefficient blocks ASoC: core: Add support for masking out parts of coefficient blocks ASoC: wm5100: Add DRC coefficient configuration
include/sound/soc.h | 27 +++++++++++ sound/soc/codecs/wm5100.c | 2 + sound/soc/soc-core.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 0 deletions(-)
Allow devices to export blocks of registers to the application layer, intended for use for reading and writing coefficient data which can't usefully be worked with by the kernel at runtime (for example, due to requiring complex and expensive calculations or being the results of callibration procedures). Currently drivers are using platform data to provide configurations for coefficient blocks which isn't at all convenient for runtime management or configuration development.
Currently only devices using regmap are supported, an error will be generated for any attempt to work with a byte control on a non-regmap device. There's no fundamental block to other devices so support could be added if required.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/soc.h | 18 ++++++++++++++++++ sound/soc/soc-core.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 0 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e16d6e..3e9cae0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -185,6 +185,12 @@ .rreg = xreg_right, .shift = xshift, \ .min = xmin, .max = xmax} }
+#define SND_SOC_BYTES(xname, xbase, xregs) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ + .put = snd_soc_bytes_put, .private_value = \ + ((unsigned long)&(struct soc_bytes) \ + {.base = xbase, .num_regs = xregs }) }
/* * Simplified versions of above macros, declaring a struct and calculating @@ -413,6 +419,13 @@ int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +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); +
/** * struct snd_soc_reg_access - Describes whether a given register is @@ -888,6 +901,11 @@ struct soc_mixer_control { unsigned int reg, rreg, shift, rshift, invert; };
+struct soc_bytes { + int base; + int num_regs; +}; + /* enumerated kcontrol */ struct soc_enum { unsigned short reg; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 14bdaee..ed9138e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2730,6 +2730,55 @@ int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
+int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_bytes *params = (void *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = params->num_regs * codec->val_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_info); + +int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int ret; + + if (codec->using_regmap) + ret = regmap_raw_read(codec->control_data, params->base, + ucontrol->value.bytes.data, + params->num_regs * codec->val_bytes); + else + ret = -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_get); + +int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int ret; + + if (codec->using_regmap) + ret = regmap_raw_write(codec->control_data, params->base, + ucontrol->value.bytes.data, + params->num_regs * codec->val_bytes); + else + ret = -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_put); + /** * snd_soc_dai_set_sysclk - configure DAI system or master clock. * @dai: DAI
Chip designers frequently include things like the enable and disable controls for algorithms in the register blocks which also hold the coefficients. Since it's desirable to split out the enable/disable control from userspace the plain SND_SOC_BYTES() isn't optimal for these devices.
Add a SND_SOC_BYTES_MASK() which allows a bitmask from the first word of the block to be excluded from the control. This supports the needs of devices I've looked at and lets us have a reasonably simple API. Further controls can be added in future if that's needed.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/soc.h | 9 ++++++ sound/soc/soc-core.c | 75 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 77 insertions(+), 7 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 3e9cae0..82bd773 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -192,6 +192,14 @@ ((unsigned long)&(struct soc_bytes) \ {.base = xbase, .num_regs = xregs }) }
+#define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ + .put = snd_soc_bytes_put, .private_value = \ + ((unsigned long)&(struct soc_bytes) \ + {.base = xbase, .num_regs = xregs, \ + .mask = xmask }) } + /* * Simplified versions of above macros, declaring a struct and calculating * ARRAY_SIZE internally @@ -904,6 +912,7 @@ struct soc_mixer_control { struct soc_bytes { int base; int num_regs; + u32 mask; };
/* enumerated kcontrol */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ed9138e..bb01c02 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2757,6 +2757,25 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, else ret = -EINVAL;
+ /* Hide any masked bytes to ensure consistent data reporting */ + if (ret == 0 && params->mask) { + switch (codec->val_bytes) { + case 1: + ucontrol->value.bytes.data[0] &= ~params->mask; + break; + case 2: + ((u16 *)(&ucontrol->value.bytes.data))[0] + &= ~params->mask; + break; + case 4: + ((u32 *)(&ucontrol->value.bytes.data))[0] + &= ~params->mask; + break; + default: + return -EINVAL; + } + } + return ret; } EXPORT_SYMBOL_GPL(snd_soc_bytes_get); @@ -2766,14 +2785,56 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, { struct soc_bytes *params = (void *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int ret; + int ret, len; + unsigned int val; + void *data;
- if (codec->using_regmap) - ret = regmap_raw_write(codec->control_data, params->base, - ucontrol->value.bytes.data, - params->num_regs * codec->val_bytes); - else - ret = -EINVAL; + if (!codec->using_regmap) + return -EINVAL; + + len = params->num_regs * codec->val_bytes; + + /* + * If we've got a mask then we need to preserve the register + * bits. We shouldn't modify the incoming data so take a + * copy. + */ + if (params->mask) { + ret = regmap_read(codec->control_data, params->base, &val); + if (ret != 0) + return ret; + + val |= ~params->mask; + + data = kmalloc(len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + switch (codec->val_bytes) { + case 1: + ((u8 *)data)[0] &= ~params->mask; + ((u8 *)data)[0] |= val; + break; + case 2: + ((u16 *)data)[0] &= ~params->mask; + ((u16 *)data)[0] |= val; + break; + case 4: + ((u32 *)data)[0] &= ~params->mask; + ((u32 *)data)[0] |= val; + break; + default: + return -EINVAL; + } + } else { + data = ucontrol->value.bytes.data; + } + + ret = regmap_raw_write(codec->control_data, params->base, + data, len); + + if (params->mask) + kfree(data);
return ret; }
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm5100.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 74e9372..7fbcd6d 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -744,6 +744,8 @@ WM5100_MIXER_CONTROLS("EQ4", WM5100_EQ4MIX_INPUT_1_SOURCE),
WM5100_MIXER_CONTROLS("DRC1L", WM5100_DRC1LMIX_INPUT_1_SOURCE), WM5100_MIXER_CONTROLS("DRC1R", WM5100_DRC1RMIX_INPUT_1_SOURCE), +SND_SOC_BYTES_MASK("DRC", WM5100_DRC1_CTRL1, 5, + WM5100_DRCL_ENA | WM5100_DRCR_ENA),
WM5100_MIXER_CONTROLS("LHPF1", WM5100_HPLP1MIX_INPUT_1_SOURCE), WM5100_MIXER_CONTROLS("LHPF2", WM5100_HPLP2MIX_INPUT_1_SOURCE),
On Fri, 2012-02-17 at 16:49 -0800, Mark Brown wrote:
This series is only compile tested as yet, I'll probably get a chance to test it shortly - it should work out so hopefully the review can overlap usefully with the testing.
Mark Brown (3): ASoC: core: Add SND_SOC_BYTES control for coefficient blocks ASoC: core: Add support for masking out parts of coefficient blocks ASoC: wm5100: Add DRC coefficient configuration
include/sound/soc.h | 27 +++++++++++ sound/soc/codecs/wm5100.c | 2 + sound/soc/soc-core.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 0 deletions(-)
All
Acked-by: Liam Girdwood lrg@ti.com
participants (2)
-
Liam Girdwood
-
Mark Brown