diff options
author | Peter Ujfalusi <peter.ujfalusi@nokia.com> | 2010-05-10 07:39:24 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-05-11 04:34:11 -0400 |
commit | d11bb4a925613fa814ed4ae350440eb24ebff336 (patch) | |
tree | 45332b4ea11ef84f6f33a7eb5a7957453de379a7 | |
parent | 896060c76bdfd8a45eb33b3dd1a8307fe37f6c04 (diff) |
ASoC: core: Fix for the volume limiting when invert is in use
If the register for the volume needs invert, than the inversion
need to be done from the chip maximum, and not from the platform
dependent limit.
Introduce soc_mixer_control.platform_max value, which initially
equals to chip maximum.
The snd_soc_limit_volume function only modify the platform_max,
all volsw_info call returns this as well.
The .max value holds the chip default (maximum), and it is used
for the inversion, if it is needed.
Additional check in the volsw_info call has been added to check
the validity of the platform_max in case, when custom macros
used by codec drivers are not initializing it correctly.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | include/sound/soc.h | 23 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 30 |
2 files changed, 33 insertions, 20 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h index 8326fc3db1cf..697e7ffe39d7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -30,10 +30,10 @@ | |||
30 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ | 30 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ |
31 | ((unsigned long)&(struct soc_mixer_control) \ | 31 | ((unsigned long)&(struct soc_mixer_control) \ |
32 | {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ | 32 | {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ |
33 | .invert = xinvert}) | 33 | .platform_max = xmax, .invert = xinvert}) |
34 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ | 34 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ |
35 | ((unsigned long)&(struct soc_mixer_control) \ | 35 | ((unsigned long)&(struct soc_mixer_control) \ |
36 | {.reg = xreg, .max = xmax, .invert = xinvert}) | 36 | {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) |
37 | #define SOC_SINGLE(xname, reg, shift, max, invert) \ | 37 | #define SOC_SINGLE(xname, reg, shift, max, invert) \ |
38 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 38 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
39 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 39 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
@@ -53,14 +53,14 @@ | |||
53 | .put = snd_soc_put_volsw, \ | 53 | .put = snd_soc_put_volsw, \ |
54 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 54 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
55 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ | 55 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ |
56 | .max = xmax, .invert = xinvert} } | 56 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
57 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ | 57 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ |
58 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 58 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
59 | .info = snd_soc_info_volsw_2r, \ | 59 | .info = snd_soc_info_volsw_2r, \ |
60 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ | 60 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ |
61 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 61 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
62 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ | 62 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ |
63 | .max = xmax, .invert = xinvert} } | 63 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
64 | #define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \ | 64 | #define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \ |
65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
66 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 66 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
@@ -70,7 +70,7 @@ | |||
70 | .put = snd_soc_put_volsw, \ | 70 | .put = snd_soc_put_volsw, \ |
71 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 71 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
72 | {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ | 72 | {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ |
73 | .max = xmax, .invert = xinvert} } | 73 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
74 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ | 74 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ |
75 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 75 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
76 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 76 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
@@ -80,7 +80,7 @@ | |||
80 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ | 80 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ |
81 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 81 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
82 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ | 82 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ |
83 | .max = xmax, .invert = xinvert} } | 83 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
84 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ | 84 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ |
85 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 85 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
86 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 86 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
@@ -89,7 +89,8 @@ | |||
89 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ | 89 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ |
90 | .put = snd_soc_put_volsw_s8, \ | 90 | .put = snd_soc_put_volsw_s8, \ |
91 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 91 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
92 | {.reg = xreg, .min = xmin, .max = xmax} } | 92 | {.reg = xreg, .min = xmin, .max = xmax, \ |
93 | .platform_max = xmax} } | ||
93 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \ | 94 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \ |
94 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 95 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
95 | .max = xmax, .texts = xtexts } | 96 | .max = xmax, .texts = xtexts } |
@@ -126,7 +127,7 @@ | |||
126 | .get = xhandler_get, .put = xhandler_put, \ | 127 | .get = xhandler_get, .put = xhandler_put, \ |
127 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 128 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
128 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ | 129 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ |
129 | .max = xmax, .invert = xinvert} } | 130 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
130 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ | 131 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ |
131 | xhandler_get, xhandler_put, tlv_array) \ | 132 | xhandler_get, xhandler_put, tlv_array) \ |
132 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 133 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
@@ -146,7 +147,7 @@ | |||
146 | .get = xhandler_get, .put = xhandler_put, \ | 147 | .get = xhandler_get, .put = xhandler_put, \ |
147 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 148 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
148 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ | 149 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ |
149 | .max = xmax, .invert = xinvert} } | 150 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
150 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ | 151 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ |
151 | xhandler_get, xhandler_put, tlv_array) \ | 152 | xhandler_get, xhandler_put, tlv_array) \ |
152 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 153 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
@@ -157,7 +158,7 @@ | |||
157 | .get = xhandler_get, .put = xhandler_put, \ | 158 | .get = xhandler_get, .put = xhandler_put, \ |
158 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 159 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
159 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ | 160 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ |
160 | .max = xmax, .invert = xinvert} } | 161 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
161 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ | 162 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ |
162 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 163 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
163 | .info = snd_soc_info_bool_ext, \ | 164 | .info = snd_soc_info_bool_ext, \ |
@@ -572,7 +573,7 @@ struct snd_soc_pcm_runtime { | |||
572 | 573 | ||
573 | /* mixer control */ | 574 | /* mixer control */ |
574 | struct soc_mixer_control { | 575 | struct soc_mixer_control { |
575 | int min, max; | 576 | int min, max, platform_max; |
576 | unsigned int reg, rreg, shift, rshift, invert; | 577 | unsigned int reg, rreg, shift, rshift, invert; |
577 | }; | 578 | }; |
578 | 579 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 34f71bf60140..e1043f644730 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -2017,18 +2017,22 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | |||
2017 | { | 2017 | { |
2018 | struct soc_mixer_control *mc = | 2018 | struct soc_mixer_control *mc = |
2019 | (struct soc_mixer_control *)kcontrol->private_value; | 2019 | (struct soc_mixer_control *)kcontrol->private_value; |
2020 | int max = mc->max; | 2020 | int platform_max; |
2021 | unsigned int shift = mc->shift; | 2021 | unsigned int shift = mc->shift; |
2022 | unsigned int rshift = mc->rshift; | 2022 | unsigned int rshift = mc->rshift; |
2023 | 2023 | ||
2024 | if (max == 1 && !strstr(kcontrol->id.name, " Volume")) | 2024 | if (!mc->platform_max) |
2025 | mc->platform_max = mc->max; | ||
2026 | platform_max = mc->platform_max; | ||
2027 | |||
2028 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
2025 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 2029 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
2026 | else | 2030 | else |
2027 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2031 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2028 | 2032 | ||
2029 | uinfo->count = shift == rshift ? 1 : 2; | 2033 | uinfo->count = shift == rshift ? 1 : 2; |
2030 | uinfo->value.integer.min = 0; | 2034 | uinfo->value.integer.min = 0; |
2031 | uinfo->value.integer.max = max; | 2035 | uinfo->value.integer.max = platform_max; |
2032 | return 0; | 2036 | return 0; |
2033 | } | 2037 | } |
2034 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | 2038 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); |
@@ -2126,16 +2130,20 @@ int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | |||
2126 | { | 2130 | { |
2127 | struct soc_mixer_control *mc = | 2131 | struct soc_mixer_control *mc = |
2128 | (struct soc_mixer_control *)kcontrol->private_value; | 2132 | (struct soc_mixer_control *)kcontrol->private_value; |
2129 | int max = mc->max; | 2133 | int platform_max; |
2130 | 2134 | ||
2131 | if (max == 1 && !strstr(kcontrol->id.name, " Volume")) | 2135 | if (!mc->platform_max) |
2136 | mc->platform_max = mc->max; | ||
2137 | platform_max = mc->platform_max; | ||
2138 | |||
2139 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
2132 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 2140 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
2133 | else | 2141 | else |
2134 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2142 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2135 | 2143 | ||
2136 | uinfo->count = 2; | 2144 | uinfo->count = 2; |
2137 | uinfo->value.integer.min = 0; | 2145 | uinfo->value.integer.min = 0; |
2138 | uinfo->value.integer.max = max; | 2146 | uinfo->value.integer.max = platform_max; |
2139 | return 0; | 2147 | return 0; |
2140 | } | 2148 | } |
2141 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); | 2149 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); |
@@ -2236,13 +2244,17 @@ int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | |||
2236 | { | 2244 | { |
2237 | struct soc_mixer_control *mc = | 2245 | struct soc_mixer_control *mc = |
2238 | (struct soc_mixer_control *)kcontrol->private_value; | 2246 | (struct soc_mixer_control *)kcontrol->private_value; |
2239 | int max = mc->max; | 2247 | int platform_max; |
2240 | int min = mc->min; | 2248 | int min = mc->min; |
2241 | 2249 | ||
2250 | if (!mc->platform_max) | ||
2251 | mc->platform_max = mc->max; | ||
2252 | platform_max = mc->platform_max; | ||
2253 | |||
2242 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2254 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2243 | uinfo->count = 2; | 2255 | uinfo->count = 2; |
2244 | uinfo->value.integer.min = 0; | 2256 | uinfo->value.integer.min = 0; |
2245 | uinfo->value.integer.max = max-min; | 2257 | uinfo->value.integer.max = platform_max - min; |
2246 | return 0; | 2258 | return 0; |
2247 | } | 2259 | } |
2248 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | 2260 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); |
@@ -2331,7 +2343,7 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec, | |||
2331 | if (found) { | 2343 | if (found) { |
2332 | mc = (struct soc_mixer_control *)kctl->private_value; | 2344 | mc = (struct soc_mixer_control *)kctl->private_value; |
2333 | if (max <= mc->max) { | 2345 | if (max <= mc->max) { |
2334 | mc->max = max; | 2346 | mc->platform_max = max; |
2335 | ret = 0; | 2347 | ret = 0; |
2336 | } | 2348 | } |
2337 | } | 2349 | } |