diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2014-02-28 02:31:03 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-02-28 22:03:33 -0500 |
commit | 29ae2fa5533e607a7d97b7564dc015252f1e73f4 (patch) | |
tree | d0d301930177438179ffb297f15c6555e1ed694d | |
parent | 8303d769ea9e9626c4f0c3bd13e35e904a1253ab (diff) |
ASoC: Consolidate enum and value enum controls
The implementations for enum and value enum controls are almost identical. The
only difference is that the value enum uses an additional look-up table to map
the control value to the register value, while the enum control uses a direct
mapping. Enums and value enums can easily be distinguished at runtime, for value
enums the values field of the snd_soc_enum struct contains the look-up table,
while for enums it is NULL. This patch adds two new small helper functions
called snd_soc_enum_item_to_val() and snd_soc_enum_val_to_item() which map
between register value and control item. If the items field of the snd_soc_enum
struct is NULL the function will do a direct mapping otherwise they'll use the
look-up table to do the mapping. Using these small helper functions it is
possible to use the same kcontrol handlers for both enums and value enums. The
functions are added a inline functions in soc.h so they can also be used by the
DAPM code to accomplish similar consolidation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r-- | include/sound/soc.h | 34 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 101 |
2 files changed, 41 insertions, 94 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h index 49d6c10f4612..60c700ccc518 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -195,11 +195,7 @@ | |||
195 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ | 195 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ |
196 | .private_value = (unsigned long)&xenum } | 196 | .private_value = (unsigned long)&xenum } |
197 | #define SOC_VALUE_ENUM(xname, xenum) \ | 197 | #define SOC_VALUE_ENUM(xname, xenum) \ |
198 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 198 | SOC_ENUM(xname, xenum) |
199 | .info = snd_soc_info_enum_double, \ | ||
200 | .get = snd_soc_get_value_enum_double, \ | ||
201 | .put = snd_soc_put_value_enum_double, \ | ||
202 | .private_value = (unsigned long)&xenum } | ||
203 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ | 199 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ |
204 | xhandler_get, xhandler_put) \ | 200 | xhandler_get, xhandler_put) \ |
205 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 201 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
@@ -510,10 +506,6 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
510 | struct snd_ctl_elem_value *ucontrol); | 506 | struct snd_ctl_elem_value *ucontrol); |
511 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | 507 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, |
512 | struct snd_ctl_elem_value *ucontrol); | 508 | struct snd_ctl_elem_value *ucontrol); |
513 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
514 | struct snd_ctl_elem_value *ucontrol); | ||
515 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
516 | struct snd_ctl_elem_value *ucontrol); | ||
517 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 509 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
518 | struct snd_ctl_elem_info *uinfo); | 510 | struct snd_ctl_elem_info *uinfo); |
519 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info | 511 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info |
@@ -1182,6 +1174,30 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) | |||
1182 | return 1; | 1174 | return 1; |
1183 | } | 1175 | } |
1184 | 1176 | ||
1177 | static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e, | ||
1178 | unsigned int val) | ||
1179 | { | ||
1180 | unsigned int i; | ||
1181 | |||
1182 | if (!e->values) | ||
1183 | return val; | ||
1184 | |||
1185 | for (i = 0; i < e->items; i++) | ||
1186 | if (val == e->values[i]) | ||
1187 | return i; | ||
1188 | |||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e, | ||
1193 | unsigned int item) | ||
1194 | { | ||
1195 | if (!e->values) | ||
1196 | return item; | ||
1197 | |||
1198 | return e->values[item]; | ||
1199 | } | ||
1200 | |||
1185 | int snd_soc_util_init(void); | 1201 | int snd_soc_util_init(void); |
1186 | void snd_soc_util_exit(void); | 1202 | void snd_soc_util_exit(void); |
1187 | 1203 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 851733897206..2ddc7a4939d2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -2596,14 +2596,18 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2596 | { | 2596 | { |
2597 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2597 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2598 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2598 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2599 | unsigned int val; | 2599 | unsigned int val, item; |
2600 | unsigned int reg_val; | ||
2600 | 2601 | ||
2601 | val = snd_soc_read(codec, e->reg); | 2602 | reg_val = snd_soc_read(codec, e->reg); |
2602 | ucontrol->value.enumerated.item[0] | 2603 | val = (reg_val >> e->shift_l) & e->mask; |
2603 | = (val >> e->shift_l) & e->mask; | 2604 | item = snd_soc_enum_val_to_item(e, val); |
2604 | if (e->shift_l != e->shift_r) | 2605 | ucontrol->value.enumerated.item[0] = item; |
2605 | ucontrol->value.enumerated.item[1] = | 2606 | if (e->shift_l != e->shift_r) { |
2606 | (val >> e->shift_r) & e->mask; | 2607 | val = (reg_val >> e->shift_l) & e->mask; |
2608 | item = snd_soc_enum_val_to_item(e, val); | ||
2609 | ucontrol->value.enumerated.item[1] = item; | ||
2610 | } | ||
2607 | 2611 | ||
2608 | return 0; | 2612 | return 0; |
2609 | } | 2613 | } |
@@ -2623,17 +2627,18 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2623 | { | 2627 | { |
2624 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2628 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2625 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2629 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2630 | unsigned int *item = ucontrol->value.enumerated.item; | ||
2626 | unsigned int val; | 2631 | unsigned int val; |
2627 | unsigned int mask; | 2632 | unsigned int mask; |
2628 | 2633 | ||
2629 | if (ucontrol->value.enumerated.item[0] >= e->items) | 2634 | if (item[0] >= e->items) |
2630 | return -EINVAL; | 2635 | return -EINVAL; |
2631 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | 2636 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; |
2632 | mask = e->mask << e->shift_l; | 2637 | mask = e->mask << e->shift_l; |
2633 | if (e->shift_l != e->shift_r) { | 2638 | if (e->shift_l != e->shift_r) { |
2634 | if (ucontrol->value.enumerated.item[1] >= e->items) | 2639 | if (item[1] >= e->items) |
2635 | return -EINVAL; | 2640 | return -EINVAL; |
2636 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 2641 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; |
2637 | mask |= e->mask << e->shift_r; | 2642 | mask |= e->mask << e->shift_r; |
2638 | } | 2643 | } |
2639 | 2644 | ||
@@ -2642,80 +2647,6 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2642 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | 2647 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); |
2643 | 2648 | ||
2644 | /** | 2649 | /** |
2645 | * snd_soc_get_value_enum_double - semi enumerated double mixer get callback | ||
2646 | * @kcontrol: mixer control | ||
2647 | * @ucontrol: control element information | ||
2648 | * | ||
2649 | * Callback to get the value of a double semi enumerated mixer. | ||
2650 | * | ||
2651 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
2652 | * used for handling bitfield coded enumeration for example. | ||
2653 | * | ||
2654 | * Returns 0 for success. | ||
2655 | */ | ||
2656 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
2657 | struct snd_ctl_elem_value *ucontrol) | ||
2658 | { | ||
2659 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2660 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2661 | unsigned int reg_val, val, mux; | ||
2662 | |||
2663 | reg_val = snd_soc_read(codec, e->reg); | ||
2664 | val = (reg_val >> e->shift_l) & e->mask; | ||
2665 | for (mux = 0; mux < e->items; mux++) { | ||
2666 | if (val == e->values[mux]) | ||
2667 | break; | ||
2668 | } | ||
2669 | ucontrol->value.enumerated.item[0] = mux; | ||
2670 | if (e->shift_l != e->shift_r) { | ||
2671 | val = (reg_val >> e->shift_r) & e->mask; | ||
2672 | for (mux = 0; mux < e->items; mux++) { | ||
2673 | if (val == e->values[mux]) | ||
2674 | break; | ||
2675 | } | ||
2676 | ucontrol->value.enumerated.item[1] = mux; | ||
2677 | } | ||
2678 | |||
2679 | return 0; | ||
2680 | } | ||
2681 | EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); | ||
2682 | |||
2683 | /** | ||
2684 | * snd_soc_put_value_enum_double - semi enumerated double mixer put callback | ||
2685 | * @kcontrol: mixer control | ||
2686 | * @ucontrol: control element information | ||
2687 | * | ||
2688 | * Callback to set the value of a double semi enumerated mixer. | ||
2689 | * | ||
2690 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
2691 | * used for handling bitfield coded enumeration for example. | ||
2692 | * | ||
2693 | * Returns 0 for success. | ||
2694 | */ | ||
2695 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
2696 | struct snd_ctl_elem_value *ucontrol) | ||
2697 | { | ||
2698 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2699 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2700 | unsigned int val; | ||
2701 | unsigned int mask; | ||
2702 | |||
2703 | if (ucontrol->value.enumerated.item[0] >= e->items) | ||
2704 | return -EINVAL; | ||
2705 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | ||
2706 | mask = e->mask << e->shift_l; | ||
2707 | if (e->shift_l != e->shift_r) { | ||
2708 | if (ucontrol->value.enumerated.item[1] >= e->items) | ||
2709 | return -EINVAL; | ||
2710 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | ||
2711 | mask |= e->mask << e->shift_r; | ||
2712 | } | ||
2713 | |||
2714 | return snd_soc_update_bits_locked(codec, e->reg, mask, val); | ||
2715 | } | ||
2716 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | ||
2717 | |||
2718 | /** | ||
2719 | * snd_soc_read_signed - Read a codec register and interprete as signed value | 2650 | * snd_soc_read_signed - Read a codec register and interprete as signed value |
2720 | * @codec: codec | 2651 | * @codec: codec |
2721 | * @reg: Register to read | 2652 | * @reg: Register to read |