diff options
author | Markus Pargmann <mpa@pengutronix.de> | 2014-01-16 10:02:10 -0500 |
---|---|---|
committer | Shengjiu Wang <b02247@freescale.com> | 2014-05-13 04:54:33 -0400 |
commit | 2dac3d5a08aa3e8f18610113264eb8dc7781b4ae (patch) | |
tree | c27684fa524b7ce49d651c36f6d62554cf675a2d /sound/soc/soc-core.c | |
parent | 7cb5ee809f648c51ae84b1e99e0167ed3a431610 (diff) |
ASoC: core: Add signed register volume control logic
Some codecs use signed volume control representation with non standard
register sizes, e.g. 6 or 7 bit signed integers.
This patch adds generic signed register volume control logic to
soc-core. Instead of a fixed width signed register control, this
implementation uses a 'min' value and the signed bit location to translate
it to an absolute volume. Using the 'sign_bit' we can calculate a
correct mask for the register values and translate it back into signed
integers of standard size.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
(cherry picked from commit f227b88f0fce5f9b82aa934f8829a741c2e06d82)
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 d56bbea6e75e..2192e69469b1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -2603,6 +2603,48 @@ int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | |||
2603 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | 2603 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); |
2604 | 2604 | ||
2605 | /** | 2605 | /** |
2606 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
2607 | * @codec: codec | ||
2608 | * @reg: Register to read | ||
2609 | * @mask: Mask to use after shifting the register value | ||
2610 | * @shift: Right shift of register value | ||
2611 | * @sign_bit: Bit that describes if a number is negative or not. | ||
2612 | * | ||
2613 | * This functions reads a codec register. The register value is shifted right | ||
2614 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
2615 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
2616 | * | ||
2617 | * Returns the register value as signed int. | ||
2618 | */ | ||
2619 | static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg, | ||
2620 | unsigned int mask, unsigned int shift, unsigned int sign_bit) | ||
2621 | { | ||
2622 | int ret; | ||
2623 | unsigned int val; | ||
2624 | |||
2625 | val = (snd_soc_read(codec, reg) >> shift) & mask; | ||
2626 | |||
2627 | if (!sign_bit) | ||
2628 | return val; | ||
2629 | |||
2630 | /* non-negative number */ | ||
2631 | if (!(val & BIT(sign_bit))) | ||
2632 | return val; | ||
2633 | |||
2634 | ret = val; | ||
2635 | |||
2636 | /* | ||
2637 | * The register most probably does not contain a full-sized int. | ||
2638 | * Instead we have an arbitrary number of bits in a signed | ||
2639 | * representation which has to be translated into a full-sized int. | ||
2640 | * This is done by filling up all bits above the sign-bit. | ||
2641 | */ | ||
2642 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
2643 | |||
2644 | return ret; | ||
2645 | } | ||
2646 | |||
2647 | /** | ||
2606 | * snd_soc_info_volsw - single mixer info callback | 2648 | * snd_soc_info_volsw - single mixer info callback |
2607 | * @kcontrol: mixer control | 2649 | * @kcontrol: mixer control |
2608 | * @uinfo: control element information | 2650 | * @uinfo: control element information |
@@ -2630,7 +2672,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | |||
2630 | 2672 | ||
2631 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | 2673 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; |
2632 | uinfo->value.integer.min = 0; | 2674 | uinfo->value.integer.min = 0; |
2633 | uinfo->value.integer.max = platform_max; | 2675 | uinfo->value.integer.max = platform_max - mc->min; |
2634 | return 0; | 2676 | return 0; |
2635 | } | 2677 | } |
2636 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | 2678 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); |
@@ -2656,11 +2698,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
2656 | unsigned int shift = mc->shift; | 2698 | unsigned int shift = mc->shift; |
2657 | unsigned int rshift = mc->rshift; | 2699 | unsigned int rshift = mc->rshift; |
2658 | int max = mc->max; | 2700 | int max = mc->max; |
2701 | int min = mc->min; | ||
2702 | int sign_bit = mc->sign_bit; | ||
2659 | unsigned int mask = (1 << fls(max)) - 1; | 2703 | unsigned int mask = (1 << fls(max)) - 1; |
2660 | unsigned int invert = mc->invert; | 2704 | unsigned int invert = mc->invert; |
2661 | 2705 | ||
2662 | ucontrol->value.integer.value[0] = | 2706 | if (sign_bit) |
2663 | (snd_soc_read(codec, reg) >> shift) & mask; | 2707 | mask = BIT(sign_bit + 1) - 1; |
2708 | |||
2709 | ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask, | ||
2710 | shift, sign_bit) - min; | ||
2664 | if (invert) | 2711 | if (invert) |
2665 | ucontrol->value.integer.value[0] = | 2712 | ucontrol->value.integer.value[0] = |
2666 | max - ucontrol->value.integer.value[0]; | 2713 | max - ucontrol->value.integer.value[0]; |
@@ -2668,10 +2715,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
2668 | if (snd_soc_volsw_is_stereo(mc)) { | 2715 | if (snd_soc_volsw_is_stereo(mc)) { |
2669 | if (reg == reg2) | 2716 | if (reg == reg2) |
2670 | ucontrol->value.integer.value[1] = | 2717 | ucontrol->value.integer.value[1] = |
2671 | (snd_soc_read(codec, reg) >> rshift) & mask; | 2718 | snd_soc_read_signed(codec, reg, mask, rshift, |
2719 | sign_bit) - min; | ||
2672 | else | 2720 | else |
2673 | ucontrol->value.integer.value[1] = | 2721 | ucontrol->value.integer.value[1] = |
2674 | (snd_soc_read(codec, reg2) >> shift) & mask; | 2722 | snd_soc_read_signed(codec, reg2, mask, shift, |
2723 | sign_bit) - min; | ||
2675 | if (invert) | 2724 | if (invert) |
2676 | ucontrol->value.integer.value[1] = | 2725 | ucontrol->value.integer.value[1] = |
2677 | max - ucontrol->value.integer.value[1]; | 2726 | max - ucontrol->value.integer.value[1]; |
@@ -2702,6 +2751,8 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
2702 | unsigned int shift = mc->shift; | 2751 | unsigned int shift = mc->shift; |
2703 | unsigned int rshift = mc->rshift; | 2752 | unsigned int rshift = mc->rshift; |
2704 | int max = mc->max; | 2753 | int max = mc->max; |
2754 | int min = mc->min; | ||
2755 | unsigned int sign_bit = mc->sign_bit; | ||
2705 | unsigned int mask = (1 << fls(max)) - 1; | 2756 | unsigned int mask = (1 << fls(max)) - 1; |
2706 | unsigned int invert = mc->invert; | 2757 | unsigned int invert = mc->invert; |
2707 | int err; | 2758 | int err; |
@@ -2709,13 +2760,16 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
2709 | unsigned int val2 = 0; | 2760 | unsigned int val2 = 0; |
2710 | unsigned int val, val_mask; | 2761 | unsigned int val, val_mask; |
2711 | 2762 | ||
2712 | val = (ucontrol->value.integer.value[0] & mask); | 2763 | if (sign_bit) |
2764 | mask = BIT(sign_bit + 1) - 1; | ||
2765 | |||
2766 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2713 | if (invert) | 2767 | if (invert) |
2714 | val = max - val; | 2768 | val = max - val; |
2715 | val_mask = mask << shift; | 2769 | val_mask = mask << shift; |
2716 | val = val << shift; | 2770 | val = val << shift; |
2717 | if (snd_soc_volsw_is_stereo(mc)) { | 2771 | if (snd_soc_volsw_is_stereo(mc)) { |
2718 | val2 = (ucontrol->value.integer.value[1] & mask); | 2772 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); |
2719 | if (invert) | 2773 | if (invert) |
2720 | val2 = max - val2; | 2774 | val2 = max - val2; |
2721 | if (reg == reg2) { | 2775 | if (reg == reg2) { |