aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-17 19:20:33 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-21 14:34:48 -0500
commitf831b055ececb3172f7fe498db5ca1fb43ff644d (patch)
treecf0209339df80b83065986fe4db7f1ad61b9a154
parent71d08516b80638a69d5efea4e8cb832c053f9dd9 (diff)
ASoC: core: Add support for masking out parts of coefficient blocks
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> Acked-by: Liam Girdwood <lrg@ti.com>
-rw-r--r--include/sound/soc.h9
-rw-r--r--sound/soc/soc-core.c74
2 files changed, 76 insertions, 7 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 3e9cae001eab..82bd773f8ab1 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -192,6 +192,14 @@
192 ((unsigned long)&(struct soc_bytes) \ 192 ((unsigned long)&(struct soc_bytes) \
193 {.base = xbase, .num_regs = xregs }) } 193 {.base = xbase, .num_regs = xregs }) }
194 194
195#define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \
196{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
197 .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
198 .put = snd_soc_bytes_put, .private_value = \
199 ((unsigned long)&(struct soc_bytes) \
200 {.base = xbase, .num_regs = xregs, \
201 .mask = xmask }) }
202
195/* 203/*
196 * Simplified versions of above macros, declaring a struct and calculating 204 * Simplified versions of above macros, declaring a struct and calculating
197 * ARRAY_SIZE internally 205 * ARRAY_SIZE internally
@@ -904,6 +912,7 @@ struct soc_mixer_control {
904struct soc_bytes { 912struct soc_bytes {
905 int base; 913 int base;
906 int num_regs; 914 int num_regs;
915 u32 mask;
907}; 916};
908 917
909/* enumerated kcontrol */ 918/* enumerated kcontrol */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index a9786ab70504..fc0fd3485e7d 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2763,6 +2763,25 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
2763 else 2763 else
2764 ret = -EINVAL; 2764 ret = -EINVAL;
2765 2765
2766 /* Hide any masked bytes to ensure consistent data reporting */
2767 if (ret == 0 && params->mask) {
2768 switch (codec->val_bytes) {
2769 case 1:
2770 ucontrol->value.bytes.data[0] &= ~params->mask;
2771 break;
2772 case 2:
2773 ((u16 *)(&ucontrol->value.bytes.data))[0]
2774 &= ~params->mask;
2775 break;
2776 case 4:
2777 ((u32 *)(&ucontrol->value.bytes.data))[0]
2778 &= ~params->mask;
2779 break;
2780 default:
2781 return -EINVAL;
2782 }
2783 }
2784
2766 return ret; 2785 return ret;
2767} 2786}
2768EXPORT_SYMBOL_GPL(snd_soc_bytes_get); 2787EXPORT_SYMBOL_GPL(snd_soc_bytes_get);
@@ -2772,14 +2791,55 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
2772{ 2791{
2773 struct soc_bytes *params = (void *)kcontrol->private_value; 2792 struct soc_bytes *params = (void *)kcontrol->private_value;
2774 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 2793 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2775 int ret; 2794 int ret, len;
2795 unsigned int val;
2796 void *data;
2776 2797
2777 if (codec->using_regmap) 2798 if (!codec->using_regmap)
2778 ret = regmap_raw_write(codec->control_data, params->base, 2799 return -EINVAL;
2779 ucontrol->value.bytes.data, 2800
2780 params->num_regs * codec->val_bytes); 2801 data = ucontrol->value.bytes.data;
2781 else 2802 len = params->num_regs * codec->val_bytes;
2782 ret = -EINVAL; 2803
2804 /*
2805 * If we've got a mask then we need to preserve the register
2806 * bits. We shouldn't modify the incoming data so take a
2807 * copy.
2808 */
2809 if (params->mask) {
2810 ret = regmap_read(codec->control_data, params->base, &val);
2811 if (ret != 0)
2812 return ret;
2813
2814 val &= params->mask;
2815
2816 data = kmemdup(data, len, GFP_KERNEL);
2817 if (!data)
2818 return -ENOMEM;
2819
2820 switch (codec->val_bytes) {
2821 case 1:
2822 ((u8 *)data)[0] &= ~params->mask;
2823 ((u8 *)data)[0] |= val;
2824 break;
2825 case 2:
2826 ((u16 *)data)[0] &= cpu_to_be16(~params->mask);
2827 ((u16 *)data)[0] |= cpu_to_be16(val);
2828 break;
2829 case 4:
2830 ((u32 *)data)[0] &= cpu_to_be32(~params->mask);
2831 ((u32 *)data)[0] |= cpu_to_be32(val);
2832 break;
2833 default:
2834 return -EINVAL;
2835 }
2836 }
2837
2838 ret = regmap_raw_write(codec->control_data, params->base,
2839 data, len);
2840
2841 if (params->mask)
2842 kfree(data);
2783 2843
2784 return ret; 2844 return ret;
2785} 2845}