diff options
author | Johannes Stezenbach <js@sig21.net> | 2011-07-11 11:01:23 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-07-13 11:24:31 -0400 |
commit | 796884391504426e9da15bdf76f73c5f4eda3714 (patch) | |
tree | 2e7505ffa5823c93fea5b5403c24c0e3f8c2b5a3 | |
parent | 5b7396709e0b2d43527024316e0bc4630759bcf3 (diff) |
ASoC: STA32x: Add mixer controls for biquad coefficients
The STA32x has a number of preset EQ settings, but also
allows full user control of the biquad filter coeffcients
(when "Automode EQ" is set to "User").
Each biquad has five signed, 24bit, fixed-point coefficients
representing the range -1...1. The five biquad coefficients
can be uploaded in one atomic operation into on-chip
coefficient RAM.
There are also a few prescale, postscale and mixing
coefficients, in the same numeric format and range
(a negative coefficient inverts phase).
These coefficients are made available as SNDRV_CTL_ELEM_TYPE_BYTES
mixer controls.
Signed-off-by: Johannes Stezenbach <js@sig21.net>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/sta32x.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 486628a144b4..9bf944ca43a1 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c | |||
@@ -177,6 +177,95 @@ static const struct soc_enum sta32x_limiter1_release_rate_enum = | |||
177 | static const struct soc_enum sta32x_limiter2_release_rate_enum = | 177 | static const struct soc_enum sta32x_limiter2_release_rate_enum = |
178 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, | 178 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, |
179 | 16, sta32x_limiter_release_rate); | 179 | 16, sta32x_limiter_release_rate); |
180 | |||
181 | /* byte array controls for setting biquad, mixer, scaling coefficients; | ||
182 | * for biquads all five coefficients need to be set in one go, | ||
183 | * mixer and pre/postscale coefs can be set individually; | ||
184 | * each coef is 24bit, the bytes are ordered in the same way | ||
185 | * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0) | ||
186 | */ | ||
187 | |||
188 | static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol, | ||
189 | struct snd_ctl_elem_info *uinfo) | ||
190 | { | ||
191 | int numcoef = kcontrol->private_value >> 16; | ||
192 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
193 | uinfo->count = 3 * numcoef; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, | ||
198 | struct snd_ctl_elem_value *ucontrol) | ||
199 | { | ||
200 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
201 | int numcoef = kcontrol->private_value >> 16; | ||
202 | int index = kcontrol->private_value & 0xffff; | ||
203 | unsigned int cfud; | ||
204 | int i; | ||
205 | |||
206 | /* preserve reserved bits in STA32X_CFUD */ | ||
207 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
208 | /* chip documentation does not say if the bits are self clearing, | ||
209 | * so do it explicitly */ | ||
210 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
211 | |||
212 | snd_soc_write(codec, STA32X_CFADDR2, index); | ||
213 | if (numcoef == 1) | ||
214 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x04); | ||
215 | else if (numcoef == 5) | ||
216 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x08); | ||
217 | else | ||
218 | return -EINVAL; | ||
219 | for (i = 0; i < 3 * numcoef; i++) | ||
220 | ucontrol->value.bytes.data[i] = | ||
221 | snd_soc_read(codec, STA32X_B1CF1 + i); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, | ||
227 | struct snd_ctl_elem_value *ucontrol) | ||
228 | { | ||
229 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
230 | int numcoef = kcontrol->private_value >> 16; | ||
231 | int index = kcontrol->private_value & 0xffff; | ||
232 | unsigned int cfud; | ||
233 | int i; | ||
234 | |||
235 | /* preserve reserved bits in STA32X_CFUD */ | ||
236 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
237 | /* chip documentation does not say if the bits are self clearing, | ||
238 | * so do it explicitly */ | ||
239 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
240 | |||
241 | snd_soc_write(codec, STA32X_CFADDR2, index); | ||
242 | for (i = 0; i < 3 * numcoef; i++) | ||
243 | snd_soc_write(codec, STA32X_B1CF1 + i, | ||
244 | ucontrol->value.bytes.data[i]); | ||
245 | if (numcoef == 1) | ||
246 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); | ||
247 | else if (numcoef == 5) | ||
248 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x02); | ||
249 | else | ||
250 | return -EINVAL; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | #define SINGLE_COEF(xname, index) \ | ||
256 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
257 | .info = sta32x_coefficient_info, \ | ||
258 | .get = sta32x_coefficient_get,\ | ||
259 | .put = sta32x_coefficient_put, \ | ||
260 | .private_value = index | (1 << 16) } | ||
261 | |||
262 | #define BIQUAD_COEFS(xname, index) \ | ||
263 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
264 | .info = sta32x_coefficient_info, \ | ||
265 | .get = sta32x_coefficient_get,\ | ||
266 | .put = sta32x_coefficient_put, \ | ||
267 | .private_value = index | (5 << 16) } | ||
268 | |||
180 | static const struct snd_kcontrol_new sta32x_snd_controls[] = { | 269 | static const struct snd_kcontrol_new sta32x_snd_controls[] = { |
181 | SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), | 270 | SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), |
182 | SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), | 271 | SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), |
@@ -232,6 +321,29 @@ SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_Lx | |||
232 | 16, 0, sta32x_limiter_drc_release_tlv), | 321 | 16, 0, sta32x_limiter_drc_release_tlv), |
233 | SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, | 322 | SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, |
234 | 16, 0, sta32x_limiter_drc_release_tlv), | 323 | 16, 0, sta32x_limiter_drc_release_tlv), |
324 | |||
325 | BIQUAD_COEFS("Ch1 - Biquad 1", 0), | ||
326 | BIQUAD_COEFS("Ch1 - Biquad 2", 5), | ||
327 | BIQUAD_COEFS("Ch1 - Biquad 3", 10), | ||
328 | BIQUAD_COEFS("Ch1 - Biquad 4", 15), | ||
329 | BIQUAD_COEFS("Ch2 - Biquad 1", 20), | ||
330 | BIQUAD_COEFS("Ch2 - Biquad 2", 25), | ||
331 | BIQUAD_COEFS("Ch2 - Biquad 3", 30), | ||
332 | BIQUAD_COEFS("Ch2 - Biquad 4", 35), | ||
333 | BIQUAD_COEFS("High-pass", 40), | ||
334 | BIQUAD_COEFS("Low-pass", 45), | ||
335 | SINGLE_COEF("Ch1 - Prescale", 50), | ||
336 | SINGLE_COEF("Ch2 - Prescale", 51), | ||
337 | SINGLE_COEF("Ch1 - Postscale", 52), | ||
338 | SINGLE_COEF("Ch2 - Postscale", 53), | ||
339 | SINGLE_COEF("Ch3 - Postscale", 54), | ||
340 | SINGLE_COEF("Thermal warning - Postscale", 55), | ||
341 | SINGLE_COEF("Ch1 - Mix 1", 56), | ||
342 | SINGLE_COEF("Ch1 - Mix 2", 57), | ||
343 | SINGLE_COEF("Ch2 - Mix 1", 58), | ||
344 | SINGLE_COEF("Ch2 - Mix 2", 59), | ||
345 | SINGLE_COEF("Ch3 - Mix 1", 60), | ||
346 | SINGLE_COEF("Ch3 - Mix 2", 61), | ||
235 | }; | 347 | }; |
236 | 348 | ||
237 | static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { | 349 | static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { |
@@ -686,6 +798,17 @@ static int sta32x_remove(struct snd_soc_codec *codec) | |||
686 | return 0; | 798 | return 0; |
687 | } | 799 | } |
688 | 800 | ||
801 | static int sta32x_reg_is_volatile(struct snd_soc_codec *codec, | ||
802 | unsigned int reg) | ||
803 | { | ||
804 | switch (reg) { | ||
805 | case STA32X_CONFA ... STA32X_L2ATRT: | ||
806 | case STA32X_MPCC1 ... STA32X_FDRC2: | ||
807 | return 0; | ||
808 | } | ||
809 | return 1; | ||
810 | } | ||
811 | |||
689 | static const struct snd_soc_codec_driver sta32x_codec = { | 812 | static const struct snd_soc_codec_driver sta32x_codec = { |
690 | .probe = sta32x_probe, | 813 | .probe = sta32x_probe, |
691 | .remove = sta32x_remove, | 814 | .remove = sta32x_remove, |
@@ -693,6 +816,7 @@ static const struct snd_soc_codec_driver sta32x_codec = { | |||
693 | .resume = sta32x_resume, | 816 | .resume = sta32x_resume, |
694 | .reg_cache_size = STA32X_REGISTER_COUNT, | 817 | .reg_cache_size = STA32X_REGISTER_COUNT, |
695 | .reg_word_size = sizeof(u8), | 818 | .reg_word_size = sizeof(u8), |
819 | .volatile_register = sta32x_reg_is_volatile, | ||
696 | .set_bias_level = sta32x_set_bias_level, | 820 | .set_bias_level = sta32x_set_bias_level, |
697 | .controls = sta32x_snd_controls, | 821 | .controls = sta32x_snd_controls, |
698 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), | 822 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), |