blob: 9492f3d2455b4aee6d6d6f8b84c02ec239e95582 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ALSA driver for ICEnsemble VT1724 (Envy24HT)
3 *
4 * Lowlevel functions for Terratec Aureon cards
5 *
6 * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 *
23 * NOTES:
24 *
Takashi Iwaiab0c7d72005-11-17 15:00:18 +010025 * - we reuse the struct snd_akm4xxx record for storing the wm8770 codec data.
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 * both wm and akm codecs are pretty similar, so we can integrate
27 * both controls in the future, once if wm codecs are reused in
28 * many boards.
29 *
30 * - DAC digital volumes are not implemented in the mixer.
31 * if they show better response than DAC analog volumes, we can use them
32 * instead.
33 *
34 * Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards
35 * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca>
36 *
37 * version 0.82: Stable / not all features work yet (no communication with AC97 secondary)
38 * added 64x/128x oversampling switch (should be 64x only for 96khz)
39 * fixed some recording labels (still need to check the rest)
40 * recording is working probably thanks to correct wm8770 initialization
41 *
42 * version 0.5: Initial release:
43 * working: analog output, mixer, headphone amplifier switch
44 * not working: prety much everything else, at least i could verify that
45 * we have no digital output, no capture, pretty bad clicks and poops
46 * on mixer switch and other coll stuff.
47 *
48 */
49
50#include <sound/driver.h>
51#include <asm/io.h>
52#include <linux/delay.h>
53#include <linux/interrupt.h>
54#include <linux/init.h>
55#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010056#include <linux/mutex.h>
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <sound/core.h>
59
60#include "ice1712.h"
61#include "envy24ht.h"
62#include "aureon.h"
63
64/* WM8770 registers */
65#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
66#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
67#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
68#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
69#define WM_PHASE_SWAP 0x12 /* DAC phase */
70#define WM_DAC_CTRL1 0x13 /* DAC control bits */
71#define WM_MUTE 0x14 /* mute controls */
72#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
73#define WM_INT_CTRL 0x16 /* interface control */
74#define WM_MASTER 0x17 /* master clock and mode */
75#define WM_POWERDOWN 0x18 /* power-down controls */
76#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
77#define WM_ADC_MUX 0x1b /* input MUX */
78#define WM_OUT_MUX1 0x1c /* output MUX */
79#define WM_OUT_MUX2 0x1e /* output MUX */
80#define WM_RESET 0x1f /* software reset */
81
82/* CS8415A registers */
83#define CS8415_CTRL1 0x01
84#define CS8415_CTRL2 0x02
85#define CS8415_QSUB 0x14
86#define CS8415_RATIO 0x1E
87#define CS8415_C_BUFFER 0x20
88#define CS8415_ID 0x7F
89
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +020090/* PCA9554 registers */
91#define PCA9554_DEV 0x40 /* I2C device address */
92#define PCA9554_IN 0x00 /* input port */
93#define PCA9554_OUT 0x01 /* output port */
94#define PCA9554_INVERT 0x02 /* input invert */
95#define PCA9554_DIR 0x03 /* port directions */
96
97/*
98 * Aureon Universe additional controls using PCA9554
99 */
100
101/*
102 * Send data to pca9554
103 */
104static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
105 unsigned char data)
106{
107 unsigned int tmp;
108 int i, j;
109 unsigned char dev = PCA9554_DEV; /* ID 0100000, write */
110 unsigned char val = 0;
111
112 tmp = snd_ice1712_gpio_read(ice);
113
114 snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK|
115 AUREON_WM_RW|AUREON_WM_CS|
116 AUREON_CS8415_CS));
117 tmp |= AUREON_WM_RW;
118 tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */
119
120 tmp &= ~AUREON_SPI_MOSI;
121 tmp &= ~AUREON_SPI_CLK;
122 snd_ice1712_gpio_write(ice, tmp);
123 udelay(50);
124
125 /*
126 * send i2c stop condition and start condition
127 * to obtain sane state
128 */
129 tmp |= AUREON_SPI_CLK;
130 snd_ice1712_gpio_write(ice, tmp);
131 udelay(50);
132 tmp |= AUREON_SPI_MOSI;
133 snd_ice1712_gpio_write(ice, tmp);
134 udelay(100);
135 tmp &= ~AUREON_SPI_MOSI;
136 snd_ice1712_gpio_write(ice, tmp);
137 udelay(50);
138 tmp &= ~AUREON_SPI_CLK;
139 snd_ice1712_gpio_write(ice, tmp);
140 udelay(100);
141 /*
142 * send device address, command and value,
143 * skipping ack cycles inbetween
144 */
145 for (j = 0; j < 3; j++) {
146 switch(j) {
147 case 0: val = dev; break;
148 case 1: val = reg; break;
149 case 2: val = data; break;
150 }
151 for (i = 7; i >= 0; i--) {
152 tmp &= ~AUREON_SPI_CLK;
153 snd_ice1712_gpio_write(ice, tmp);
154 udelay(40);
155 if (val & (1 << i))
156 tmp |= AUREON_SPI_MOSI;
157 else
158 tmp &= ~AUREON_SPI_MOSI;
159 snd_ice1712_gpio_write(ice, tmp);
160 udelay(40);
161 tmp |= AUREON_SPI_CLK;
162 snd_ice1712_gpio_write(ice, tmp);
163 udelay(40);
164 }
165 tmp &= ~AUREON_SPI_CLK;
166 snd_ice1712_gpio_write(ice, tmp);
167 udelay(40);
168 tmp |= AUREON_SPI_CLK;
169 snd_ice1712_gpio_write(ice, tmp);
170 udelay(40);
171 tmp &= ~AUREON_SPI_CLK;
172 snd_ice1712_gpio_write(ice, tmp);
173 udelay(40);
174 }
175 tmp &= ~AUREON_SPI_CLK;
176 snd_ice1712_gpio_write(ice, tmp);
177 udelay(40);
178 tmp &= ~AUREON_SPI_MOSI;
179 snd_ice1712_gpio_write(ice, tmp);
180 udelay(40);
181 tmp |= AUREON_SPI_CLK;
182 snd_ice1712_gpio_write(ice, tmp);
183 udelay(50);
184 tmp |= AUREON_SPI_MOSI;
185 snd_ice1712_gpio_write(ice, tmp);
186 udelay(100);
187}
188
189static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
190 struct snd_ctl_elem_info *uinfo)
191{
192 char *texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"};
193
194 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
195 uinfo->count = 1;
196 uinfo->value.enumerated.items = 3;
197 if(uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
198 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
199 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
200 return 0;
201}
202
203static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
204 struct snd_ctl_elem_value *ucontrol)
205{
206 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
207 ucontrol->value.integer.value[0] = ice->spec.aureon.pca9554_out;
208 return 0;
209}
210
211static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
212 struct snd_ctl_elem_value *ucontrol)
213{
214 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
215 unsigned char oval, nval;
216 int change;
217
218 snd_ice1712_save_gpio_status(ice);
219
220 oval = ice->spec.aureon.pca9554_out;
221 nval = ucontrol->value.integer.value[0];
222 if ((change = (oval != nval))) {
223 aureon_pca9554_write(ice, PCA9554_OUT, nval);
224 ice->spec.aureon.pca9554_out = nval;
225 }
226 snd_ice1712_restore_gpio_status(ice);
227
228 return change;
229}
230
231
232static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
233 unsigned short val)
234{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 unsigned int tmp;
236
237 /* Send address to XILINX chip */
238 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
239 snd_ice1712_gpio_write(ice, tmp);
240 udelay(10);
241 tmp |= AUREON_AC97_ADDR;
242 snd_ice1712_gpio_write(ice, tmp);
243 udelay(10);
244 tmp &= ~AUREON_AC97_ADDR;
245 snd_ice1712_gpio_write(ice, tmp);
246 udelay(10);
247
248 /* Send low-order byte to XILINX chip */
249 tmp &= ~AUREON_AC97_DATA_MASK;
250 tmp |= val & AUREON_AC97_DATA_MASK;
251 snd_ice1712_gpio_write(ice, tmp);
252 udelay(10);
253 tmp |= AUREON_AC97_DATA_LOW;
254 snd_ice1712_gpio_write(ice, tmp);
255 udelay(10);
256 tmp &= ~AUREON_AC97_DATA_LOW;
257 snd_ice1712_gpio_write(ice, tmp);
258 udelay(10);
259
260 /* Send high-order byte to XILINX chip */
261 tmp &= ~AUREON_AC97_DATA_MASK;
262 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
263
264 snd_ice1712_gpio_write(ice, tmp);
265 udelay(10);
266 tmp |= AUREON_AC97_DATA_HIGH;
267 snd_ice1712_gpio_write(ice, tmp);
268 udelay(10);
269 tmp &= ~AUREON_AC97_DATA_HIGH;
270 snd_ice1712_gpio_write(ice, tmp);
271 udelay(10);
272
273 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
274 tmp |= AUREON_AC97_COMMIT;
275 snd_ice1712_gpio_write(ice, tmp);
276 udelay(10);
277 tmp &= ~AUREON_AC97_COMMIT;
278 snd_ice1712_gpio_write(ice, tmp);
279 udelay(10);
280
281 /* Store the data in out private buffer */
282 ice->spec.aureon.stac9744[(reg & 0x7F) >> 1] = val;
283}
284
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100285static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
287 return ice->spec.aureon.stac9744[(reg & 0x7F) >> 1];
288}
289
290/*
291 * Initialize STAC9744 chip
292 */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200293static int aureon_ac97_init (struct snd_ice1712 *ice)
294{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 int i;
296 static unsigned short ac97_defaults[] = {
297 0x00, 0x9640,
298 0x02, 0x8000,
299 0x04, 0x8000,
300 0x06, 0x8000,
301 0x0C, 0x8008,
302 0x0E, 0x8008,
303 0x10, 0x8808,
304 0x12, 0x8808,
305 0x14, 0x8808,
306 0x16, 0x8808,
307 0x18, 0x8808,
308 0x1C, 0x8000,
309 0x26, 0x000F,
310 0x28, 0x0201,
311 0x2C, 0xBB80,
312 0x32, 0xBB80,
313 0x7C, 0x8384,
314 0x7E, 0x7644,
315 (unsigned short)-1
316 };
317 unsigned int tmp;
318
319 /* Cold reset */
320 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
321 snd_ice1712_gpio_write(ice, tmp);
322 udelay(3);
323
324 tmp &= ~AUREON_AC97_RESET;
325 snd_ice1712_gpio_write(ice, tmp);
326 udelay(3);
327
328 tmp |= AUREON_AC97_RESET;
329 snd_ice1712_gpio_write(ice, tmp);
330 udelay(3);
331
332 memset(&ice->spec.aureon.stac9744, 0, sizeof(ice->spec.aureon.stac9744));
333 for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
334 ice->spec.aureon.stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
335
336 aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
337
338 return 0;
339}
340
341#define AUREON_AC97_STEREO 0x80
342
343/*
344 * AC'97 volume controls
345 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100346static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
349 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
350 uinfo->value.integer.min = 0;
351 uinfo->value.integer.max = 31;
352 return 0;
353}
354
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100355static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100357 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 unsigned short vol;
359
Ingo Molnar62932df2006-01-16 16:34:20 +0100360 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
363 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
364 if (kcontrol->private_value & AUREON_AC97_STEREO)
365 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
366
Ingo Molnar62932df2006-01-16 16:34:20 +0100367 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 return 0;
369}
370
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100371static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100373 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 unsigned short ovol, nvol;
375 int change;
376
377 snd_ice1712_save_gpio_status(ice);
378
379 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
380 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
381 if (kcontrol->private_value & AUREON_AC97_STEREO)
382 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
383 nvol |= ovol & ~0x1F1F;
384
385 if ((change = (ovol != nvol)))
386 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
387
388 snd_ice1712_restore_gpio_status(ice);
389
390 return change;
391}
392
393/*
394 * AC'97 mute controls
395 */
396#define aureon_ac97_mute_info aureon_mono_bool_info
397
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100398static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100400 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Ingo Molnar62932df2006-01-16 16:34:20 +0100402 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
405
Ingo Molnar62932df2006-01-16 16:34:20 +0100406 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 return 0;
408}
409
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100410static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100412 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 unsigned short ovol, nvol;
414 int change;
415
416 snd_ice1712_save_gpio_status(ice);
417
418 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
419 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~ 0x8000);
420
421 if ((change = (ovol != nvol)))
422 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
423
424 snd_ice1712_restore_gpio_status(ice);
425
426 return change;
427}
428
429/*
430 * AC'97 mute controls
431 */
432#define aureon_ac97_micboost_info aureon_mono_bool_info
433
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100434static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100436 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Ingo Molnar62932df2006-01-16 16:34:20 +0100438 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
441
Ingo Molnar62932df2006-01-16 16:34:20 +0100442 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 return 0;
444}
445
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100446static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100448 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 unsigned short ovol, nvol;
450 int change;
451
452 snd_ice1712_save_gpio_status(ice);
453
454 ovol = aureon_ac97_read(ice, AC97_MIC);
455 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
456
457 if ((change = (ovol != nvol)))
458 aureon_ac97_write(ice, AC97_MIC, nvol);
459
460 snd_ice1712_restore_gpio_status(ice);
461
462 return change;
463}
464
465/*
466 * write data in the SPI mode
467 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100468static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
470 unsigned int tmp;
471 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100472 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
474 tmp = snd_ice1712_gpio_read(ice);
475
Takashi Iwai45fe7222006-01-13 13:50:16 +0100476 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
477 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
478 mosi = PRODIGY_SPI_MOSI;
479 clk = PRODIGY_SPI_CLK;
480 }
481 else {
482 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
483 AUREON_WM_CS|AUREON_CS8415_CS));
484 mosi = AUREON_SPI_MOSI;
485 clk = AUREON_SPI_CLK;
486
487 tmp |= AUREON_WM_RW;
488 }
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 tmp &= ~cs;
491 snd_ice1712_gpio_write(ice, tmp);
492 udelay(1);
493
494 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100495 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 snd_ice1712_gpio_write(ice, tmp);
497 udelay(1);
498 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100499 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100501 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 snd_ice1712_gpio_write(ice, tmp);
503 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100504 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 snd_ice1712_gpio_write(ice, tmp);
506 udelay(1);
507 }
508
Takashi Iwai45fe7222006-01-13 13:50:16 +0100509 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 tmp |= cs;
511 snd_ice1712_gpio_write(ice, tmp);
512 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100513 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 snd_ice1712_gpio_write(ice, tmp);
515 udelay(1);
516}
517
518/*
519 * Read data in SPI mode
520 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100521static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 int i, j;
523 unsigned int tmp;
524
525 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
526 snd_ice1712_gpio_write(ice, tmp);
527 tmp &= ~cs;
528 snd_ice1712_gpio_write(ice, tmp);
529 udelay(1);
530
531 for (i=bits-1; i>=0; i--) {
532 if (data & (1 << i))
533 tmp |= AUREON_SPI_MOSI;
534 else
535 tmp &= ~AUREON_SPI_MOSI;
536 snd_ice1712_gpio_write(ice, tmp);
537 udelay(1);
538
539 tmp |= AUREON_SPI_CLK;
540 snd_ice1712_gpio_write(ice, tmp);
541 udelay(1);
542
543 tmp &= ~AUREON_SPI_CLK;
544 snd_ice1712_gpio_write(ice, tmp);
545 udelay(1);
546 }
547
548 for (j=0; j<size; j++) {
549 unsigned char outdata = 0;
550 for (i=7; i>=0; i--) {
551 tmp = snd_ice1712_gpio_read(ice);
552 outdata <<= 1;
553 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
554 udelay(1);
555
556 tmp |= AUREON_SPI_CLK;
557 snd_ice1712_gpio_write(ice, tmp);
558 udelay(1);
559
560 tmp &= ~AUREON_SPI_CLK;
561 snd_ice1712_gpio_write(ice, tmp);
562 udelay(1);
563 }
564 buffer[j] = outdata;
565 }
566
567 tmp |= cs;
568 snd_ice1712_gpio_write(ice, tmp);
569}
570
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100571static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 unsigned char val;
573 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
574 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
575 return val;
576}
577
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100578static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
580 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
581}
582
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100583static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
585}
586
587/*
588 * get the current register value of WM codec
589 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100590static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
592 reg <<= 1;
593 return ((unsigned short)ice->akm[0].images[reg] << 8) |
594 ice->akm[0].images[reg + 1];
595}
596
597/*
598 * set the register value of WM codec
599 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100600static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100602 aureon_spi_write(ice,
603 (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
604 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605}
606
607/*
608 * set the register value of WM codec and remember it
609 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100610static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
612 wm_put_nocache(ice, reg, val);
613 reg <<= 1;
614 ice->akm[0].images[reg] = val >> 8;
615 ice->akm[0].images[reg + 1] = val;
616}
617
618/*
619 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100620static int aureon_mono_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
622 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
623 uinfo->count = 1;
624 uinfo->value.integer.min = 0;
625 uinfo->value.integer.max = 1;
626 return 0;
627}
628
629/*
630 * AC'97 master playback mute controls (Mute on WM8770 chip)
631 */
632#define aureon_ac97_mmute_info aureon_mono_bool_info
633
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100634static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100636 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Ingo Molnar62932df2006-01-16 16:34:20 +0100638 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
641
Ingo Molnar62932df2006-01-16 16:34:20 +0100642 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 return 0;
644}
645
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100646static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
647 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 unsigned short ovol, nvol;
649 int change;
650
651 snd_ice1712_save_gpio_status(ice);
652
653 ovol = wm_get(ice, WM_OUT_MUX1);
654 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
655 if ((change = (ovol != nvol)))
656 wm_put(ice, WM_OUT_MUX1, nvol);
657
658 snd_ice1712_restore_gpio_status(ice);
659
660 return change;
661}
662
663/*
664 * Logarithmic volume values for WM8770
665 * Computed as 20 * Log10(255 / x)
666 */
667static unsigned char wm_vol[256] = {
668 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
669 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
670 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
671 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
672 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
673 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
674 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
675 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
676 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
677 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
678 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
679 0, 0
680};
681
682#define WM_VOL_MAX (sizeof(wm_vol) - 1)
683#define WM_VOL_MUTE 0x8000
684
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100685static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 unsigned char nvol;
688
689 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
690 nvol = 0;
691 else
692 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
693
694 wm_put(ice, index, nvol);
695 wm_put_nocache(ice, index, 0x180 | nvol);
696}
697
698/*
699 * DAC mute control
700 */
701#define wm_pcm_mute_info aureon_mono_bool_info
702
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100703static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100705 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Ingo Molnar62932df2006-01-16 16:34:20 +0100707 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100709 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 return 0;
711}
712
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100713static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100715 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 unsigned short nval, oval;
717 int change;
718
719 snd_ice1712_save_gpio_status(ice);
720 oval = wm_get(ice, WM_MUTE);
721 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
722 if ((change = (nval != oval)))
723 wm_put(ice, WM_MUTE, nval);
724 snd_ice1712_restore_gpio_status(ice);
725
726 return change;
727}
728
729/*
730 * Master volume attenuation mixer control
731 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100732static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733{
734 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
735 uinfo->count = 2;
736 uinfo->value.integer.min = 0;
737 uinfo->value.integer.max = WM_VOL_MAX;
738 return 0;
739}
740
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100741static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100743 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 int i;
745 for (i=0; i<2; i++)
746 ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE;
747 return 0;
748}
749
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100750static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100752 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 int ch, change = 0;
754
755 snd_ice1712_save_gpio_status(ice);
756 for (ch = 0; ch < 2; ch++) {
757 if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) {
758 int dac;
759 ice->spec.aureon.master[ch] &= WM_VOL_MUTE;
760 ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch];
761 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
762 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
763 ice->spec.aureon.vol[dac + ch],
764 ice->spec.aureon.master[ch]);
765 change = 1;
766 }
767 }
768 snd_ice1712_restore_gpio_status(ice);
769 return change;
770}
771
772/*
773 * DAC volume attenuation mixer control
774 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100775static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
777 int voices = kcontrol->private_value >> 8;
778 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
779 uinfo->count = voices;
780 uinfo->value.integer.min = 0; /* mute (-101dB) */
781 uinfo->value.integer.max = 0x7F; /* 0dB */
782 return 0;
783}
784
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100785static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100787 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 int i, ofs, voices;
789
790 voices = kcontrol->private_value >> 8;
791 ofs = kcontrol->private_value & 0xff;
792 for (i = 0; i < voices; i++)
793 ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE;
794 return 0;
795}
796
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100797static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100799 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 int i, idx, ofs, voices;
801 int change = 0;
802
803 voices = kcontrol->private_value >> 8;
804 ofs = kcontrol->private_value & 0xff;
805 snd_ice1712_save_gpio_status(ice);
806 for (i = 0; i < voices; i++) {
807 idx = WM_DAC_ATTEN + ofs + i;
808 if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) {
809 ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE;
810 ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i];
811 wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i],
812 ice->spec.aureon.master[i]);
813 change = 1;
814 }
815 }
816 snd_ice1712_restore_gpio_status(ice);
817 return change;
818}
819
820/*
821 * WM8770 mute control
822 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100823static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
825 uinfo->count = kcontrol->private_value >> 8;
826 uinfo->value.integer.min = 0;
827 uinfo->value.integer.max = 1;
828 return 0;
829}
830
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100831static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100833 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 int voices, ofs, i;
835
836 voices = kcontrol->private_value >> 8;
837 ofs = kcontrol->private_value & 0xFF;
838
839 for (i = 0; i < voices; i++)
840 ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
841 return 0;
842}
843
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100844static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100846 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 int change = 0, voices, ofs, i;
848
849 voices = kcontrol->private_value >> 8;
850 ofs = kcontrol->private_value & 0xFF;
851
852 snd_ice1712_save_gpio_status(ice);
853 for (i = 0; i < voices; i++) {
854 int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
855 if (ucontrol->value.integer.value[i] != val) {
856 ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE;
857 ice->spec.aureon.vol[ofs + i] |=
858 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
859 wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i],
860 ice->spec.aureon.master[i]);
861 change = 1;
862 }
863 }
864 snd_ice1712_restore_gpio_status(ice);
865
866 return change;
867}
868
869/*
870 * WM8770 master mute control
871 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100872static int wm_master_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
874 uinfo->count = 2;
875 uinfo->value.integer.min = 0;
876 uinfo->value.integer.max = 1;
877 return 0;
878}
879
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100880static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100882 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1;
885 ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1;
886 return 0;
887}
888
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100889static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100891 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 int change = 0, i;
893
894 snd_ice1712_save_gpio_status(ice);
895 for (i = 0; i < 2; i++) {
896 int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1;
897 if (ucontrol->value.integer.value[i] != val) {
898 int dac;
899 ice->spec.aureon.master[i] &= ~WM_VOL_MUTE;
900 ice->spec.aureon.master[i] |=
901 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
902 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
903 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
904 ice->spec.aureon.vol[dac + i],
905 ice->spec.aureon.master[i]);
906 change = 1;
907 }
908 }
909 snd_ice1712_restore_gpio_status(ice);
910
911 return change;
912}
913
914/* digital master volume */
915#define PCM_0dB 0xff
916#define PCM_RES 128 /* -64dB */
917#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100918static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
920 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
921 uinfo->count = 1;
922 uinfo->value.integer.min = 0; /* mute (-64dB) */
923 uinfo->value.integer.max = PCM_RES; /* 0dB */
924 return 0;
925}
926
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100927static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100929 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 unsigned short val;
931
Ingo Molnar62932df2006-01-16 16:34:20 +0100932 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
934 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
935 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100936 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 return 0;
938}
939
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100940static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100942 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 unsigned short ovol, nvol;
944 int change = 0;
945
946 snd_ice1712_save_gpio_status(ice);
947 nvol = ucontrol->value.integer.value[0];
948 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
949 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
950 if (ovol != nvol) {
951 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
952 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
953 change = 1;
954 }
955 snd_ice1712_restore_gpio_status(ice);
956 return change;
957}
958
959/*
960 * ADC mute control
961 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100962static int wm_adc_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
964 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
965 uinfo->count = 2;
966 uinfo->value.integer.min = 0;
967 uinfo->value.integer.max = 1;
968 return 0;
969}
970
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100971static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100973 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 unsigned short val;
975 int i;
976
Ingo Molnar62932df2006-01-16 16:34:20 +0100977 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 for (i = 0; i < 2; i++) {
979 val = wm_get(ice, WM_ADC_GAIN + i);
980 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
981 }
Ingo Molnar62932df2006-01-16 16:34:20 +0100982 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return 0;
984}
985
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100986static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100988 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 unsigned short new, old;
990 int i, change = 0;
991
992 snd_ice1712_save_gpio_status(ice);
993 for (i = 0; i < 2; i++) {
994 old = wm_get(ice, WM_ADC_GAIN + i);
995 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
996 if (new != old) {
997 wm_put(ice, WM_ADC_GAIN + i, new);
998 change = 1;
999 }
1000 }
1001 snd_ice1712_restore_gpio_status(ice);
1002
1003 return change;
1004}
1005
1006/*
1007 * ADC gain mixer control
1008 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001009static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010{
1011 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1012 uinfo->count = 2;
1013 uinfo->value.integer.min = 0; /* -12dB */
1014 uinfo->value.integer.max = 0x1f; /* 19dB */
1015 return 0;
1016}
1017
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001018static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001020 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 int i, idx;
1022 unsigned short vol;
1023
Ingo Molnar62932df2006-01-16 16:34:20 +01001024 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 for (i = 0; i < 2; i++) {
1026 idx = WM_ADC_GAIN + i;
1027 vol = wm_get(ice, idx) & 0x1f;
1028 ucontrol->value.integer.value[i] = vol;
1029 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001030 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return 0;
1032}
1033
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001034static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001036 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 int i, idx;
1038 unsigned short ovol, nvol;
1039 int change = 0;
1040
1041 snd_ice1712_save_gpio_status(ice);
1042 for (i = 0; i < 2; i++) {
1043 idx = WM_ADC_GAIN + i;
1044 nvol = ucontrol->value.integer.value[i];
1045 ovol = wm_get(ice, idx);
1046 if ((ovol & 0x1f) != nvol) {
1047 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1048 change = 1;
1049 }
1050 }
1051 snd_ice1712_restore_gpio_status(ice);
1052 return change;
1053}
1054
1055/*
1056 * ADC input mux mixer control
1057 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001058static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
1060 static char *texts[] = {
1061 "CD", //AIN1
1062 "Aux", //AIN2
1063 "Line", //AIN3
1064 "Mic", //AIN4
1065 "AC97" //AIN5
1066 };
1067 static char *universe_texts[] = {
1068 "Aux1", //AIN1
1069 "CD", //AIN2
1070 "Phono", //AIN3
1071 "Line", //AIN4
1072 "Aux2", //AIN5
1073 "Mic", //AIN6
1074 "Aux3", //AIN7
1075 "AC97" //AIN8
1076 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001077 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
1079 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1080 uinfo->count = 2;
1081 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1082 uinfo->value.enumerated.items = 8;
1083 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1084 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1085 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
1086 }
1087 else {
1088 uinfo->value.enumerated.items = 5;
1089 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1090 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1091 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1092 }
1093 return 0;
1094}
1095
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001096static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001098 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 unsigned short val;
1100
Ingo Molnar62932df2006-01-16 16:34:20 +01001101 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001103 ucontrol->value.enumerated.item[0] = val & 7;
1104 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001105 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 return 0;
1107}
1108
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001109static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001111 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 unsigned short oval, nval;
1113 int change;
1114
1115 snd_ice1712_save_gpio_status(ice);
1116 oval = wm_get(ice, WM_ADC_MUX);
1117 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001118 nval |= ucontrol->value.enumerated.item[0] & 7;
1119 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 change = (oval != nval);
1121 if (change)
1122 wm_put(ice, WM_ADC_MUX, nval);
1123 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001124 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125}
1126
1127/*
1128 * CS8415 Input mux
1129 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001130static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001132 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 static char *aureon_texts[] = {
1134 "CD", //RXP0
1135 "Optical" //RXP1
1136 };
1137 static char *prodigy_texts[] = {
1138 "CD",
1139 "Coax"
1140 };
1141 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1142 uinfo->count = 1;
1143 uinfo->value.enumerated.items = 2;
1144 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1145 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1146 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1147 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1148 else
1149 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1150 return 0;
1151}
1152
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001153static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001155 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 //snd_ice1712_save_gpio_status(ice);
1158 //val = aureon_cs8415_get(ice, CS8415_CTRL2);
Takashi Iwai66820252006-03-20 18:31:57 +01001159 ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 //snd_ice1712_restore_gpio_status(ice);
1161 return 0;
1162}
1163
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001164static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001166 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 unsigned short oval, nval;
1168 int change;
1169
1170 snd_ice1712_save_gpio_status(ice);
1171 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1172 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001173 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 change = (oval != nval);
1175 if (change)
1176 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1177 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai66820252006-03-20 18:31:57 +01001178 ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 return change;
1180}
1181
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001182static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183{
1184 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1185 uinfo->count = 1;
1186 uinfo->value.integer.min = 0;
1187 uinfo->value.integer.max = 192000;
1188 return 0;
1189}
1190
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001191static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001193 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 unsigned char ratio;
1195 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1196 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1197 return 0;
1198}
1199
1200/*
1201 * CS8415A Mute
1202 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001203static int aureon_cs8415_mute_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204{
1205 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1206 uinfo->count = 1;
1207 return 0;
1208}
1209
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001210static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001212 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 snd_ice1712_save_gpio_status(ice);
1214 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1215 snd_ice1712_restore_gpio_status(ice);
1216 return 0;
1217}
1218
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001219static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001221 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 unsigned char oval, nval;
1223 int change;
1224 snd_ice1712_save_gpio_status(ice);
1225 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1226 if (ucontrol->value.integer.value[0])
1227 nval = oval & ~0x20;
1228 else
1229 nval = oval | 0x20;
1230 if ((change = (oval != nval)))
1231 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1232 snd_ice1712_restore_gpio_status(ice);
1233 return change;
1234}
1235
1236/*
1237 * CS8415A Q-Sub info
1238 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001239static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1241 uinfo->count = 10;
1242 return 0;
1243}
1244
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001245static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1246 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248 snd_ice1712_save_gpio_status(ice);
1249 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1250 snd_ice1712_restore_gpio_status(ice);
1251
1252 return 0;
1253}
1254
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001255static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1257 uinfo->count = 1;
1258 return 0;
1259}
1260
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001261static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 memset(ucontrol->value.iec958.status, 0xFF, 24);
1263 return 0;
1264}
1265
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001266static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1267 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269 snd_ice1712_save_gpio_status(ice);
1270 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1271 snd_ice1712_restore_gpio_status(ice);
1272 return 0;
1273}
1274
1275/*
1276 * Headphone Amplifier
1277 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001278static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
1280 unsigned int tmp, tmp2;
1281
1282 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1283 if (enable)
Takashi Iwaic5130272006-05-23 15:46:10 +02001284 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
1285 tmp |= AUREON_HP_SEL;
1286 else
1287 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 else
Takashi Iwaic5130272006-05-23 15:46:10 +02001289 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
1290 tmp &= ~ AUREON_HP_SEL;
1291 else
1292 tmp &= ~ PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 if (tmp != tmp2) {
1294 snd_ice1712_gpio_write(ice, tmp);
1295 return 1;
1296 }
1297 return 0;
1298}
1299
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001300static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301{
1302 unsigned int tmp = snd_ice1712_gpio_read(ice);
1303
1304 return ( tmp & AUREON_HP_SEL )!= 0;
1305}
1306
1307#define aureon_hpamp_info aureon_mono_bool_info
1308
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001309static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001311 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1314 return 0;
1315}
1316
1317
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001318static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001320 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
1323}
1324
1325/*
1326 * Deemphasis
1327 */
1328
1329#define aureon_deemp_info aureon_mono_bool_info
1330
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001331static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001333 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1335 return 0;
1336}
1337
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001338static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001340 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 int temp, temp2;
1342 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1343 if (ucontrol->value.integer.value[0])
1344 temp |= 0xf;
1345 else
1346 temp &= ~0xf;
1347 if (temp != temp2) {
1348 wm_put(ice, WM_DAC_CTRL2, temp);
1349 return 1;
1350 }
1351 return 0;
1352}
1353
1354/*
1355 * ADC Oversampling
1356 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001357static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358{
1359 static char *texts[2] = { "128x", "64x" };
1360
1361 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1362 uinfo->count = 1;
1363 uinfo->value.enumerated.items = 2;
1364
1365 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1366 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1367 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1368
1369 return 0;
1370}
1371
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001372static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001374 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1376 return 0;
1377}
1378
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001379static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
1381 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001382 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 temp2 = temp = wm_get(ice, WM_MASTER);
1385
1386 if (ucontrol->value.enumerated.item[0])
1387 temp |= 0x8;
1388 else
1389 temp &= ~0x8;
1390
1391 if (temp != temp2) {
1392 wm_put(ice, WM_MASTER, temp);
1393 return 1;
1394 }
1395 return 0;
1396}
1397
1398/*
1399 * mixers
1400 */
1401
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001402static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 {
1404 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1405 .name = "Master Playback Switch",
1406 .info = wm_master_mute_info,
1407 .get = wm_master_mute_get,
1408 .put = wm_master_mute_put
1409 },
1410 {
1411 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1412 .name = "Master Playback Volume",
1413 .info = wm_master_vol_info,
1414 .get = wm_master_vol_get,
1415 .put = wm_master_vol_put
1416 },
1417 {
1418 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1419 .name = "Front Playback Switch",
1420 .info = wm_mute_info,
1421 .get = wm_mute_get,
1422 .put = wm_mute_put,
1423 .private_value = (2 << 8) | 0
1424 },
1425 {
1426 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1427 .name = "Front Playback Volume",
1428 .info = wm_vol_info,
1429 .get = wm_vol_get,
1430 .put = wm_vol_put,
1431 .private_value = (2 << 8) | 0
1432 },
1433 {
1434 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1435 .name = "Rear Playback Switch",
1436 .info = wm_mute_info,
1437 .get = wm_mute_get,
1438 .put = wm_mute_put,
1439 .private_value = (2 << 8) | 2
1440 },
1441 {
1442 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1443 .name = "Rear Playback Volume",
1444 .info = wm_vol_info,
1445 .get = wm_vol_get,
1446 .put = wm_vol_put,
1447 .private_value = (2 << 8) | 2
1448 },
1449 {
1450 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1451 .name = "Center Playback Switch",
1452 .info = wm_mute_info,
1453 .get = wm_mute_get,
1454 .put = wm_mute_put,
1455 .private_value = (1 << 8) | 4
1456 },
1457 {
1458 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1459 .name = "Center Playback Volume",
1460 .info = wm_vol_info,
1461 .get = wm_vol_get,
1462 .put = wm_vol_put,
1463 .private_value = (1 << 8) | 4
1464 },
1465 {
1466 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1467 .name = "LFE Playback Switch",
1468 .info = wm_mute_info,
1469 .get = wm_mute_get,
1470 .put = wm_mute_put,
1471 .private_value = (1 << 8) | 5
1472 },
1473 {
1474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1475 .name = "LFE Playback Volume",
1476 .info = wm_vol_info,
1477 .get = wm_vol_get,
1478 .put = wm_vol_put,
1479 .private_value = (1 << 8) | 5
1480 },
1481 {
1482 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1483 .name = "Side Playback Switch",
1484 .info = wm_mute_info,
1485 .get = wm_mute_get,
1486 .put = wm_mute_put,
1487 .private_value = (2 << 8) | 6
1488 },
1489 {
1490 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1491 .name = "Side Playback Volume",
1492 .info = wm_vol_info,
1493 .get = wm_vol_get,
1494 .put = wm_vol_put,
1495 .private_value = (2 << 8) | 6
1496 }
1497};
1498
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001499static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 {
1501 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1502 .name = "PCM Playback Switch",
1503 .info = wm_pcm_mute_info,
1504 .get = wm_pcm_mute_get,
1505 .put = wm_pcm_mute_put
1506 },
1507 {
1508 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1509 .name = "PCM Playback Volume",
1510 .info = wm_pcm_vol_info,
1511 .get = wm_pcm_vol_get,
1512 .put = wm_pcm_vol_put
1513 },
1514 {
1515 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1516 .name = "Capture Switch",
1517 .info = wm_adc_mute_info,
1518 .get = wm_adc_mute_get,
1519 .put = wm_adc_mute_put,
1520 },
1521 {
1522 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1523 .name = "Capture Volume",
1524 .info = wm_adc_vol_info,
1525 .get = wm_adc_vol_get,
1526 .put = wm_adc_vol_put
1527 },
1528 {
1529 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1530 .name = "Capture Source",
1531 .info = wm_adc_mux_info,
1532 .get = wm_adc_mux_get,
1533 .put = wm_adc_mux_put,
1534 .private_value = 5
1535 },
1536 {
1537 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1538 .name = "External Amplifier",
1539 .info = aureon_hpamp_info,
1540 .get = aureon_hpamp_get,
1541 .put = aureon_hpamp_put
1542 },
1543 {
1544 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1545 .name = "DAC Deemphasis Switch",
1546 .info = aureon_deemp_info,
1547 .get = aureon_deemp_get,
1548 .put = aureon_deemp_put
1549 },
1550 {
1551 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1552 .name = "ADC Oversampling",
1553 .info = aureon_oversampling_info,
1554 .get = aureon_oversampling_get,
1555 .put = aureon_oversampling_put
1556 }
1557};
1558
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001559static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 {
1561 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1562 .name = "AC97 Playback Switch",
1563 .info = aureon_ac97_mmute_info,
1564 .get = aureon_ac97_mmute_get,
1565 .put = aureon_ac97_mmute_put,
1566 .private_value = AC97_MASTER
1567 },
1568 {
1569 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1570 .name = "AC97 Playback Volume",
1571 .info = aureon_ac97_vol_info,
1572 .get = aureon_ac97_vol_get,
1573 .put = aureon_ac97_vol_put,
1574 .private_value = AC97_MASTER|AUREON_AC97_STEREO
1575 },
1576 {
1577 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1578 .name = "CD Playback Switch",
1579 .info = aureon_ac97_mute_info,
1580 .get = aureon_ac97_mute_get,
1581 .put = aureon_ac97_mute_put,
1582 .private_value = AC97_CD
1583 },
1584 {
1585 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1586 .name = "CD Playback Volume",
1587 .info = aureon_ac97_vol_info,
1588 .get = aureon_ac97_vol_get,
1589 .put = aureon_ac97_vol_put,
1590 .private_value = AC97_CD|AUREON_AC97_STEREO
1591 },
1592 {
1593 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1594 .name = "Aux Playback Switch",
1595 .info = aureon_ac97_mute_info,
1596 .get = aureon_ac97_mute_get,
1597 .put = aureon_ac97_mute_put,
1598 .private_value = AC97_AUX,
1599 },
1600 {
1601 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1602 .name = "Aux Playback Volume",
1603 .info = aureon_ac97_vol_info,
1604 .get = aureon_ac97_vol_get,
1605 .put = aureon_ac97_vol_put,
1606 .private_value = AC97_AUX|AUREON_AC97_STEREO
1607 },
1608 {
1609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1610 .name = "Line Playback Switch",
1611 .info = aureon_ac97_mute_info,
1612 .get = aureon_ac97_mute_get,
1613 .put = aureon_ac97_mute_put,
1614 .private_value = AC97_LINE
1615 },
1616 {
1617 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1618 .name = "Line Playback Volume",
1619 .info = aureon_ac97_vol_info,
1620 .get = aureon_ac97_vol_get,
1621 .put = aureon_ac97_vol_put,
1622 .private_value = AC97_LINE|AUREON_AC97_STEREO
1623 },
1624 {
1625 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1626 .name = "Mic Playback Switch",
1627 .info = aureon_ac97_mute_info,
1628 .get = aureon_ac97_mute_get,
1629 .put = aureon_ac97_mute_put,
1630 .private_value = AC97_MIC
1631 },
1632 {
1633 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1634 .name = "Mic Playback Volume",
1635 .info = aureon_ac97_vol_info,
1636 .get = aureon_ac97_vol_get,
1637 .put = aureon_ac97_vol_put,
1638 .private_value = AC97_MIC
1639 },
1640 {
1641 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1642 .name = "Mic Boost (+20dB)",
1643 .info = aureon_ac97_micboost_info,
1644 .get = aureon_ac97_micboost_get,
1645 .put = aureon_ac97_micboost_put
1646 }
1647};
1648
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001649static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 {
1651 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1652 .name = "AC97 Playback Switch",
1653 .info = aureon_ac97_mmute_info,
1654 .get = aureon_ac97_mmute_get,
1655 .put = aureon_ac97_mmute_put,
1656 .private_value = AC97_MASTER
1657 },
1658 {
1659 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1660 .name = "AC97 Playback Volume",
1661 .info = aureon_ac97_vol_info,
1662 .get = aureon_ac97_vol_get,
1663 .put = aureon_ac97_vol_put,
1664 .private_value = AC97_MASTER|AUREON_AC97_STEREO
1665 },
1666 {
1667 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1668 .name = "CD Playback Switch",
1669 .info = aureon_ac97_mute_info,
1670 .get = aureon_ac97_mute_get,
1671 .put = aureon_ac97_mute_put,
1672 .private_value = AC97_AUX
1673 },
1674 {
1675 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1676 .name = "CD Playback Volume",
1677 .info = aureon_ac97_vol_info,
1678 .get = aureon_ac97_vol_get,
1679 .put = aureon_ac97_vol_put,
1680 .private_value = AC97_AUX|AUREON_AC97_STEREO
1681 },
1682 {
1683 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1684 .name = "Phono Playback Switch",
1685 .info = aureon_ac97_mute_info,
1686 .get = aureon_ac97_mute_get,
1687 .put = aureon_ac97_mute_put,
1688 .private_value = AC97_CD,
1689 },
1690 {
1691 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1692 .name = "Phono Playback Volume",
1693 .info = aureon_ac97_vol_info,
1694 .get = aureon_ac97_vol_get,
1695 .put = aureon_ac97_vol_put,
1696 .private_value = AC97_CD|AUREON_AC97_STEREO
1697 },
1698 {
1699 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1700 .name = "Line Playback Switch",
1701 .info = aureon_ac97_mute_info,
1702 .get = aureon_ac97_mute_get,
1703 .put = aureon_ac97_mute_put,
1704 .private_value = AC97_LINE
1705 },
1706 {
1707 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1708 .name = "Line Playback Volume",
1709 .info = aureon_ac97_vol_info,
1710 .get = aureon_ac97_vol_get,
1711 .put = aureon_ac97_vol_put,
1712 .private_value = AC97_LINE|AUREON_AC97_STEREO
1713 },
1714 {
1715 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1716 .name = "Mic Playback Switch",
1717 .info = aureon_ac97_mute_info,
1718 .get = aureon_ac97_mute_get,
1719 .put = aureon_ac97_mute_put,
1720 .private_value = AC97_MIC
1721 },
1722 {
1723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1724 .name = "Mic Playback Volume",
1725 .info = aureon_ac97_vol_info,
1726 .get = aureon_ac97_vol_get,
1727 .put = aureon_ac97_vol_put,
1728 .private_value = AC97_MIC
1729 },
1730 {
1731 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1732 .name = "Mic Boost (+20dB)",
1733 .info = aureon_ac97_micboost_info,
1734 .get = aureon_ac97_micboost_get,
1735 .put = aureon_ac97_micboost_put
1736 },
1737 {
1738 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1739 .name = "Aux Playback Switch",
1740 .info = aureon_ac97_mute_info,
1741 .get = aureon_ac97_mute_get,
1742 .put = aureon_ac97_mute_put,
1743 .private_value = AC97_VIDEO,
1744 },
1745 {
1746 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1747 .name = "Aux Playback Volume",
1748 .info = aureon_ac97_vol_info,
1749 .get = aureon_ac97_vol_get,
1750 .put = aureon_ac97_vol_put,
1751 .private_value = AC97_VIDEO|AUREON_AC97_STEREO
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001752 },
1753 {
1754 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1755 .name = "Aux Source",
1756 .info = aureon_universe_inmux_info,
1757 .get = aureon_universe_inmux_get,
1758 .put = aureon_universe_inmux_put
1759 }
1760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761};
1762
1763
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001764static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 {
1766 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1767 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
1768 .info = aureon_cs8415_mute_info,
1769 .get = aureon_cs8415_mute_get,
1770 .put = aureon_cs8415_mute_put
1771 },
1772 {
1773 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1774 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
1775 .info = aureon_cs8415_mux_info,
1776 .get = aureon_cs8415_mux_get,
1777 .put = aureon_cs8415_mux_put,
1778 },
1779 {
1780 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1781 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
1782 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1783 .info = aureon_cs8415_qsub_info,
1784 .get = aureon_cs8415_qsub_get,
1785 },
1786 {
1787 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1788 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
1789 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1790 .info = aureon_cs8415_spdif_info,
1791 .get = aureon_cs8415_mask_get
1792 },
1793 {
1794 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1795 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
1796 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1797 .info = aureon_cs8415_spdif_info,
1798 .get = aureon_cs8415_spdif_get
1799 },
1800 {
1801 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1802 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
1803 .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1804 .info = aureon_cs8415_rate_info,
1805 .get = aureon_cs8415_rate_get
1806 }
1807};
1808
1809
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001810static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811{
1812 unsigned int i, counts;
1813 int err;
1814
1815 counts = ARRAY_SIZE(aureon_dac_controls);
1816 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1817 counts -= 2; /* no side */
1818 for (i = 0; i < counts; i++) {
1819 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1820 if (err < 0)
1821 return err;
1822 }
1823
1824 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1825 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1826 if (err < 0)
1827 return err;
1828 }
1829
1830 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1831 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1832 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1833 if (err < 0)
1834 return err;
1835 }
1836 }
Takashi Iwai45fe7222006-01-13 13:50:16 +01001837 else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1839 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1840 if (err < 0)
1841 return err;
1842 }
1843 }
1844
Takashi Iwai45fe7222006-01-13 13:50:16 +01001845 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 unsigned char id;
1847 snd_ice1712_save_gpio_status(ice);
1848 id = aureon_cs8415_get(ice, CS8415_ID);
1849 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001850 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001852 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 else {
1854 for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001855 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1857 if (err < 0)
1858 return err;
1859 if (i > 1)
1860 kctl->id.device = ice->pcm->device;
1861 }
1862 }
1863 snd_ice1712_restore_gpio_status(ice);
1864 }
1865
1866 return 0;
1867}
1868
1869
1870/*
1871 * initialize the chip
1872 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001873static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874{
1875 static unsigned short wm_inits_aureon[] = {
1876 /* These come first to reduce init pop noise */
1877 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1878 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1879 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1880
1881 0x18, 0x000, /* All power-up */
1882
1883 0x16, 0x122, /* I2S, normal polarity, 24bit */
1884 0x17, 0x022, /* 256fs, slave mode */
1885 0x00, 0, /* DAC1 analog mute */
1886 0x01, 0, /* DAC2 analog mute */
1887 0x02, 0, /* DAC3 analog mute */
1888 0x03, 0, /* DAC4 analog mute */
1889 0x04, 0, /* DAC5 analog mute */
1890 0x05, 0, /* DAC6 analog mute */
1891 0x06, 0, /* DAC7 analog mute */
1892 0x07, 0, /* DAC8 analog mute */
1893 0x08, 0x100, /* master analog mute */
1894 0x09, 0xff, /* DAC1 digital full */
1895 0x0a, 0xff, /* DAC2 digital full */
1896 0x0b, 0xff, /* DAC3 digital full */
1897 0x0c, 0xff, /* DAC4 digital full */
1898 0x0d, 0xff, /* DAC5 digital full */
1899 0x0e, 0xff, /* DAC6 digital full */
1900 0x0f, 0xff, /* DAC7 digital full */
1901 0x10, 0xff, /* DAC8 digital full */
1902 0x11, 0x1ff, /* master digital full */
1903 0x12, 0x000, /* phase normal */
1904 0x13, 0x090, /* unmute DAC L/R */
1905 0x14, 0x000, /* all unmute */
1906 0x15, 0x000, /* no deemphasis, no ZFLG */
1907 0x19, 0x000, /* -12dB ADC/L */
1908 0x1a, 0x000, /* -12dB ADC/R */
1909 (unsigned short)-1
1910 };
1911 static unsigned short wm_inits_prodigy[] = {
1912
1913 /* These come first to reduce init pop noise */
1914 0x1b, 0x000, /* ADC Mux */
1915 0x1c, 0x009, /* Out Mux1 */
1916 0x1d, 0x009, /* Out Mux2 */
1917
1918 0x18, 0x000, /* All power-up */
1919
1920 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
1921 0x17, 0x006, /* 128fs, slave mode */
1922
1923 0x00, 0, /* DAC1 analog mute */
1924 0x01, 0, /* DAC2 analog mute */
1925 0x02, 0, /* DAC3 analog mute */
1926 0x03, 0, /* DAC4 analog mute */
1927 0x04, 0, /* DAC5 analog mute */
1928 0x05, 0, /* DAC6 analog mute */
1929 0x06, 0, /* DAC7 analog mute */
1930 0x07, 0, /* DAC8 analog mute */
1931 0x08, 0x100, /* master analog mute */
1932
1933 0x09, 0x7f, /* DAC1 digital full */
1934 0x0a, 0x7f, /* DAC2 digital full */
1935 0x0b, 0x7f, /* DAC3 digital full */
1936 0x0c, 0x7f, /* DAC4 digital full */
1937 0x0d, 0x7f, /* DAC5 digital full */
1938 0x0e, 0x7f, /* DAC6 digital full */
1939 0x0f, 0x7f, /* DAC7 digital full */
1940 0x10, 0x7f, /* DAC8 digital full */
1941 0x11, 0x1FF, /* master digital full */
1942
1943 0x12, 0x000, /* phase normal */
1944 0x13, 0x090, /* unmute DAC L/R */
1945 0x14, 0x000, /* all unmute */
1946 0x15, 0x000, /* no deemphasis, no ZFLG */
1947
1948 0x19, 0x000, /* -12dB ADC/L */
1949 0x1a, 0x000, /* -12dB ADC/R */
1950 (unsigned short)-1
1951
1952 };
1953 static unsigned short cs_inits[] = {
1954 0x0441, /* RUN */
1955 0x0180, /* no mute, OMCK output on RMCK pin */
1956 0x0201, /* S/PDIF source on RXP1 */
1957 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
1958 (unsigned short)-1
1959 };
1960 unsigned int tmp;
1961 unsigned short *p;
1962 int err, i;
1963
1964 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
1965 ice->num_total_dacs = 6;
1966 ice->num_total_adcs = 2;
1967 } else {
1968 /* aureon 7.1 and prodigy 7.1 */
1969 ice->num_total_dacs = 8;
1970 ice->num_total_adcs = 2;
1971 }
1972
1973 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001974 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 if (! ice->akm)
1976 return -ENOMEM;
1977 ice->akm_codecs = 1;
1978
1979 if ((err = aureon_ac97_init(ice)) != 0)
1980 return err;
1981
1982 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
1983
1984 /* reset the wm codec as the SPI mode */
1985 snd_ice1712_save_gpio_status(ice);
1986 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
1987
1988 tmp = snd_ice1712_gpio_read(ice);
1989 tmp &= ~AUREON_WM_RESET;
1990 snd_ice1712_gpio_write(ice, tmp);
1991 udelay(1);
1992 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
1993 snd_ice1712_gpio_write(ice, tmp);
1994 udelay(1);
1995 tmp |= AUREON_WM_RESET;
1996 snd_ice1712_gpio_write(ice, tmp);
1997 udelay(1);
1998
1999 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002000 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
2001 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 p = wm_inits_prodigy;
2003 else
2004 p = wm_inits_aureon;
2005 for (; *p != (unsigned short)-1; p += 2)
2006 wm_put(ice, p[0], p[1]);
2007
2008 /* initialize CS8415A codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002009 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
2010 for (p = cs_inits; *p != (unsigned short)-1; p++)
2011 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
2012 ice->spec.aureon.cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
Takashi Iwai45fe7222006-01-13 13:50:16 +01002014 aureon_set_headphone_amp(ice, 1);
2015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
2017 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002018
2019 /* initialize PCA9554 pin directions & set default input*/
2020 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2021 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023 ice->spec.aureon.master[0] = WM_VOL_MUTE;
2024 ice->spec.aureon.master[1] = WM_VOL_MUTE;
2025 for (i = 0; i < ice->num_total_dacs; i++) {
2026 ice->spec.aureon.vol[i] = WM_VOL_MUTE;
2027 wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]);
2028 }
2029
2030 return 0;
2031}
2032
2033
2034/*
2035 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2036 * hence the driver needs to sets up it properly.
2037 */
2038
2039static unsigned char aureon51_eeprom[] __devinitdata = {
2040 0x0a, /* SYSCONF: clock 512, spdif-in/ADC, 3DACs */
2041 0x80, /* ACLINK: I2S */
2042 0xfc, /* I2S: vol, 96k, 24bit, 192k */
2043 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2044 0xff, /* GPIO_DIR */
2045 0xff, /* GPIO_DIR1 */
2046 0x5f, /* GPIO_DIR2 */
2047 0x00, /* GPIO_MASK */
2048 0x00, /* GPIO_MASK1 */
2049 0x00, /* GPIO_MASK2 */
2050 0x00, /* GPIO_STATE */
2051 0x00, /* GPIO_STATE1 */
2052 0x00, /* GPIO_STATE2 */
2053};
2054
2055static unsigned char aureon71_eeprom[] __devinitdata = {
2056 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
2057 0x80, /* ACLINK: I2S */
2058 0xfc, /* I2S: vol, 96k, 24bit, 192k */
2059 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2060 0xff, /* GPIO_DIR */
2061 0xff, /* GPIO_DIR1 */
2062 0x5f, /* GPIO_DIR2 */
2063 0x00, /* GPIO_MASK */
2064 0x00, /* GPIO_MASK1 */
2065 0x00, /* GPIO_MASK2 */
2066 0x00, /* GPIO_STATE */
2067 0x00, /* GPIO_STATE1 */
2068 0x00, /* GPIO_STATE2 */
2069};
2070
2071static unsigned char prodigy71_eeprom[] __devinitdata = {
2072 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
2073 0x80, /* ACLINK: I2S */
2074 0xfc, /* I2S: vol, 96k, 24bit, 192k */
2075 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2076 0xff, /* GPIO_DIR */
2077 0xff, /* GPIO_DIR1 */
2078 0x5f, /* GPIO_DIR2 */
2079 0x00, /* GPIO_MASK */
2080 0x00, /* GPIO_MASK1 */
2081 0x00, /* GPIO_MASK2 */
2082 0x00, /* GPIO_STATE */
2083 0x00, /* GPIO_STATE1 */
2084 0x00, /* GPIO_STATE2 */
2085};
2086
Takashi Iwai45fe7222006-01-13 13:50:16 +01002087static unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwaic5130272006-05-23 15:46:10 +02002088 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002089 0x80, /* ACLINK: I2S */
2090 0xfc, /* I2S: vol, 96k, 24bit, 192k */
Takashi Iwaic5130272006-05-23 15:46:10 +02002091 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2092 0xff, /* GPIO_DIR */
2093 0xff, /* GPIO_DIR1 */
2094 0x5f, /* GPIO_DIR2 */
2095 0x00, /* GPIO_MASK */
2096 0x00, /* GPIO_MASK1 */
2097 0x00, /* GPIO_MASK2 */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002098 0x00, /* GPIO_STATE */
2099 0x00, /* GPIO_STATE1 */
2100 0x00, /* GPIO_STATE2 */
2101};
2102
2103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104/* entry point */
2105struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
2106 {
2107 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2108 .name = "Terratec Aureon 5.1-Sky",
2109 .model = "aureon51",
2110 .chip_init = aureon_init,
2111 .build_controls = aureon_add_controls,
2112 .eeprom_size = sizeof(aureon51_eeprom),
2113 .eeprom_data = aureon51_eeprom,
2114 .driver = "Aureon51",
2115 },
2116 {
2117 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2118 .name = "Terratec Aureon 7.1-Space",
2119 .model = "aureon71",
2120 .chip_init = aureon_init,
2121 .build_controls = aureon_add_controls,
2122 .eeprom_size = sizeof(aureon71_eeprom),
2123 .eeprom_data = aureon71_eeprom,
2124 .driver = "Aureon71",
2125 },
2126 {
2127 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2128 .name = "Terratec Aureon 7.1-Universe",
2129 .model = "universe",
2130 .chip_init = aureon_init,
2131 .build_controls = aureon_add_controls,
2132 .eeprom_size = sizeof(aureon71_eeprom),
2133 .eeprom_data = aureon71_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002134 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 },
2136 {
2137 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2138 .name = "Audiotrak Prodigy 7.1",
2139 .model = "prodigy71",
2140 .chip_init = aureon_init,
2141 .build_controls = aureon_add_controls,
2142 .eeprom_size = sizeof(prodigy71_eeprom),
2143 .eeprom_data = prodigy71_eeprom,
2144 .driver = "Prodigy71", /* should be identical with Aureon71 */
2145 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002146 {
2147 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2148 .name = "Audiotrak Prodigy 7.1 LT",
2149 .model = "prodigy71lt",
2150 .chip_init = aureon_init,
2151 .build_controls = aureon_add_controls,
2152 .eeprom_size = sizeof(prodigy71lt_eeprom),
2153 .eeprom_data = prodigy71lt_eeprom,
2154 .driver = "Prodigy71LT",
2155 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 { } /* terminator */
2157};