xref: /openbmc/linux/sound/pci/au88x0/au88x0_eq.c (revision d0e22329)
1 /***************************************************************************
2  *            au88x0_eq.c
3  *  Aureal Vortex Hardware EQ control/access.
4  *
5  *  Sun Jun  8 18:19:19 2003
6  *  2003  Manuel Jander (mjander@users.sourceforge.net)
7  *
8  *  02 July 2003: First time something works :)
9  *  November 2003: A3D Bypass code completed but untested.
10  *
11  *  TODO:
12  *     - Debug (testing)
13  *     - Test peak visualization support.
14  *
15  ****************************************************************************/
16 
17 /*
18  *  This program is free software; you can redistribute it and/or modify
19  *  it under the terms of the GNU General Public License as published by
20  *  the Free Software Foundation; either version 2 of the License, or
21  *  (at your option) any later version.
22  *
23  *  This program is distributed in the hope that it will be useful,
24  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
25  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  *  GNU Library General Public License for more details.
27  *
28  *  You should have received a copy of the GNU General Public License
29  *  along with this program; if not, write to the Free Software
30  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31  */
32 
33 /*
34  The Aureal Hardware EQ is found on AU8810 and AU8830 chips only.
35  it has 4 inputs (2 for general mix, 2 for A3D) and 2 outputs (supposed
36  to be routed to the codec).
37 */
38 
39 #include "au88x0.h"
40 #include "au88x0_eq.h"
41 #include "au88x0_eqdata.c"
42 
43 #define VORTEX_EQ_BASE	 0x2b000
44 #define VORTEX_EQ_DEST   (VORTEX_EQ_BASE + 0x410)
45 #define VORTEX_EQ_SOURCE (VORTEX_EQ_BASE + 0x430)
46 #define VORTEX_EQ_CTRL   (VORTEX_EQ_BASE + 0x440)
47 
48 #define VORTEX_BAND_COEFF_SIZE 0x30
49 
50 /* CEqHw.s */
51 static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 gain, u16 level)
52 {
53 	hwwrite(vortex->mmio, 0x2b3c4, gain);
54 	hwwrite(vortex->mmio, 0x2b3c8, level);
55 }
56 
57 static inline u16 sign_invert(u16 a)
58 {
59 	/* -(-32768) -> -32768 so we do -(-32768) -> 32767 to make the result positive */
60 	if (a == (u16)-32768)
61 		return 32767;
62 	else
63 		return -a;
64 }
65 
66 static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 coefs[])
67 {
68 	eqhw_t *eqhw = &(vortex->eq.this04);
69 	int i = 0, n /*esp2c */;
70 
71 	for (n = 0; n < eqhw->this04; n++) {
72 		hwwrite(vortex->mmio, 0x2b000 + n * 0x30, coefs[i + 0]);
73 		hwwrite(vortex->mmio, 0x2b004 + n * 0x30, coefs[i + 1]);
74 
75 		if (eqhw->this08 == 0) {
76 			hwwrite(vortex->mmio, 0x2b008 + n * 0x30, coefs[i + 2]);
77 			hwwrite(vortex->mmio, 0x2b00c + n * 0x30, coefs[i + 3]);
78 			hwwrite(vortex->mmio, 0x2b010 + n * 0x30, coefs[i + 4]);
79 		} else {
80 			hwwrite(vortex->mmio, 0x2b008 + n * 0x30, sign_invert(coefs[2 + i]));
81 			hwwrite(vortex->mmio, 0x2b00c + n * 0x30, sign_invert(coefs[3 + i]));
82 		        hwwrite(vortex->mmio, 0x2b010 + n * 0x30, sign_invert(coefs[4 + i]));
83 		}
84 		i += 5;
85 	}
86 }
87 
88 static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 coefs[])
89 {
90 	eqhw_t *eqhw = &(vortex->eq.this04);
91 	int i = 0, n /*esp2c */;
92 
93 	for (n = 0; n < eqhw->this04; n++) {
94 		hwwrite(vortex->mmio, 0x2b1e0 + n * 0x30, coefs[0 + i]);
95 		hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, coefs[1 + i]);
96 
97 		if (eqhw->this08 == 0) {
98 			hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, coefs[2 + i]);
99 			hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, coefs[3 + i]);
100 			hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, coefs[4 + i]);
101 		} else {
102 			hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, sign_invert(coefs[2 + i]));
103 			hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, sign_invert(coefs[3 + i]));
104 			hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, sign_invert(coefs[4 + i]));
105 		}
106 		i += 5;
107 	}
108 
109 }
110 
111 static void vortex_EqHw_SetLeftStates(vortex_t * vortex, u16 a[], u16 b[])
112 {
113 	eqhw_t *eqhw = &(vortex->eq.this04);
114 	int i = 0, ebx;
115 
116 	hwwrite(vortex->mmio, 0x2b3fc, a[0]);
117 	hwwrite(vortex->mmio, 0x2b400, a[1]);
118 
119 	for (ebx = 0; ebx < eqhw->this04; ebx++) {
120 		hwwrite(vortex->mmio, 0x2b014 + (i * 0xc), b[i]);
121 		hwwrite(vortex->mmio, 0x2b018 + (i * 0xc), b[1 + i]);
122 		hwwrite(vortex->mmio, 0x2b01c + (i * 0xc), b[2 + i]);
123 		hwwrite(vortex->mmio, 0x2b020 + (i * 0xc), b[3 + i]);
124 		i += 4;
125 	}
126 }
127 
128 static void vortex_EqHw_SetRightStates(vortex_t * vortex, u16 a[], u16 b[])
129 {
130 	eqhw_t *eqhw = &(vortex->eq.this04);
131 	int i = 0, ebx;
132 
133 	hwwrite(vortex->mmio, 0x2b404, a[0]);
134 	hwwrite(vortex->mmio, 0x2b408, a[1]);
135 
136 	for (ebx = 0; ebx < eqhw->this04; ebx++) {
137 		hwwrite(vortex->mmio, 0x2b1f4 + (i * 0xc), b[i]);
138 		hwwrite(vortex->mmio, 0x2b1f8 + (i * 0xc), b[1 + i]);
139 		hwwrite(vortex->mmio, 0x2b1fc + (i * 0xc), b[2 + i]);
140 		hwwrite(vortex->mmio, 0x2b200 + (i * 0xc), b[3 + i]);
141 		i += 4;
142 	}
143 }
144 
145 #if 0
146 static void vortex_EqHw_GetTimeConsts(vortex_t * vortex, u16 * a, u16 * b)
147 {
148 	*a = hwread(vortex->mmio, 0x2b3c4);
149 	*b = hwread(vortex->mmio, 0x2b3c8);
150 }
151 
152 static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[])
153 {
154 
155 }
156 
157 static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[])
158 {
159 
160 }
161 
162 static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[])
163 {
164 
165 }
166 
167 static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[])
168 {
169 
170 }
171 
172 #endif
173 /* Mix Gains */
174 static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b)
175 {
176 	eqhw_t *eqhw = &(vortex->eq.this04);
177 	if (eqhw->this08 == 0) {
178 		hwwrite(vortex->mmio, 0x2b3d4, a);
179 		hwwrite(vortex->mmio, 0x2b3ec, b);
180 	} else {
181 		hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a));
182 		hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b));
183 	}
184 }
185 
186 static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
187 {
188 
189 	hwwrite(vortex->mmio, 0x2b3e0, a);
190 	hwwrite(vortex->mmio, 0x2b3f8, b);
191 }
192 
193 #if 0
194 static void vortex_EqHw_SetCurrBypassGain(vortex_t * vortex, u16 a, u16 b)
195 {
196 
197 	hwwrite(vortex->mmio, 0x2b3d0, a);
198 	hwwrite(vortex->mmio, 0x2b3e8, b);
199 }
200 
201 static void vortex_EqHw_SetCurrA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
202 {
203 
204 	hwwrite(vortex->mmio, 0x2b3dc, a);
205 	hwwrite(vortex->mmio, 0x2b3f4, b);
206 }
207 
208 #endif
209 static void
210 vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
211 {
212 	hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b);
213 }
214 
215 static void
216 vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
217 {
218 	hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b);
219 }
220 
221 static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[])
222 {
223 	eqhw_t *eqhw = &(vortex->eq.this04);
224 	int ebx;
225 
226 	for (ebx = 0; ebx < eqhw->this04; ebx++) {
227 		hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]);
228 	}
229 }
230 
231 static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[])
232 {
233 	eqhw_t *eqhw = &(vortex->eq.this04);
234 	int ebx;
235 
236 	for (ebx = 0; ebx < eqhw->this04; ebx++) {
237 		hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]);
238 	}
239 }
240 
241 static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[])
242 {
243 	eqhw_t *eqhw = &(vortex->eq.this04);
244 	int ebx;
245 
246 	for (ebx = 0; ebx < eqhw->this04; ebx++) {
247 		hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]);
248 	}
249 }
250 
251 static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[])
252 {
253 	eqhw_t *eqhw = &(vortex->eq.this04);
254 	int ebx;
255 
256 	for (ebx = 0; ebx < eqhw->this04; ebx++) {
257 		hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]);
258 	}
259 }
260 
261 #if 0
262 static void vortex_EqHw_GetLeftGainsTarget(vortex_t * vortex, u16 a[])
263 {
264 	eqhw_t *eqhw = &(vortex->eq.this04);
265 	int ebx = 0;
266 
267 	if (eqhw->this04 < 0)
268 		return;
269 
270 	do {
271 		a[ebx] = hwread(vortex->mmio, 0x2b02c + ebx * 0x30);
272 		ebx++;
273 	}
274 	while (ebx < eqhw->this04);
275 }
276 
277 static void vortex_EqHw_GetRightGainsTarget(vortex_t * vortex, u16 a[])
278 {
279 	eqhw_t *eqhw = &(vortex->eq.this04);
280 	int ebx = 0;
281 
282 	if (eqhw->this04 < 0)
283 		return;
284 
285 	do {
286 		a[ebx] = hwread(vortex->mmio, 0x2b20c + ebx * 0x30);
287 		ebx++;
288 	}
289 	while (ebx < eqhw->this04);
290 }
291 
292 static void vortex_EqHw_GetLeftGainsCurrent(vortex_t * vortex, u16 a[])
293 {
294 	eqhw_t *eqhw = &(vortex->eq.this04);
295 	int ebx = 0;
296 
297 	if (eqhw->this04 < 0)
298 		return;
299 
300 	do {
301 		a[ebx] = hwread(vortex->mmio, 0x2b028 + ebx * 0x30);
302 		ebx++;
303 	}
304 	while (ebx < eqhw->this04);
305 }
306 
307 static void vortex_EqHw_GetRightGainsCurrent(vortex_t * vortex, u16 a[])
308 {
309 	eqhw_t *eqhw = &(vortex->eq.this04);
310 	int ebx = 0;
311 
312 	if (eqhw->this04 < 0)
313 		return;
314 
315 	do {
316 		a[ebx] = hwread(vortex->mmio, 0x2b208 + ebx * 0x30);
317 		ebx++;
318 	}
319 	while (ebx < eqhw->this04);
320 }
321 
322 #endif
323 /* EQ band levels settings */
324 static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 peaks[])
325 {
326 	eqhw_t *eqhw = &(vortex->eq.this04);
327 	int i;
328 
329 	/* set left peaks */
330 	for (i = 0; i < eqhw->this04; i++) {
331 		hwwrite(vortex->mmio, 0x2b024 + i * VORTEX_BAND_COEFF_SIZE, peaks[i]);
332 	}
333 
334 	hwwrite(vortex->mmio, 0x2b3cc, peaks[eqhw->this04]);
335 	hwwrite(vortex->mmio, 0x2b3d8, peaks[eqhw->this04 + 1]);
336 
337 	/* set right peaks */
338 	for (i = 0; i < eqhw->this04; i++) {
339 		hwwrite(vortex->mmio, 0x2b204 + i * VORTEX_BAND_COEFF_SIZE,
340 			peaks[i + (eqhw->this04 + 2)]);
341 	}
342 
343 	hwwrite(vortex->mmio, 0x2b3e4, peaks[2 + (eqhw->this04 * 2)]);
344 	hwwrite(vortex->mmio, 0x2b3f0, peaks[3 + (eqhw->this04 * 2)]);
345 }
346 
347 #if 0
348 static void vortex_EqHw_GetLevels(vortex_t * vortex, u16 a[])
349 {
350 	eqhw_t *eqhw = &(vortex->eq.this04);
351 	int ebx;
352 
353 	if (eqhw->this04 < 0)
354 		return;
355 
356 	ebx = 0;
357 	do {
358 		a[ebx] = hwread(vortex->mmio, 0x2b024 + ebx * 0x30);
359 		ebx++;
360 	}
361 	while (ebx < eqhw->this04);
362 
363 	a[eqhw->this04] = hwread(vortex->mmio, 0x2b3cc);
364 	a[eqhw->this04 + 1] = hwread(vortex->mmio, 0x2b3d8);
365 
366 	ebx = 0;
367 	do {
368 		a[ebx + (eqhw->this04 + 2)] =
369 		    hwread(vortex->mmio, 0x2b204 + ebx * 0x30);
370 		ebx++;
371 	}
372 	while (ebx < eqhw->this04);
373 
374 	a[2 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3e4);
375 	a[3 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3f0);
376 }
377 
378 #endif
379 /* Global Control */
380 static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg)
381 {
382 	hwwrite(vortex->mmio, 0x2b440, reg);
383 }
384 
385 static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr)
386 {
387 	hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
388 }
389 
390 #if 0
391 static void vortex_EqHw_GetControlReg(vortex_t * vortex, u32 *reg)
392 {
393 	*reg = hwread(vortex->mmio, 0x2b440);
394 }
395 
396 static void vortex_EqHw_GetSampleRate(vortex_t * vortex, u32 *sr)
397 {
398 	*sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f;
399 }
400 
401 #endif
402 static void vortex_EqHw_Enable(vortex_t * vortex)
403 {
404 	hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001);
405 }
406 
407 static void vortex_EqHw_Disable(vortex_t * vortex)
408 {
409 	hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000);
410 }
411 
412 /* Reset (zero) buffers */
413 static void vortex_EqHw_ZeroIO(vortex_t * vortex)
414 {
415 	int i;
416 	for (i = 0; i < 0x8; i++)
417 		hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
418 	for (i = 0; i < 0x4; i++)
419 		hwwrite(vortex->mmio, VORTEX_EQ_SOURCE + (i << 2), 0x0);
420 }
421 
422 static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex)
423 {
424 	int i;
425 	for (i = 0; i < 0x4; i++)
426 		hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
427 }
428 
429 static void vortex_EqHw_ZeroState(vortex_t * vortex)
430 {
431 
432 	vortex_EqHw_SetControlReg(vortex, 0);
433 	vortex_EqHw_ZeroIO(vortex);
434 	hwwrite(vortex->mmio, 0x2b3c0, 0);
435 
436 	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
437 
438 	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros);
439 	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros);
440 
441 	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero);
442 	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero);
443 	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero);
444 	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero);
445 
446 	vortex_EqHw_SetBypassGain(vortex, 0, 0);
447 	//vortex_EqHw_SetCurrBypassGain(vortex, 0, 0);
448 	vortex_EqHw_SetA3DBypassGain(vortex, 0, 0);
449 	//vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0);
450 	vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros);
451 	vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros);
452 	vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels);
453 }
454 
455 /* Program coeficients as pass through */
456 static void vortex_EqHw_ProgramPipe(vortex_t * vortex)
457 {
458 	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
459 
460 	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes);
461 	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes);
462 
463 	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current);
464 	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current);
465 	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current);
466 	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current);
467 }
468 
469 /* Program EQ block as 10 band Equalizer */
470 static void
471 vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset)
472 {
473 
474 	vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0);
475 
476 	vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs);
477 	vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs);
478 
479 	vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains);
480 
481 	vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains);
482 	vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains);
483 
484 	vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains);
485 }
486 
487 /* Read all EQ peaks. (think VU meter) */
488 static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[])
489 {
490 	eqhw_t *eqhw = &(vortex->eq.this04);
491 	int i;
492 
493 	if (eqhw->this04 <= 0)
494 		return;
495 
496 	for (i = 0; i < eqhw->this04; i++)
497 		peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30);
498 	for (i = 0; i < eqhw->this04; i++)
499 		peaks[i + eqhw->this04] =
500 		    hwread(vortex->mmio, 0x2B204 + i * 0x30);
501 }
502 
503 /* CEqlzr.s */
504 
505 static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain)
506 {
507 	eqlzr_t *eq = &(vortex->eq);
508 
509 	if (eq->this28) {
510 		*gain = eq->this130[index];
511 		return 0;
512 	}
513 	return 1;
514 }
515 
516 static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain)
517 {
518 	eqlzr_t *eq = &(vortex->eq);
519 
520 	if (eq->this28 == 0)
521 		return;
522 
523 	eq->this130[index] = gain;
524 	if (eq->this54)
525 		return;
526 
527 	vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain);
528 }
529 
530 static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain)
531 {
532 	eqlzr_t *eq = &(vortex->eq);
533 
534 	if (eq->this28) {
535 		*gain = eq->this130[index + eq->this10];
536 		return 0;
537 	}
538 	return 1;
539 }
540 
541 static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain)
542 {
543 	eqlzr_t *eq = &(vortex->eq);
544 
545 	if (eq->this28 == 0)
546 		return;
547 
548 	eq->this130[index + eq->this10] = gain;
549 	if (eq->this54)
550 		return;
551 
552 	vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain);
553 }
554 
555 #if 0
556 static int
557 vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, s32 *cnt)
558 {
559 	eqlzr_t *eq = &(vortex->eq);
560 	int si = 0;
561 
562 	if (eq->this10 == 0)
563 		return 1;
564 
565 	{
566 		if (vortex_Eqlzr_GetLeftGain(vortex, si, &gains[si]))
567 			return 1;
568 		if (vortex_Eqlzr_GetRightGain
569 		    (vortex, si, &gains[si + eq->this10]))
570 			return 1;
571 		si++;
572 	}
573 	while (eq->this10 > si) ;
574 	*cnt = si * 2;
575 	return 0;
576 }
577 #endif
578 static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
579 {
580 	eqlzr_t *eq = &(vortex->eq);
581 
582 	vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
583 	vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
584 
585 	return 0;
586 }
587 
588 static int
589 vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count)
590 {
591 	eqlzr_t *eq = &(vortex->eq);
592 	int i;
593 
594 	if (((eq->this10) * 2 != count) || (eq->this28 == 0))
595 		return 1;
596 
597 	for (i = 0; i < count; i++) {
598 		eq->this130[i] = gains[i];
599 	}
600 
601 	if (eq->this54)
602 		return 0;
603 	return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
604 }
605 
606 static void
607 vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b)
608 {
609 	eqlzr_t *eq = &(vortex->eq);
610 	u32 eax, ebx;
611 
612 	eq->this58 = a;
613 	eq->this5c = b;
614 	if (eq->this54)
615 		eax = eq->this0e;
616 	else
617 		eax = eq->this0a;
618 	ebx = (eax * eq->this58) >> 0x10;
619 	eax = (eax * eq->this5c) >> 0x10;
620 	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
621 }
622 
623 static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
624 {
625 	eqlzr_t *eq = &(vortex->eq);
626 	u32 eax, ebx;
627 
628 	if (eq->this54)
629 		eax = eq->this0e;
630 	else
631 		eax = eq->this0a;
632 	ebx = (eax * eq->this58) >> 0x10;
633 	eax = (eax * eq->this5c) >> 0x10;
634 	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
635 }
636 
637 static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex)
638 {
639 	if (vortex != NULL)
640 		vortex_EqHw_ZeroA3DIO(vortex);
641 }
642 
643 static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp)
644 {
645 	eqlzr_t *eq = &(vortex->eq);
646 
647 	if ((eq->this28) && (bp == 0)) {
648 		/* EQ enabled */
649 		vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
650 		vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
651 	} else {
652 		/* EQ disabled. */
653 		vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array);
654 		vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array);
655 		vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
656 	}
657 	vortex_Eqlzr_ProgramA3dBypassGain(vortex);
658 }
659 
660 static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex)
661 {
662 	eqlzr_t *eq = &(vortex->eq);
663 
664 	/* Set EQ BiQuad filter coeficients */
665 	memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t));
666 	/* Set EQ Band gain levels and dump into hardware registers. */
667 	vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2);
668 }
669 
670 static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count)
671 {
672 	eqlzr_t *eq = &(vortex->eq);
673 
674 	if (eq->this10 == 0)
675 		return 1;
676 	*count = eq->this10 * 2;
677 	vortex_EqHw_GetTenBandLevels(vortex, peaks);
678 	return 0;
679 }
680 
681 #if 0
682 static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex)
683 {
684 	eqlzr_t *eq = &(vortex->eq);
685 
686 	return (&(eq->coefset));
687 }
688 #endif
689 static void vortex_Eqlzr_init(vortex_t * vortex)
690 {
691 	eqlzr_t *eq = &(vortex->eq);
692 
693 	/* Object constructor */
694 	//eq->this04 = 0;
695 	eq->this08 = 0;		/* Bypass gain with EQ in use. */
696 	eq->this0a = 0x5999;
697 	eq->this0c = 0x5999;	/* Bypass gain with EQ disabled. */
698 	eq->this0e = 0x5999;
699 
700 	eq->this10 = 0xa;	/* 10 eq frequency bands. */
701 	eq->this04.this04 = eq->this10;
702 	eq->this28 = 0x1;	/* if 1 => Allow read access to this130 (gains) */
703 	eq->this54 = 0x0;	/* if 1 => Dont Allow access to hardware (gains) */
704 	eq->this58 = 0xffff;
705 	eq->this5c = 0xffff;
706 
707 	/* Set gains. */
708 	memset(eq->this14_array, 0, sizeof(eq->this14_array));
709 
710 	/* Actual init. */
711 	vortex_EqHw_ZeroState(vortex);
712 	vortex_EqHw_SetSampleRate(vortex, 0x11);
713 	vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex);
714 
715 	vortex_EqHw_Program10Band(vortex, &(eq->coefset));
716 	vortex_Eqlzr_SetBypass(vortex, eq->this54);
717 	vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0);
718 	vortex_EqHw_Enable(vortex);
719 }
720 
721 static void vortex_Eqlzr_shutdown(vortex_t * vortex)
722 {
723 	vortex_Eqlzr_ShutDownA3d(vortex);
724 	vortex_EqHw_ProgramPipe(vortex);
725 	vortex_EqHw_Disable(vortex);
726 }
727 
728 /* ALSA interface */
729 
730 /* Control interface */
731 #define snd_vortex_eqtoggle_info	snd_ctl_boolean_mono_info
732 
733 static int
734 snd_vortex_eqtoggle_get(struct snd_kcontrol *kcontrol,
735 			struct snd_ctl_elem_value *ucontrol)
736 {
737 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
738 	eqlzr_t *eq = &(vortex->eq);
739 	//int i = kcontrol->private_value;
740 
741 	ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1;
742 
743 	return 0;
744 }
745 
746 static int
747 snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol,
748 			struct snd_ctl_elem_value *ucontrol)
749 {
750 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
751 	eqlzr_t *eq = &(vortex->eq);
752 	//int i = kcontrol->private_value;
753 
754 	eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1;
755 	vortex_Eqlzr_SetBypass(vortex, eq->this54);
756 
757 	return 1;		/* Allways changes */
758 }
759 
760 static const struct snd_kcontrol_new vortex_eqtoggle_kcontrol = {
761 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
762 	.name = "EQ Enable",
763 	.index = 0,
764 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
765 	.private_value = 0,
766 	.info = snd_vortex_eqtoggle_info,
767 	.get = snd_vortex_eqtoggle_get,
768 	.put = snd_vortex_eqtoggle_put
769 };
770 
771 static int
772 snd_vortex_eq_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
773 {
774 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
775 	uinfo->count = 2;
776 	uinfo->value.integer.min = 0x0000;
777 	uinfo->value.integer.max = 0x7fff;
778 	return 0;
779 }
780 
781 static int
782 snd_vortex_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
783 {
784 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
785 	int i = kcontrol->private_value;
786 	u16 gainL = 0, gainR = 0;
787 
788 	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
789 	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
790 	ucontrol->value.integer.value[0] = gainL;
791 	ucontrol->value.integer.value[1] = gainR;
792 	return 0;
793 }
794 
795 static int
796 snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
797 {
798 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
799 	int changed = 0, i = kcontrol->private_value;
800 	u16 gainL = 0, gainR = 0;
801 
802 	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
803 	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
804 
805 	if (gainL != ucontrol->value.integer.value[0]) {
806 		vortex_Eqlzr_SetLeftGain(vortex, i,
807 					 ucontrol->value.integer.value[0]);
808 		changed = 1;
809 	}
810 	if (gainR != ucontrol->value.integer.value[1]) {
811 		vortex_Eqlzr_SetRightGain(vortex, i,
812 					  ucontrol->value.integer.value[1]);
813 		changed = 1;
814 	}
815 	return changed;
816 }
817 
818 static const struct snd_kcontrol_new vortex_eq_kcontrol = {
819 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
820 	.name = "                        .",
821 	.index = 0,
822 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
823 	.private_value = 0,
824 	.info = snd_vortex_eq_info,
825 	.get = snd_vortex_eq_get,
826 	.put = snd_vortex_eq_put
827 };
828 
829 static int
830 snd_vortex_peaks_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
831 {
832 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
833 	uinfo->count = 20;
834 	uinfo->value.integer.min = 0x0000;
835 	uinfo->value.integer.max = 0x7fff;
836 	return 0;
837 }
838 
839 static int
840 snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
841 {
842 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
843 	int i, count = 0;
844 	u16 peaks[20];
845 
846 	vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
847 	if (count != 20) {
848 		dev_err(vortex->card->dev,
849 			"peak count error 20 != %d\n", count);
850 		return -1;
851 	}
852 	for (i = 0; i < 20; i++)
853 		ucontrol->value.integer.value[i] = peaks[i];
854 
855 	return 0;
856 }
857 
858 static const struct snd_kcontrol_new vortex_levels_kcontrol = {
859 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
860 	.name = "EQ Peaks",
861 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
862 	.info = snd_vortex_peaks_info,
863 	.get = snd_vortex_peaks_get,
864 };
865 
866 /* EQ band gain labels. */
867 static char *EqBandLabels[10] = {
868 	"EQ0 31Hz\0",
869 	"EQ1 63Hz\0",
870 	"EQ2 125Hz\0",
871 	"EQ3 250Hz\0",
872 	"EQ4 500Hz\0",
873 	"EQ5 1KHz\0",
874 	"EQ6 2KHz\0",
875 	"EQ7 4KHz\0",
876 	"EQ8 8KHz\0",
877 	"EQ9 16KHz\0",
878 };
879 
880 /* ALSA driver entry points. Init and exit. */
881 static int vortex_eq_init(vortex_t *vortex)
882 {
883 	struct snd_kcontrol *kcontrol;
884 	int err, i;
885 
886 	vortex_Eqlzr_init(vortex);
887 
888 	if ((kcontrol =
889 	     snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL)
890 		return -ENOMEM;
891 	kcontrol->private_value = 0;
892 	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
893 		return err;
894 
895 	/* EQ gain controls */
896 	for (i = 0; i < 10; i++) {
897 		if ((kcontrol =
898 		     snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
899 			return -ENOMEM;
900 		snprintf(kcontrol->id.name, sizeof(kcontrol->id.name),
901 			"%s Playback Volume", EqBandLabels[i]);
902 		kcontrol->private_value = i;
903 		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
904 			return err;
905 		//vortex->eqctrl[i] = kcontrol;
906 	}
907 	/* EQ band levels */
908 	if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL)
909 		return -ENOMEM;
910 	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
911 		return err;
912 
913 	return 0;
914 }
915 
916 static int vortex_eq_free(vortex_t * vortex)
917 {
918 	/*
919 	   //FIXME: segfault because vortex->eqctrl[i] == 4
920 	   int i;
921 	   for (i=0; i<10; i++) {
922 	   if (vortex->eqctrl[i])
923 	   snd_ctl_remove(vortex->card, vortex->eqctrl[i]);
924 	   }
925 	 */
926 	vortex_Eqlzr_shutdown(vortex);
927 	return 0;
928 }
929 
930 /* End */
931