aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}