diff options
-rw-r--r-- | include/sound/soc.h | 9 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 74 |
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 { | |||
904 | struct soc_bytes { | 912 | struct 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 | } |
2768 | EXPORT_SYMBOL_GPL(snd_soc_bytes_get); | 2787 | EXPORT_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 | } |