aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2010-05-10 07:39:24 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-05-11 04:34:11 -0400
commitd11bb4a925613fa814ed4ae350440eb24ebff336 (patch)
tree45332b4ea11ef84f6f33a7eb5a7957453de379a7
parent896060c76bdfd8a45eb33b3dd1a8307fe37f6c04 (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.h23
-rw-r--r--sound/soc/soc-core.c30
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 */
574struct soc_mixer_control { 575struct 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}
2034EXPORT_SYMBOL_GPL(snd_soc_info_volsw); 2038EXPORT_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}
2141EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); 2149EXPORT_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}
2248EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); 2260EXPORT_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 }