diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 68 |
1 files changed, 61 insertions, 7 deletions
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) { |