aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-core.c
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 /sound/soc/soc-core.c
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>
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r--sound/soc/soc-core.c74
1 files changed, 67 insertions, 7 deletions
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}