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