aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Stezenbach <js@sig21.net>2011-07-11 11:01:23 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-07-13 11:24:31 -0400
commit796884391504426e9da15bdf76f73c5f4eda3714 (patch)
tree2e7505ffa5823c93fea5b5403c24c0e3f8c2b5a3
parent5b7396709e0b2d43527024316e0bc4630759bcf3 (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.c124
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 =
177static const struct soc_enum sta32x_limiter2_release_rate_enum = 177static 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
188static 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
197static 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
226static 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
180static const struct snd_kcontrol_new sta32x_snd_controls[] = { 269static const struct snd_kcontrol_new sta32x_snd_controls[] = {
181SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), 270SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv),
182SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), 271SOC_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),
233SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, 322SOC_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
325BIQUAD_COEFS("Ch1 - Biquad 1", 0),
326BIQUAD_COEFS("Ch1 - Biquad 2", 5),
327BIQUAD_COEFS("Ch1 - Biquad 3", 10),
328BIQUAD_COEFS("Ch1 - Biquad 4", 15),
329BIQUAD_COEFS("Ch2 - Biquad 1", 20),
330BIQUAD_COEFS("Ch2 - Biquad 2", 25),
331BIQUAD_COEFS("Ch2 - Biquad 3", 30),
332BIQUAD_COEFS("Ch2 - Biquad 4", 35),
333BIQUAD_COEFS("High-pass", 40),
334BIQUAD_COEFS("Low-pass", 45),
335SINGLE_COEF("Ch1 - Prescale", 50),
336SINGLE_COEF("Ch2 - Prescale", 51),
337SINGLE_COEF("Ch1 - Postscale", 52),
338SINGLE_COEF("Ch2 - Postscale", 53),
339SINGLE_COEF("Ch3 - Postscale", 54),
340SINGLE_COEF("Thermal warning - Postscale", 55),
341SINGLE_COEF("Ch1 - Mix 1", 56),
342SINGLE_COEF("Ch1 - Mix 2", 57),
343SINGLE_COEF("Ch2 - Mix 1", 58),
344SINGLE_COEF("Ch2 - Mix 2", 59),
345SINGLE_COEF("Ch3 - Mix 1", 60),
346SINGLE_COEF("Ch3 - Mix 2", 61),
235}; 347};
236 348
237static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { 349static 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
801static 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
689static const struct snd_soc_codec_driver sta32x_codec = { 812static 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),