aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Thomson <Adam.Thomson@diasemi.com>2012-05-31 10:18:01 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-06-03 08:06:41 -0400
commit6c9d8cf6372ed2995a3d982f5c1f966e842101cc (patch)
tree1a71ce7d37e0183e7e01968e64774711d444d10e
parentbc92657a11c0982783979bbb84ceaf58ba222124 (diff)
ASoC: core: Add single controls with specified range of values
Control type added for cases where a specific range of values within a register are required for control. Added convenience macros: SOC_SINGLE_RANGE SOC_SINGLE_RANGE_TLV Added accessor implementations: snd_soc_info_volsw_range snd_soc_put_volsw_range snd_soc_get_volsw_range Signed-off-by: Michal Hajduk <Michal.Hajduk@diasemi.com> Signed-off-by: Adam Thomson <Adam.Thomson@diasemi.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--include/sound/soc.h23
-rw-r--r--sound/soc/soc-core.c98
2 files changed, 121 insertions, 0 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 23c4efbe13a6..e4348d25fca3 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -47,6 +47,13 @@
47 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ 47 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
48 .put = snd_soc_put_volsw, \ 48 .put = snd_soc_put_volsw, \
49 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } 49 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
50#define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
51{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
52 .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
53 .put = snd_soc_put_volsw_range, \
54 .private_value = (unsigned long)&(struct soc_mixer_control) \
55 {.reg = xreg, .shift = xshift, .min = xmin,\
56 .max = xmax, .platform_max = xmax, .invert = xinvert} }
50#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ 57#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
51{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 58{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
52 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ 59 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -67,6 +74,16 @@
67 {.reg = xreg, .rreg = xreg, \ 74 {.reg = xreg, .rreg = xreg, \
68 .shift = xshift, .rshift = xshift, \ 75 .shift = xshift, .rshift = xshift, \
69 .max = xmax, .min = xmin} } 76 .max = xmax, .min = xmin} }
77#define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, tlv_array) \
78{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
79 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
80 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
81 .tlv.p = (tlv_array), \
82 .info = snd_soc_info_volsw_range, \
83 .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
84 .private_value = (unsigned long)&(struct soc_mixer_control) \
85 {.reg = xreg, .shift = xshift, .min = xmin,\
86 .max = xmax, .platform_max = xmax, .invert = xinvert} }
70#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ 87#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
71{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ 88{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
72 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ 89 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@@ -460,6 +477,12 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
460 struct snd_ctl_elem_value *ucontrol); 477 struct snd_ctl_elem_value *ucontrol);
461int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, 478int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
462 struct snd_ctl_elem_value *ucontrol); 479 struct snd_ctl_elem_value *ucontrol);
480int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
481 struct snd_ctl_elem_info *uinfo);
482int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
483 struct snd_ctl_elem_value *ucontrol);
484int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
485 struct snd_ctl_elem_value *ucontrol);
463int snd_soc_limit_volume(struct snd_soc_codec *codec, 486int snd_soc_limit_volume(struct snd_soc_codec *codec,
464 const char *name, int max); 487 const char *name, int max);
465int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, 488int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ec8350570346..3d803f3cd272 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2792,6 +2792,104 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
2792EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); 2792EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
2793 2793
2794/** 2794/**
2795 * snd_soc_info_volsw_range - single mixer info callback with range.
2796 * @kcontrol: mixer control
2797 * @uinfo: control element information
2798 *
2799 * Callback to provide information, within a range, about a single
2800 * mixer control.
2801 *
2802 * returns 0 for success.
2803 */
2804int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
2805 struct snd_ctl_elem_info *uinfo)
2806{
2807 struct soc_mixer_control *mc =
2808 (struct soc_mixer_control *)kcontrol->private_value;
2809 int platform_max;
2810 int min = mc->min;
2811
2812 if (!mc->platform_max)
2813 mc->platform_max = mc->max;
2814 platform_max = mc->platform_max;
2815
2816 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2817 uinfo->count = 1;
2818 uinfo->value.integer.min = 0;
2819 uinfo->value.integer.max = platform_max - min;
2820
2821 return 0;
2822}
2823EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
2824
2825/**
2826 * snd_soc_put_volsw_range - single mixer put value callback with range.
2827 * @kcontrol: mixer control
2828 * @ucontrol: control element information
2829 *
2830 * Callback to set the value, within a range, for a single mixer control.
2831 *
2832 * Returns 0 for success.
2833 */
2834int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
2835 struct snd_ctl_elem_value *ucontrol)
2836{
2837 struct soc_mixer_control *mc =
2838 (struct soc_mixer_control *)kcontrol->private_value;
2839 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2840 unsigned int reg = mc->reg;
2841 unsigned int shift = mc->shift;
2842 int min = mc->min;
2843 int max = mc->max;
2844 unsigned int mask = (1 << fls(max)) - 1;
2845 unsigned int invert = mc->invert;
2846 unsigned int val, val_mask;
2847
2848 val = ((ucontrol->value.integer.value[0] + min) & mask);
2849 if (invert)
2850 val = max - val;
2851 val_mask = mask << shift;
2852 val = val << shift;
2853
2854 return snd_soc_update_bits_locked(codec, reg, val_mask, val);
2855}
2856EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
2857
2858/**
2859 * snd_soc_get_volsw_range - single mixer get callback with range
2860 * @kcontrol: mixer control
2861 * @ucontrol: control element information
2862 *
2863 * Callback to get the value, within a range, of a single mixer control.
2864 *
2865 * Returns 0 for success.
2866 */
2867int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
2868 struct snd_ctl_elem_value *ucontrol)
2869{
2870 struct soc_mixer_control *mc =
2871 (struct soc_mixer_control *)kcontrol->private_value;
2872 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2873 unsigned int reg = mc->reg;
2874 unsigned int shift = mc->shift;
2875 int min = mc->min;
2876 int max = mc->max;
2877 unsigned int mask = (1 << fls(max)) - 1;
2878 unsigned int invert = mc->invert;
2879
2880 ucontrol->value.integer.value[0] =
2881 (snd_soc_read(codec, reg) >> shift) & mask;
2882 if (invert)
2883 ucontrol->value.integer.value[0] =
2884 max - ucontrol->value.integer.value[0];
2885 ucontrol->value.integer.value[0] =
2886 ucontrol->value.integer.value[0] - min;
2887
2888 return 0;
2889}
2890EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
2891
2892/**
2795 * snd_soc_limit_volume - Set new limit to an existing volume control. 2893 * snd_soc_limit_volume - Set new limit to an existing volume control.
2796 * 2894 *
2797 * @codec: where to look for the control 2895 * @codec: where to look for the control