diff options
author | Mark Brown <broonie@linaro.org> | 2014-02-03 07:46:54 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-02-03 07:46:54 -0500 |
commit | 80e9c19c02fd8f1343c9c263d22a08e2371c9f55 (patch) | |
tree | d1fa4b7dfbca30f3138860725c334b2f5b9adbd8 | |
parent | a74ab5121f8d91fb7f13ac1c86e72e9d35e0bc29 (diff) | |
parent | cd21b123346c6a2f033d8c3bd2bf240198b5712a (diff) |
Merge branch 'topic/sign' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-tlv320aic32x4
-rw-r--r-- | include/sound/soc.h | 15 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 68 |
2 files changed, 76 insertions, 7 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h index 9a001472b96a..c4be7ab89399 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -45,6 +45,11 @@ | |||
45 | ((unsigned long)&(struct soc_mixer_control) \ | 45 | ((unsigned long)&(struct soc_mixer_control) \ |
46 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | 46 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ |
47 | .max = xmax, .platform_max = xmax, .invert = xinvert}) | 47 | .max = xmax, .platform_max = xmax, .invert = xinvert}) |
48 | #define SOC_DOUBLE_R_S_VALUE(xlreg, xrreg, xshift, xmin, xmax, xsign_bit, xinvert) \ | ||
49 | ((unsigned long)&(struct soc_mixer_control) \ | ||
50 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | ||
51 | .max = xmax, .min = xmin, .platform_max = xmax, .sign_bit = xsign_bit, \ | ||
52 | .invert = xinvert}) | ||
48 | #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \ | 53 | #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \ |
49 | ((unsigned long)&(struct soc_mixer_control) \ | 54 | ((unsigned long)&(struct soc_mixer_control) \ |
50 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | 55 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ |
@@ -152,6 +157,15 @@ | |||
152 | {.reg = xreg, .rreg = xrreg, \ | 157 | {.reg = xreg, .rreg = xrreg, \ |
153 | .shift = xshift, .rshift = xshift, \ | 158 | .shift = xshift, .rshift = xshift, \ |
154 | .max = xmax, .min = xmin} } | 159 | .max = xmax, .min = xmin} } |
160 | #define SOC_DOUBLE_R_S_TLV(xname, reg_left, reg_right, xshift, xmin, xmax, xsign_bit, xinvert, tlv_array) \ | ||
161 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | ||
162 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
163 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
164 | .tlv.p = (tlv_array), \ | ||
165 | .info = snd_soc_info_volsw, \ | ||
166 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ | ||
167 | .private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \ | ||
168 | xmin, xmax, xsign_bit, xinvert) } | ||
155 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ | 169 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ |
156 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 170 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
157 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 171 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
@@ -1067,6 +1081,7 @@ struct soc_mixer_control { | |||
1067 | int min, max, platform_max; | 1081 | int min, max, platform_max; |
1068 | int reg, rreg; | 1082 | int reg, rreg; |
1069 | unsigned int shift, rshift; | 1083 | unsigned int shift, rshift; |
1084 | unsigned int sign_bit; | ||
1070 | unsigned int invert:1; | 1085 | unsigned int invert:1; |
1071 | unsigned int autodisable:1; | 1086 | unsigned int autodisable:1; |
1072 | }; | 1087 | }; |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fe1df50805a3..c1d9d8539ee9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -2716,6 +2716,48 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2716 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | 2716 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); |
2717 | 2717 | ||
2718 | /** | 2718 | /** |
2719 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
2720 | * @codec: codec | ||
2721 | * @reg: Register to read | ||
2722 | * @mask: Mask to use after shifting the register value | ||
2723 | * @shift: Right shift of register value | ||
2724 | * @sign_bit: Bit that describes if a number is negative or not. | ||
2725 | * | ||
2726 | * This functions reads a codec register. The register value is shifted right | ||
2727 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
2728 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
2729 | * | ||
2730 | * Returns the register value as signed int. | ||
2731 | */ | ||
2732 | static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg, | ||
2733 | unsigned int mask, unsigned int shift, unsigned int sign_bit) | ||
2734 | { | ||
2735 | int ret; | ||
2736 | unsigned int val; | ||
2737 | |||
2738 | val = (snd_soc_read(codec, reg) >> shift) & mask; | ||
2739 | |||
2740 | if (!sign_bit) | ||
2741 | return val; | ||
2742 | |||
2743 | /* non-negative number */ | ||
2744 | if (!(val & BIT(sign_bit))) | ||
2745 | return val; | ||
2746 | |||
2747 | ret = val; | ||
2748 | |||
2749 | /* | ||
2750 | * The register most probably does not contain a full-sized int. | ||
2751 | * Instead we have an arbitrary number of bits in a signed | ||
2752 | * representation which has to be translated into a full-sized int. | ||
2753 | * This is done by filling up all bits above the sign-bit. | ||
2754 | */ | ||
2755 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
2756 | |||
2757 | return ret; | ||
2758 | } | ||
2759 | |||
2760 | /** | ||
2719 | * snd_soc_info_volsw - single mixer info callback | 2761 | * snd_soc_info_volsw - single mixer info callback |
2720 | * @kcontrol: mixer control | 2762 | * @kcontrol: mixer control |
2721 | * @uinfo: control element information | 2763 | * @uinfo: control element information |
@@ -2743,7 +2785,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | |||
2743 | 2785 | ||
2744 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | 2786 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; |
2745 | uinfo->value.integer.min = 0; | 2787 | uinfo->value.integer.min = 0; |
2746 | uinfo->value.integer.max = platform_max; | 2788 | uinfo->value.integer.max = platform_max - mc->min; |
2747 | return 0; | 2789 | return 0; |
2748 | } | 2790 | } |
2749 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | 2791 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); |
@@ -2769,11 +2811,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
2769 | unsigned int shift = mc->shift; | 2811 | unsigned int shift = mc->shift; |
2770 | unsigned int rshift = mc->rshift; | 2812 | unsigned int rshift = mc->rshift; |
2771 | int max = mc->max; | 2813 | int max = mc->max; |
2814 | int min = mc->min; | ||
2815 | int sign_bit = mc->sign_bit; | ||
2772 | unsigned int mask = (1 << fls(max)) - 1; | 2816 | unsigned int mask = (1 << fls(max)) - 1; |
2773 | unsigned int invert = mc->invert; | 2817 | unsigned int invert = mc->invert; |
2774 | 2818 | ||
2775 | ucontrol->value.integer.value[0] = | 2819 | if (sign_bit) |
2776 | (snd_soc_read(codec, reg) >> shift) & mask; | 2820 | mask = BIT(sign_bit + 1) - 1; |
2821 | |||
2822 | ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask, | ||
2823 | shift, sign_bit) - min; | ||
2777 | if (invert) | 2824 | if (invert) |
2778 | ucontrol->value.integer.value[0] = | 2825 | ucontrol->value.integer.value[0] = |
2779 | max - ucontrol->value.integer.value[0]; | 2826 | max - ucontrol->value.integer.value[0]; |
@@ -2781,10 +2828,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
2781 | if (snd_soc_volsw_is_stereo(mc)) { | 2828 | if (snd_soc_volsw_is_stereo(mc)) { |
2782 | if (reg == reg2) | 2829 | if (reg == reg2) |
2783 | ucontrol->value.integer.value[1] = | 2830 | ucontrol->value.integer.value[1] = |
2784 | (snd_soc_read(codec, reg) >> rshift) & mask; | 2831 | snd_soc_read_signed(codec, reg, mask, rshift, |
2832 | sign_bit) - min; | ||
2785 | else | 2833 | else |
2786 | ucontrol->value.integer.value[1] = | 2834 | ucontrol->value.integer.value[1] = |
2787 | (snd_soc_read(codec, reg2) >> shift) & mask; | 2835 | snd_soc_read_signed(codec, reg2, mask, shift, |
2836 | sign_bit) - min; | ||
2788 | if (invert) | 2837 | if (invert) |
2789 | ucontrol->value.integer.value[1] = | 2838 | ucontrol->value.integer.value[1] = |
2790 | max - ucontrol->value.integer.value[1]; | 2839 | max - ucontrol->value.integer.value[1]; |
@@ -2815,6 +2864,8 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
2815 | unsigned int shift = mc->shift; | 2864 | unsigned int shift = mc->shift; |
2816 | unsigned int rshift = mc->rshift; | 2865 | unsigned int rshift = mc->rshift; |
2817 | int max = mc->max; | 2866 | int max = mc->max; |
2867 | int min = mc->min; | ||
2868 | unsigned int sign_bit = mc->sign_bit; | ||
2818 | unsigned int mask = (1 << fls(max)) - 1; | 2869 | unsigned int mask = (1 << fls(max)) - 1; |
2819 | unsigned int invert = mc->invert; | 2870 | unsigned int invert = mc->invert; |
2820 | int err; | 2871 | int err; |
@@ -2822,13 +2873,16 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
2822 | unsigned int val2 = 0; | 2873 | unsigned int val2 = 0; |
2823 | unsigned int val, val_mask; | 2874 | unsigned int val, val_mask; |
2824 | 2875 | ||
2825 | val = (ucontrol->value.integer.value[0] & mask); | 2876 | if (sign_bit) |
2877 | mask = BIT(sign_bit + 1) - 1; | ||
2878 | |||
2879 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2826 | if (invert) | 2880 | if (invert) |
2827 | val = max - val; | 2881 | val = max - val; |
2828 | val_mask = mask << shift; | 2882 | val_mask = mask << shift; |
2829 | val = val << shift; | 2883 | val = val << shift; |
2830 | if (snd_soc_volsw_is_stereo(mc)) { | 2884 | if (snd_soc_volsw_is_stereo(mc)) { |
2831 | val2 = (ucontrol->value.integer.value[1] & mask); | 2885 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); |
2832 | if (invert) | 2886 | if (invert) |
2833 | val2 = max - val2; | 2887 | val2 = max - val2; |
2834 | if (reg == reg2) { | 2888 | if (reg == reg2) { |